Kilian Valkhof

Building tools that make developers awesome.

When going somewhere does a thing: on links and buttons

Accessibility, CSS & HTML, 4 October 2022, 4 minute read

At the Fronteers conference, Manuel during his presentation did an exercise on building HTML that seemed fairly straightforward. On the site of Max Böck there's a thing you can click to open up a theme selector. What's that thing?

Of course, it's a button! Because it opens the theme selector at the top of the page. It does something! Add an aria-expanded to the button, make sure focus is set and you're good to go. It's obviously a button.

But what if it's not?

After Manuels excellent talk I was discussing this with a group of folks and I was adamant that it obviously was a button because it clearly opened a thing but… I didn't have a great argument for why it also couldn't also be a link. After all, all the arguments for a link are pretty sound. It stuck with me and in this article I want to explore both.

The "common" logic for when to use links or buttons is as follows:

  1. If it goes somewhere, it's a link.
  2. If it does something, it's a button.

But if you ask me, those two things aren’t always mutually exclusive. I'll give implementation examples of both that I think are fine.

What we're building

The functionality we're building is the following: The top right button on mxb.dev opens a theme selector at the top of the page, and the theme selector has a close button that closes it again. That's it. Here's a video:

Using a button

This is the example Manuel gave and it's essentially the same as what I wrote in The perfect responsive menu.

The button looks like this:

<button aria-expanded="false" aria-controls="theme-selector">
    Open Theme Selector
</button>

and the theme selector looks like this:

<div id="theme-selector" hidden="true">
  … pretend there's a theme controller here
  <button aria-expanded="false" aria-controls="theme-selector">
    Close
  </button>
</div>

Then when clicking the button, using javascript, the hidden attribute of theme-selector is removed, the aria-expanded of the button is set to true, the JS moves the focus to the theme selector and then adds some CSS makes the theme selector appear (in the live implementation it's using an additional class, but you could also use the [hidden] attribute being there or not instead).

In the theme selector, we have a close button that does the same in reverse.

Here's how it works in a codepen:

See the Pen
Button opening theme selector
by Kilian Valkhof (@Kilian)
on CodePen.

Okay, here we go. Why this can be a link: Links go somewhere, including different parts of the same page. So we can add a link that goes to #theme-selector:

<a href="#theme-selector" id="theme-selector-controller">
    Open Theme Selector
</a>

Using the :target pseudo-class, we can make the theme controller appear after clicking the link:

#theme-selector:target {
  display: block;
}

This will make the theme selector stay open while we interact with it. Inside #theme-selector we add a second link that links back to our original button:

<a href="#theme-selector-controller">
    Close Theme Selector
</a>

After clicking that, the #theme-selector no longer matches the target, so it's hidden again. You can see it in action here:

See the Pen
Button opening theme selector
by Kilian Valkhof (@Kilian)
on CodePen.

The browser gives us all the building block for a link solution. It works without javascript and as far as I can tell, the accessibility is decent too: using display means the theme selector is hidden from assistive technologies and the browser itself makes sure the focus is managed.

The only things you lose is that the "button" is no longer aware of the expanded status and can’t be used as a toggle anymore. The toggle functionality I don’t have a solution for, but you could also say that now that the browser is maintaining a target that's what holds that status.

In short, it's simple, doesn't need javascript, manages focus and the link clearly goes somewhere. It follows all the rules.

So why do I still prefer the (much more complex!) button example?

Addendum #

Here’s what Ben had to say about this: the above is accurate, but it’s not something he would recommend in practice for a few reasons:

He also brought up the point of links opening in a new tab when you middle-click. Does it make sense to have that functionality on a new tab?

All in all, he helped me understand why I still preferred the button and explained it as such: links are a semantically okayish way to do this; buttons are a more semantic way to do it. Thanks Ben!

Thanks to Manuel and Ben for feedback on drafts of this article.

Polypane browser for responsive web development and design Hi, I'm Kilian. I make Polypane, the browser for responsive web development and design. If you're reading this site, that's probably interesting to you. Try it out!