Skip to main content

Tagged “button”

Building a Good Download… Button? by Eric Bailey

Question: when presenting users with a means of downloading a file, should you use the anchor element or the button element?

Answer: you should use the anchor element.

Eric starts by quoting accessibility expert Scott O’Hara to explain why anchor is the appropriate element:

The debate about whether a button or link should be used to download a file is a bit silly, as the whole purpose of a link has always been to download content. HTML is a file, and like all other files, it needs to be retrieved from a server and downloaded before it can be presented to a user.

The confusion seems to come from developers getting super literal with the “links go places, buttons perform actions.” Yes, that is true, but links don’t actually go anywhere. They retrieve information and download it.

Long story short, the download attribute is unique to anchor links for a reason. download augments the inherent functionality of the link retrieving data. It side steps the attempt to render the file in the browser and instead says, “You know what? I’m just going to save this for later…”

Eric follows up by suggesting that as designers and developers we should make the experience of interacting with a download link as good as possible. To that end:

  • Ensure it looks like a link, i.e. underlined. You’re using a link (because it’s semantically appropriate) so now encourage the appropriate perceived affordances via conventional visual design for a link
  • Use verb plus noun for the text. For example, Download fonts
  • Include the file size (for example 34 MB) to give an indication of the download time
  • Consider adding an indicator that the link does something other than take you to another place on your website. A downward-facing arrow is conventional

To delete something, use a form rather than a link

In web-based products from e-commerce stores to email clients to accounting software you often find index pages where each item in a list (or row in a table) has a Delete option. This is often coded as a link… but it shouldn’t be.

I liked this comment by Rails developer Dan where he advises a fellow Rails developer that to create his Delete control he should use a form rather than a link, via Rails’s button_to method.

Dan mentions that in the past Rails UJS set an unsdesirable historical precedent by including a pattern of hijacking links for non-GET reqests.

But per the HTML standard, links are for navigation:

Hyperlinks… are links to other resources that… cause the user agent to navigate to those resources, e.g. to visit them in a browser or download them.

And as Dan goes on to say that’s why links make a GET request.

A GET request is a visit, it says “show me this” and it’s idempotent. When you make the same request it’ll show the same thing.

If on the other hand you want a control that performs an action (in this case request an entity to be deleted) then the appropriate HTML element is usually a button, and in this case a submit button within a form.

Relatedly, Jeremy Keith previously wrote about how to use request methods properly in his excellent post Get safe.

Should I use a button or a link?

I’ve written previously about the important differences between buttons and links. While reviewing some “component refresh” design mocks at work yesterday I noticed the designs were a bit unclear in this regard so I sent the designers a little decision-tree, which I’m noting here for future reference.

It’s important both for our users and for us as practitioners to distinguish between links (the <a> element) and the <button> element. The reason I push this is because they’re fundamentally different functionally, which has important usability implications. Users expect to use mouse, keyboard, browser back-button and assistive tech differently for links than they do for <button>s. And if they can’t visually distinguish one from the other, they’ll try things they expect to work then get confused when they don’t work.

I think this is an area where design and materials can’t be considered separately and need a joined-up approach.

Here’s a flow I hope is helpful.

Ask: does it…

  1. take the user to another page? Then it’ll be a link – the <a> (anchor) element.
  2. cause something to change on the current page, or submit a form? Then it’ll be a button – i.e. the <button> element.

If it’s a link (<a>):

  • it should be underlined so people know it’s a link
  • it should have a hover state, for example stay underlined but change colour
  • in cases where it’s a CTA you might choose to design it to look button-like and remove some standard link affordances. Just be aware you’re only “calling” it a button. In real user-experienced terms, it’s still a link.
  • it does not natively have a disabled state. We shouldn’t be disabling links.

If it’s a button (<button>):

  • it should look like a button, i.e. like a pill or rectangle
  • It should not look like a link – that’d confuse users into thinking it takes them to another page.
  • So it shouldn’t be underlined by default or on hover. It should have some other hover state.

Testing the decision tree

Let’s take the example of a control for launching a modal dialogue.

The obvious choice is a button, because the control causes something to change on the current page. In this case it causes a dialogue to appear on the current page.

