So, you look at the Figma prototype for a new page and see a button (or a link) and think "Yeah, this is pretty straightforward. I'm going to use a <button> for it". This might be a wrong choice.
TL;DR
- Choose the HTML-element by semantics, not the looks
- Then apply the looks with CSS
We've been having the current web design utilising buttons for navigating to other web pages, as well as elements looking like hyperlinks. However, newer developers tend to take these designs quite literally and use <button> for buttons that opens up a page, and <a> for a link looking element to do some kind of interaction on the current page.
What they end up with looks like this.
<!-- example.html -->
<button (click)="navigateToRequests()" class="button">See requests</button>
// example.tsGoogle
@Component({ /*...*/ })
export class ExamplePage {
private readonly router = inject(Router);
navigateToRequests(): void {
this.router.navigate(['/requests'])
// an alternative that does not involve Angular tooling
// would be something like this
window.open('/requests')
}
}
Just the code looks absurd enough, although it works. You can focus on it with a keyboard, click with a mouse, tap with your finger on a touchscreen, etc. But if you right-click on it, you can't copy its destination URL, you can't open it in a separate window or a tab. If you press it in the Arc browser, it might as well open it in a popup (Glance, as they call it).
I'm just gonna leave a live example below to prove my point.
Now consider this example.
<!-- example.html -->
<a (click)="displayHelpPopup()" class="link">Help!</a>
// example.ts
@Component({
// ...
imports: [DialogModule],
})
export class ExamplePage {
private readonly dialog = inject(Dialog);
navigateToRequests(): void {
const ref = this.dialog.open(RequestDialog)
ref.closed.subscribe(() => {
console.log('The dialog was closed');
});
}
}
<button onclick="openGoogle()" class="button">Open Google</button>
Since it doesn't even have a href attribute set up, you cannot focus and interact with it with a keyboard. Try it yourself, I left you another live example.
Then what element should I use?
Let's first take a look at how these HTML elements are supposed to be used. Let's take a quick look at MDN, literally just first paragraphs.
The
<button>HTML element is an interactive element activated by a user with a mouse, keyboard, finger, voice command, or other assistive technology. Once activated, it then performs an action, such as submitting a form or opening a dialog.
The
<a>HTML element (or anchor element), with itshrefattribute, creates a hyperlink to web pages, files, email addresses, locations in the same page, or anything else a URL can address.
The difference is pretty clear. There is the look, and then there is the function. In HTML, this is not about how does it look like in a Figma design. This is about semantics, and they do matter. The look can be adjusted with CSS.
So when buttons are links and links are buttons?
If the element performs an action - use <button>. If it looks like a link - use your CSS.
<!-- example.html -->
<button (click)="displayHelpPopup()" class="link">Help!</button>
Though visually it looks like a link, you don't need to put any ARIA-attributes to tell the browser or an accessibility tool that this is a link. That would be a lie. It's not what it seems - it is a button. It only looks like a link.
If the element redirects to a URL, use <a>. If it looks like a button - again, use CSS.
<!-- example.html -->
<a [routerLink]="['requests']" class="button">See requests</a>
<!-- or, without Angular -->
<a href="/requests" class="button">See requests</a>
See how easy it is?
Designing UI components with both elements in mind
If an element can be used both for interactivity and navigation, it must take into account, that <button> and <a> have their own default styles that should be reset.
.link,
.button {
appearance: none; /* It could even be an `input[type=button]` for all you know! */
margin: 0;
padding: 0;
border: none;
text-decoration: none;
color: inherit;
background: none;
}
/* Then you put your own stylesheets below */
.button { /* ... */ }
.link { /* ... */ }
So, please, don't confuse the actual functionality and semantics with looks. You always should pick the right tool for the job.