Is it possible to make a re-usable icon component that doesn't create duplicate TemplateRefs I have attempted to create an IconComponent that shows a different SVG icon depending on the string that is passed in.
Example:
&lt;app-icon icon=&quot;tick&quot;&gt;&lt;/app-icon&gt;

Would show an SVG of a tick.
Small StackBlitz example
I believe this approach, however, creates a new and unique TemplateRef for each instance of IconComponent, which would create useless duplicates of data in memory.
This problem concerns me when there may be thousands of icons on a page, such as on a table/grid.
Is there a better approach?
import {
  ChangeDetectorRef,
  Component,
  Input,
  OnChanges,
  SimpleChanges,
  TemplateRef,
  ViewChild
} from &quot;@angular/core&quot;;

@Component({
  selector: &quot;app-icon&quot;,
  templateUrl: &quot;./icon.component.html&quot;,
  styleUrls: [&quot;./icon.component.css&quot;]
})
export class IconComponent implements OnChanges {
  @Input(&quot;icon&quot;)
  public icon?: string;

  @ViewChild(&quot;chevronTemplate&quot;, { static: true })
  public chevronTemplate?: TemplateRef&lt;undefined&gt;;

  @ViewChild(&quot;tickTemplate&quot;, { static: true })
  public tickTemplate?: TemplateRef&lt;undefined&gt;;

  public iconTemplate?: TemplateRef&lt;undefined&gt;;

  public constructor(private readonly changeDetectorRef: ChangeDetectorRef) {}

  public ngOnChanges(changes: SimpleChanges): void {
    let hasChanges = false;

    if (changes.icon !== undefined) {
      this.iconTemplate = this.getIconTemplate();

      hasChanges = true;
    }

    if (hasChanges) {
      this.changeDetectorRef.detectChanges();
    }
  }

  private getIconTemplate(): TemplateRef&lt;undefined&gt; {
    switch (this.icon) {
      case &quot;chevron&quot;:
        return this.chevronTemplate;

      case &quot;tick&quot;:
        return this.tickTemplate;

      default:
        throw new Error(`Unknown Icon Type '${this.icon}'.`);
    }
  }
}
Indeed, although working, this approach looks a bit heavy, because for each new SVG template the icon.component.html file will need to be changed and a respective TemplateRef field has to be created in the component.
It is not clear from the example, but if in your task all the pieces of SVG are static (not generated through the app logic), it can be solved differently. Here are some hints:

for each SVG template, create a file under the application resources: chevron.svg, tick.svg etc, with the respective contents.

in icon.component.ts, add a getter returning the path to the SVG file, for example:


public get svgResourcePath(): string {
  return `/path/to/resource/${this.icon}.svg`;
}


change the icon.component.html, so that it uses a standard HTML image tag, with the value of the src attribute bound to the path:

&lt;img [src]=&quot;svgResourcePath&quot;/&gt;

Update

One point I didn't put in my question is that I also need to bind a color to the SVG through an @Input().

As I've mentioned, it was not clear from the initial question. But still there is a solution for that, although it looks a bit longer than my previous suggestion.
I've played a bit and implemented it here.
The ideas behind the approach:

Since SVG code can be included directly in a component template, we can create separate component definitions for all necessary cases, e.g. for tick:

@Component({
  selector: &quot;tick-icon&quot;, // does not matter, because we do not intend to insert it through a template
  template: `
    &lt;svg&gt;
      &lt;path
        [attr.fill]=&quot;fillColor&quot;
        d=&quot;M23.9 3.7L9.7 17.9l-6.8-6.8-2.8 2.6 9.7 9.6L26.7 6.5z&quot;
      /&gt;
    &lt;/svg&gt;
  `
})
export class TickComponent implements StyleConfigurable {
  private _fillColor: string;

  @Input()
  public set fillColor(fc: string) {
    this._fillColor = fc;
  }

  public get fillColor(): string {
    return this._fillColor;
  }
}

The StyleConfigurable interface here is an interface that defines the SVG styling properties that we want to customize:
export interface StyleConfigurable {
  fillColor: string;
}


Angular components can be instantiated dynamically, so we adjust the algo from the doc for our use case:

export class IconComponent implements OnInit {
  private _icon: string;

  private _fillColor: string;

  // inject the necessary objects for the dynamic instantiation:
  public constructor(
    private _resolver: ComponentFactoryResolver,
    private _containerRef: ViewContainerRef
  ) {}

  public ngOnInit(): void {
    // trigger the SVG icons loading when this component is initialized:
    this.loadIcon();
  }

  // dynamically load the icon:
  private loadIcon(): void {
    const cmpFactory = this._resolver.resolveComponentFactory(this.getTypeForIcon());
    const cmpRef = this._containerRef.createComponent&lt;StyleConfigurable&gt;(
      cmpFactory
    );
    // note this call: instance.fillColor is available through StyleConfigurable
    cmpRef.instance.fillColor = this._fillColor;
  }

  // for each supported value of the 'icon' property, return the corresponding component type:
  private getTypeForIcon(): Type&lt;StyleConfigurable&gt; {
    switch (this._icon) {
      case &quot;tick&quot;:
        return TickComponent;
      case &quot;chevron&quot;:
        return ChevronComponent;
      default:
        throw Error(`Unrecognized icon: ${this._icon}`);
    }
  }
}

Now the IconComponent can be used as follows:
&lt;app-icon icon=&quot;chevron&quot; fillColor=&quot;rgb(0, 255, 0)&quot;&gt;&lt;/app-icon&gt;
&lt;app-icon icon=&quot;tick&quot; fillColor=&quot;rgb(255, 0, 0)&quot;&gt;&lt;/app-icon&gt;