Angular Generic Link Component

Updated: 31 January 2024

Often we want to be able to render a link element in Angular which is able to appropriately direct a user to an internal or external website link while taking advantage of the Angular router for internal linking. Below you can see an example of a component that will enable this behaviour

Component

1
import { CommonModule } from '@angular/common';
2
import { Component, Input } from '@angular/core';
3
import { RouterModule } from '@angular/router';
4
5
export interface LinkProps {
6
/**
7
* The link to the page to use.
8
* If this starts with "." or "/" will be converted to an internal link
9
* Otherwise will use an href.
10
*
11
* > In the case of an external link the fragment will be ignored
12
*/
13
href?: string | null;
14
15
/**
16
* Section of page to link to in the case of an internal link
17
*/
18
fragment?: string | null;
19
20
/**
21
* Class to be applied to the inner lanchor component.
22
*
23
* To style the Angular host component use the `class` attribute
24
*/
25
anchorClass?: string | null;
26
27
/**
28
* Conditional classes to be applied to the inner anchor component
29
*
30
* To style the Angular host component use the `ngClass` attribute
31
*/
32
ngAnchorClass?: Record<string, boolean>;
33
}
34
35
@Component({
36
selector: 'ui-link',
37
standalone: true,
38
imports: [RouterModule, CommonModule],
39
template: `
40
@if (isInternalLink()) {
41
<a
42
[class]="anchorClass || ''"
43
[ngClass]="ngAnchorClass"
44
[routerLink]="href"
45
>
46
<ng-container *ngTemplateOutlet="content"></ng-container>
47
</a>
48
} @else {
49
<a [class]="anchorClass || ''" [ngClass]="ngAnchorClass" [href]="href">
50
<ng-container *ngTemplateOutlet="content"></ng-container>
51
</a>
52
}
53
54
<ng-template #content><ng-content></ng-content></ng-template>
55
`,
56
})
57
58
59
export class LinkComponent implements LinkProps {
60
@Input()
61
href?: string | null;
62
63
@Input()
64
ngAnchorClass?: Record<string, boolean>;
65
66
@Input()
67
anchorClass?: string | null;
68
69
@Input()
70
fragment?: string | null;
71
72
isInternalLink() {
73
return this.href?.startsWith('/') || this.href?.startsWith('.');
74
}
75
}

VSCode/Tailwind Setup

If you’re using VSCode with the TailwindCSS extension, you may also be concerned that your new class properties won’t be detected, so here’s the settings you need for that:

.vscode/settings.json

1
{
2
"tailwindCSS.classAttributes": [
3
"class",
4
"className",
5
"ngClass",
6
"anchorClass",
7
"ngAnchorClass"
8
]
9
}

References

The basic idea and structure is from this StackOverflow answer which helped to solve the issues with the other ways of attempting this that helps ensure that the component is rendered under all conditions as well as that the href attribute is not removed