Some might argue that it could be a link. This is usually influenced by the fact that dialogues are often (perhaps inadvisably) used as a kind of “fake page”. And to get someone to a “page” we use a link, right? Advocates of the link option might also have progressive enhancement in mind. If they present a link either to a named fragment further down the page or to a separate page, that offers a resilient baseline experience regardless of whether or not JavaScript is available. The idea is that they also have JavaScript to enhance the link when the user’s environment supports it, perhaps adding role=button.

However a button is the more accessible and user-friendly approach for launching the modal.

Improved focus indicators for keyboard navigation (on GitHub’s blog)

GitHub have recently done some good work on improving keyboard navigation for (and general usability of) their focusable elements such as links, buttons and form controls by improving focus indication. And then they wrote a short-but-sweet article about it, then tweeted to share that and their work is getting lots of positive recognition from all the right people. Nice job all round, GitHub!

Incidentally, that article they wrote really is very short. Maybe they’ll add to it later. The animated gif they include is very descriptive, mind you. And I noticed that they added the following alt text to it:

Animated gif of a customer using their keyboard to navigate a pull request, interactive UI elements receive a blue focus outline to show current location on the page. Key presses are shown in the bottom center of the image.

That feels like a good non-visual alternative description to me.

Buttons and links: definitions, differences and tips

On the web buttons and links are fundamentally different materials. However some design and development practices have led to them becoming conceptually “bundled together” and misunderstood. Practitioners can fall into the trap of seeing the surface-level commonality that “you click the thing, then something happens” and mistakenly thinking the two elements are interchangeable. Some might even consider them as a single “button component” without considering the distinctions underneath. However this mentality causes our users problems and is harmful for effective web development. In this post I’ll address why buttons and links are different and exist separately, and when to use each.

Problematic patterns

Modern website designs commonly apply the appearance of a button to a link. For isolated calls to action this can make sense however as a design pattern it is often overused and under-cooked, which can cause confusion to developers implementing the designs.

Relatedly, it’s now common for Design Systems to have a Button component which includes button-styled links that are referred to simply as buttons. Unless documented carefully this can lead to internal language and comprehension issues.

Meanwhile developers have historically used faux links (<a href="#">) or worse, a DIY clickable div, as a trigger for JavaScript-powered functionality where they should instead use native buttons.

These patterns in combination have given rise to a collective muddle over buttons and links. We need to get back to basics and talk about foundational HTML.

Buttons and anchors in HTML

There are two HTML elements of interest here.

Hyperlinks are created using the HTML anchor element (<a>). Buttons (by which I mean real buttons rather than links styled to appear as buttons) are implemented with the HTML button element (<button>).

Although a slight oversimplification, I think David MacDonald’s heuristic works well:

If it GOES someWHERE use a link

If it DOES someTHING use a button

A link…

  • goes somewhere (i.e. navigates to another place)
  • normally links to another document (i.e. page) on the current website or on another website
  • can alternatively link to a different section of the same page
  • historically and by default appears underlined
  • when hovered or focused offers visual feedback from the browser’s status bar
  • uses the “pointing hand” mouse pointer
  • results in browser making an HTTP GET request by default. It’s intended to get a page or resource rather than to change something
  • offers specific right-click options to mouse users (open in new tab, copy URL, etc)
  • typically results in an address which can be bookmarked
  • can be activated by pressing the return key
  • is announced by screen readers as “Link”
  • is available to screen reader users within an overall Links list

A button…

  • does something (i.e. performs an action, such as “Add”, “Update” or "Show")
  • can be used as <button type=submit> within a form to submit the form. This is a modern replacement for <input type=submit /> and much better as it’s easier to style, allows nested HTML and supports CSS pseudo-elements
  • can be used as <button type=button> to trigger JavaScript. This type of button is different to the one used for submitting a <form>. It can be used for any type of functionality that happens in-place rather than taking the user somewhere, such as expanding and collapsing content, or performing a calculation.
  • historically and by default appears in a pill or rounded rectangle
  • uses the normal mouse pointer arrow
  • can be activated by pressing return or space.
  • implictly gets the ARIA button role.
  • can be extended with further ARIA button-related states like aria-pressed
  • is announced by screen readers as “Button”
  • unlike a link is not available to screen reader users within a dedicated list

Our responsibilities

It’s our job as designers and developers to use the appropriate purpose-built element for each situation, to present it in a way that respects conventions so that users know what it is, and to then meet their expectations of it.

