Links & Buttons

There is a lot to know about links and buttons in HTML. There is markup implementation and related attributes, styling best practices, things to avoid, and the even-more-nuanced cousins of the link: buttons and button-like inputs.


Let's take a look at the whole world of links and buttons, and all the considerations at the HTML, CSS, JavaScript, design, and accessibility layers that come with them. There are plenty of pitfalls and bad practices to avoid along the way. By covering it, we’ll have a complete good UX implementation of both elements.

Quick Guidlines

  • Are you giving a user a way to go to another page or a different part of the same page? Use a link (<a href="/somewhere">link</a>)
  • Are you making a JavaScript-powered clickable action? Use a button (<button type="button">button</button>)
  • Are you submitting a form? Use a submit input (<input type="submit" value="Submit">)


Buttons

Buttons are for triggering actions. When do you use the <button> element? A good rule is to use a button when there is "no meaningful href." Here’s another way to think of that: if clicking it doesn’t do anything without JavaScript, it should be a <button>.

A <button> that is within a <form>, by default, will submit that form. But aside from that, button elements don't have any default behavior, and you'll be wiring up that interactivity with JavaScript.

HTML Implementation

<button>Buy Now</button>

Buttons inside of a <form> do something by default: they submit the form! They can also reset it, like their input counterparts. The type attributes matter:

<form action="/" method="POST">
    <input type="text" name="name" id="name">
    <button>Submit</button>
  
    <!-- If you want to be more explicit... -->
    <button type="submit">Submit</button>
  
    <!-- ...or clear the form inputs back to their initial values -->
    <button type="reset">Reset</button>
  
    <!-- This prevents a `submit` action from firing which may be useful sometimes inside a form -->
    <button type="button">Non-submitting button</button>
  </form>

Styling & CSS

Buttons are generally styled to look very button-like. They should look pressable. If you're looking for inspiration on fancy button styles, you'd do well looking at the CodePen Topic on Buttons.

Cross-browser/platform button styles

How buttons look by default varies by browser and platform.

While there is some UX truth to leaving the defaults of form elements alone so that they match that browser/platform's style and you get some affordance for free, designers typically don't like default styles, particularly ones that differ across browsers.

JavaScript Considerations

Even without JavaScript, button elements can be triggered by the Space and Enter keys on a keyboard. That's part of what makes them such appealing and useful elements: they are discoverable, focusable, and interactive with assistive technology in a predictable way.

Perhaps any <button> in that situation should be inserted into the DOM by JavaScript. A tall order! Food for thought. 🤔

JavaScript Frameworks

It's common in any JavaScript framework to make a component for handling buttons, as buttons typically have lots of variations. Those variations can be turned into an API of sorts. For example, in React:

It’s common in any JavaScript framework to make a component for handling buttons, as buttons typically have lots of variations. Those variations can be turned into an API of sorts. For example, in React:

const Button = ({ className, children }) => {
      const [activated, setActivated] = React.useState(false);
      return (
        <button
          className={`button ${className}`}
          aria-pressed={activated ? "true" : "false")
          onClick={() => setActivated(!activated)}
        >
          {children}
        </button>
      );
    };

In that example, the <button> component ensures the button will have a button class and handles a toggle-like active class.

Accessibility Considerations

The biggest accessibility consideration with buttons is actually using buttons. Don't try to replicate a button with a "div" or a "span", which is, unfortunately, more common than you might think. It's very likely that will cause problems. (Did you deal with focusability? Did you deal with keyboard events? Great. There's still probably more stuff you're forgetting.)

ARIA

Buttons already have the role they need (role="button"). But there are some other ARIA attributes that are related to buttons:

  • aria-pressed: Turns a button into a toggle, between aria-pressed="true" and aria-pressed="false". More on button toggles, which can also be done with role="switch" and aria-checked="true".
  • aria-expanded: If the button controls the open/closed state of another element (like a dropdown menu), you apply this attribute to indicate that like aria-expanded="true".
  • aria-label: Overrides the text within the button. This is useful for labeling buttons that otherwise don't have text, but you're still probably better off using a visually-hidden class so it can be translated.
  • aria-labelledby: Points to an element that will act as the label for the button.