DEV Community

Cory LaViska
Cory LaViska

Posted on • Updated on • Originally published at


On Buttons and Links

I posted a tweet yesterday that was met with some controversy, so I thought it would be a good idea to unravel it.

At face value, I understand why people are upset with this. It's hard to provide context in 280 characters, though, so I made it a thread. That was a mistake, because people don't always read the thread so the intent gets lost and assumptions get made. Twitter is a wonderful place.

Semantically Different

Let's start by stating the obvious. A button and a link are semantically different HTML elements, so no need to bust out the keyboard to tell me that. The idea of merging the two into a single component comes from real world experience working on multiple design system teams for large companies.

The fact is that designers always, always ask for links that look like buttons and buttons that look like links. I know, designers shouldn't do this. But this isn't a fantasy, it's our reality, and when it costs your organization measurable value in terms of conversions, sales, etc., you're not going to win that argument.

Emotions aside, this often leads to developers producing two separate button and link components with the same styles and logic, and consumers end up misusing them just like <button> and <a>.

To alleviate this, I propose that a custom element such as <my-button> should render the same "button" visually, but based on the presense of an optional href attribute, it will use a <button> or an <a> under the hood.

<!-- 👉 <button class="button button--primary">Save</button> -->

<my-button href="/new">New</my-button>
<!-- 👉 <a class="button button--primary" href="/new">New</a> -->
Enter fullscreen mode Exit fullscreen mode

This makes it more foolproof — if it goes somewhere, it becomes a link. If not, it's remains a button. So far, we're more or less aligned with the Twittersphere…except for one detail:

They should look different because they should do different things.

Visually Different?

As much as I want to agree with this statement, it falls apart in practice. Links will inevitably need to look like buttons from time to time. No, buttons and links are not semantically the same, but there are times when they need to be visually the same.

In web apps, the function of buttons and links is often blended. Some actions, such as "new," might simply open a new page. Others aren't as obvious. "Save" might fire off an XHR and redirect you to another page if the response is successful — or go nowhere and show an error if the response fails.

Suddenly, the line between "button" and "link" is more blurry. Should it still be a link if it takes me somewhere only after an XHR is successful? What if the request errors out and doesn't redirect? What if you click a link and the app prevents navigation because you have unsaved changes? There are so many scenarios and "what ifs" that, in practice, it's hard to settle on a 100% agreeable definition.

And then comes the design team with a Figma for the app's toolbar.

Button group with four actions: new, edit, settings, download

We'll assume that "New" takes you to /new and "Edit" takes you to /edit/:id. Those should definitely be links! But wait — "Settings" doesn't go anywhere. It just opens up a dialog, so it needs to be a button. And instead of creating an endpoint on the server that downloads the file, we'll use the download attribute so that also needs to be a link.

Let's adjust the design to account for the idea that buttons and links must be visually different.

A button group with a new link, edit link, settings button, and a download link

Do you think the design team is going to be thrilled with these changes to the toolbar? Do you think your customers will prefer this toolbar over the previous one?

What Users Expect

If the user is presented with a set of actions, they don't care if you use buttons or links under the hood. They care that it's consistent and that each control does what it's supposed to do. Remember that in all cases, each control's action is clearly inferred from its label.

Whether clicking "Delete" takes the user to a new page to confirm or opens a dialog to confirm is irrelevant. To the user, they're all just "buttons" that do something.*

It is true that links and buttons have different behaviors and the decision to make them look visually similar should be carefully considered. For example, CMD or CTRL + click typically opens a link in a new window. When buttons and links are identical, it can put users at a disadvantage.

I would recommend not making buttons and links look the same if you can reasonably expect the user will desire such behaviors. Some environments are more predictable than others. But accessibility isn't binary, so thought and consideration is still required from both design and development regardless of your approach.

Enforcement via API

The suggestion I'm making enforces the semantic definition of "button" and "link" by leaning on API design to ensure DRY principles and remove the burden of thought from consumers. This solves the problem of when to use a link or button under the hood.

It does not answer the question of "should buttons and links be visually similar?" That's a topic I'd love to have a conversation about because there are plenty of use cases that suggest at least sometimes they should.

Just know that, if you're working on a design system, it's extremely likely you will come across this requirement!

*This doesn't mean you should throw the baby out with the bathwater. It just means there might be situations where you need to use a link as a button, and the user doesn't care as long as it works. The download example comes to mind.

Top comments (2)

renatodeleao profile image
Renato de Leão • Edited

It's just sad that your tweet was so controversial and apparently no one read this excelent post, but eh we're talking about social media 🤷‍♂️... it is not designed for people to have actual productive discussions.

Speaking of design, I'm a retired designer so I can confirm that this quote is pretty accurate:

The fact is that designers always, always ask for links that look like buttons and buttons that look like link

One subtle but important difference though that you also highlight some paragraphs bellow: sometimes the designer does it, not because he wants to be a pain in the ass, but because the context where an "user action" is required asks for that particular styling, for the benefit of customers, not developers/designers.

Your post examples are excelent and highlight the myriad of complex edge cases that can happen, but I can think of one that would be a particular good fit for your twitter audience:

twitter button-link

  • a link that looks like a button
  • but that act as a link (a navigation occurs even though unnoticiable to most users — the url is replaced)
  • But we can argue that at the same time acts as a button, since "navigation" is "silent", it does feel like a button to trigger that tweet popup.

So should the designers made that CTA look like an anchor just for the sake of semantics? IMO, no. They made it stand out for quicker/easier reach for the users, it's the devs job to care about semantics.

Another super simple example from top of my mind: in 99% of the landing pages that we visit, you'll see a shinny CTA that looks like a button, but that in fact is a link that redirects you to signup/login page. Again, is that wrong? No. "Form should follow function".

stripe button-link

Woah this got a bit longer that I expected, anyways been in your shoes for way too many times. I've done both, but currently I'm also leaning towards having a single smart <app-button>, although most of the times a convinience <app-link> emerges, that is simply a wrapper around with the pre-set styling props that makes it "look like a link" by default.

Great post! Cheers, keep being controversial!

claviska profile image
Cory LaViska

Thank you for sharing — these are great examples! As you’ve shown, it’s not always black and white. For those times, a single component is, IMO, more convenient and foolproof than two separate ones with matching styles.

50 CLI Tools You Can't Live Without

>> Check out this classic DEV post <<