Tips

  • Visually distinguish button-styled call-to-action links from regular buttons, perhaps with a more pill-like appearance and a right-pointing arrow
  • Avoid a proliferation of call-to-action links by linking content itself (for example a news teaser’s headline). Not only does this reduce “link or button?” confusion but it also saves space, and provides more accessible link text.
  • Consider having separate Design System components for Button and ButtonLink to reinforce important differences.
  • For triggering JavaScript-powered interactions I’ll typically use a button. However in disclosure patterns where the trigger and target element are far apart in the DOM it can make sense to use a link as the trigger.
  • For buttons which are reliant on JavaScript, it’s best to use them within a strategy of progressive enhancement and not render them on the server but rather with client-side JavaScript. That way, if the client-side JavaScript is unsupported or fails, the user won’t be presented with a broken button.

Update: 23 November 2024

Perhaps a better heuristic than David MacDonald’s mentioned above, is:

Links are for a simple connection to a resource; buttons are for actions.

What I prefer about including a resource is that the “goes somewhere” definition of a link breaks down for anchors that instruct the linked resource to download (via the download attribute) rather than render in the browser, but this doesn’t. I also like the inclusion of simple because some buttons (like the submit button of a search form) might finish by taking you to a resource (the search results page) but that’s a complex action not a simple connection; you’re searching a database using your choice of search query.

References

Adapting Stimulus usage for better Progressive Enhancement

A while back, Jake Archibald tweeted:

Don't render buttons on the server that require JS to work.

The idea is that user interface elements which depend on JavaScript (such as buttons) should be rendered on the client-side, i.e. with JavaScript.

In the context of a progressive enhancement mindset, this makes perfect sense. Our minimum viable experience should work without JavaScript due to the fragility of a JavaScript-dependent approach so should not include script-triggering buttons which might not work. The JavaScript which applies the enhancements should not only listen for and act upon button events, but should also be responsible for actually rendering the button.

This is how I used to build JavaScript interactions as standard, however sadly due to time constraints and framework conventions I don’t always follow this best practice on all projects.

At work, we use Stimulus. Stimulus has a pretty appealing philosophy:

Stimulus is designed to enhance static or server-rendered HTML—the “HTML you already have”

However in their examples they always render buttons on the server; they always assume the JavaScript-powered experience is the baseline experience. I’ve been pondering whether that could easily be adapted toward better progressive enhancement and it seems it can.

My hunch was that I should use the connect() lifecycle method to render a button into the component (and introduce any other script-dependent markup adjustments) at the earliest opportunity. I wasn’t sure whether creating new DOM elements at this point and fitting them with Stimulus-related attributes such as action and target would make them available via the standard Stimulus APIs like server-rendered elements but was keen to try. I started by checking if anyone was doing anything similar and found a thread where Stimulus contributor Javan suggested that DIY target creation is fine.

I then gave that a try and it worked! Check out my pen Stimulus with true progressive enhancement. It’s a pretty trivial example for now, but proves the concept.

Accessible interactions (on Adactio)

Jeremy Keith takes us through his thought process regarding the choice of link or button when planning accessible interactive disclosure elements.

A button is generally a solid choice as it’s built for general interactivity and carries the expectation that when activated, something somewhere happens. However in some cases a link might be appropriate, for example when the trigger and target content are relatively far apart in the DOM and we feel the need move the user to the target / give it focus.

For a typical disclosure pattern where some content is shown/hidden by an adjacent trigger, a button suits perfectly. The DOM elements are right next to each other and flow into each other so there’s no need to move or focus anything.

However in the case of a log-in link in a navigation menu which—when enhanced by JavaScript—opens a log-in form inside a modal dialogue, a link might be better. In this case you might use an anchor with a fragment identifier (<a href="#login-modal">Log in</a>) pointing to a login-form far away at the bottom of the page. This simple baseline will work if JavaScript is unavailable or fails, however when JavaScript is available we can intercept the link’s default behaviour and enhance things. Furthermore because the expectation with links is that you’ll go somewhere and modal dialogues are kinda like faux pages, the link feels appropriate.

While not explicit in the article, another thing I take from this is that by structuring your no-JavaScript experience well, this will help you make appropriate decisions when considering the with-JavaScript experience. There’s a kind of virtuous circle there.

See all tags.

External Link Bookmark Note Entry Search