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">
)
Links
HTML Implementation
A basic link
<a href="https://css-tricks.com">CSS-Tricks</a>
That’s a link to a “fully qualified” or “absolute” URL.
A relative link
You can link “relatively” as well:
<!-- Useful in navigation, but be careful in content that may travel elsewhere (e.g. RSS) -->
<a href="/pages/about.html">About</a>
That can be useful, for example, in development where the domain name is likely to be different than the production site, but you still want to be able to click links. Relative URLs are most useful for things like navigation, but be careful of using them within content — like blog posts — where that content may be read off-site, like in an app or RSS feed.
A jump link
Links can also be “hash links” or “jump
links” by starting with a #
:
<a href="#section-2">Section Two</a>
<!-- will jump to... -->
<section id="section-2"></section>
Clicking that link will “jump” (scroll) to the first element in the DOM with an ID that matches, like the section element above.
💥 Little trick: Using a hash link (e.g.
#0
) in development can be useful so you can click the
link without being sent back to the top of the page like a click on
a #
link does. But careful, links that don’t link
anywhere should never make it to production.
💥 Little trick: Jump-links can sometimes benefit from smooth scrolling to help people understand that the page is moving from one place to another.
It’s a fairly common UI/UX thing to see a “Back to top” link on sites, particularly where important navigational controls are at the top but there is quite a bit of content to scroll (or otherwise navigate) through. To create a jump link, link to the ID of an element that is at the top of the page where it makes sense to send focus back to.
<a href="#top-of-page">Back to Top</a>
Jump links are sometimes also used to link to other anchor
(<a>
) elements that have no
href
attribute. Those are called
“placeholder” links:
<a id="section-2"></a>
<h3>Section 2</h3>
There are accessibility considerations of these, but overall they are acceptable.
There are accessibility considerations of these, but overall they are acceptable.
Do you need the link to open in a new window or tab?
You can use the target
attribute for that, but it is
strongly discouraged.
The bit that makes it work is target="_blank", but note the extra rel attribute and values there which make it safer and faster.
Making links open in new tabs is a major UX discussion. We have a whole article about when to use it here. Summarized:
Don't use it:
- Because you or your client prefer it personally.
- Because you're trying to beef up your time on site metric.
- Because you're distinguishing between internal and external links or content types.
- Because it's your way out of dealing with infinite scroll trickiness.
Do use it:
- Because a user is doing something on the current page, like actively playing media or has unsaved work.
- You have some obscure technical reason where you are forced to (even then you're still probably the rule, not the exception).
Styling & CSS
The default look of a link has it written and underlined in blue.
It's likely you'll be changing the style of your links, and also likely you'll use CSS to do it. I could make all my links red in CSS by doing:
- a { color: red; }
Sometimes selecting and styling all links on a page is a bit heavy-handed, as links in navigation might be treated entirely differently than links within text. You can always scope selectors to target links within particular areas like:
- nav a {}
- article a {}
- text a {}
Link States
Links are focusable elements. In other words, they can be selected using the Tab key on a keyboard. Links are perhaps the most common element where you'll very consciously design the different states, including a :focus state.
- :hover: For styling when a mouse pointer is over the link.
- :visited: For styling when the link has been followed, as best as the browser can remember. It has limited styling ability due to security.
- :link: For styling when a link has not been visited.
- :active: For styling when the link is pressed (e.g. the mouse button is down or the element is being tapped on a touch screen).
- :focus: Very important! Links should always have a focus style. If you choose to remove the default blue outline that most browsers apply, also use this selector to re-apply a visually obvious focus style.
JavaScript Considerations
Say you wanted to stop the clicking of a link from doing what it
normally does: go to that link or jump around the page. In
JavaScript, you can usepreventDefault
to prevent
jumping around.
const jumpLinks = document.querySelectorAll("a[href^='#']");
jumpLinks.forEach(link => {
link.addEventListener('click', event => {
event.preventDefault();
// Do something else instead, like handle the navigation behavior yourself
});
});
This kind of thing is at the core of how "Single Page Apps" (SPAs) work. They intercept the clicks so browsers don't take over and handle the navigation.
SPAs see where you are trying to go (within your own site), load the data they need, replace what they need to on the page, and update the URL. It's an awful lot of work to replicate what the browser does for free, but you get the ability to do things like animate between pages.
Another JavaScript concern with links is that, when a link to another page is clicked, the page is left and another page loads. That can be problematic for something like a page that contains a form the user is filling out but hasn't completed. If they click the link and leave the page, they lose their work! Your only opportunity to prevent the user from leaving is by using the beforeunload event.
Accessibility Considerations
We covered some accessibility in the sections above (it’s all related!), but here are some more things to think about.
- You don’t need text like “Link” or “Go to” in the link text itself. Make the text meaningful (“documentation” instead of “click here”).
- Links already have an ARIA role by default (role="link") so there's no need to explicitly set it.
- Try not to use the URL itself as the text (google.com)
- Links are generally blue and generally underlined and that's generally good.
- All images in content should have alt text anyway, but doubly so when the image is wrapped in a link with otherwise no text.
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.