Labelling inputs

Tagged with:

Labels intro

A world without labels can be both a confusing and frustrating place, often we'd encounter surprises that would not necessarily be what we hoped for. Imagine if all the canned food in the local supermarket had no labels, an array of identical silver cans filling shelves, no indication of the contents, a game of luck to anybody that buys them. Picture the scene, you want something quick to eat, you put your bread in the toaster, put a pan on the hob and open a can in the hope that it contains baked beans, only it's dog food and you don't even have a dog, a fairly rubbish surprise, I'm sure you'll agree (unless of course you like dog food, I'm not judging).

Users of websites appreciate labels on inputs the same way we all appreciate labels on other things, without these input labels, oftentimes users have no idea what the input is for, which can be a complete blocker to using the site, especially for people with disabilities.

There are multiple ways to label inputs and other considerations to make which can give users the best experience when they encounter forms on our sites, let's dive a bit deeper.

Inputs must have an accessible name

What's an accessible name?, you may ask. Put simply, it's the name of the input, which is passed to the accessibility tree, a name can be programmatically associated with the input it relates to, which means a relationship exists between 2 elements in a page's HTML or it can mean that the actual input has a name which can be achieved using various attributes on the input element.

There are 2 primary WCAG success criteria to consider when an input does not have an accessible name, WCAG 3.3.2 Labels or Instructions at Level A and WCAG 4.1.2 Name, Role, Value at Level A

What options are there to name inputs?

First let's list the main the ways an input can have a name:

We're going to discuss each of them, with some practical examples. But first, we'll just go over the "Accessible Name and Description Computation", although from now on in, I'll refer to it is the "Accessible name calc", as it's a little shorter.

We could actually use all of those on an input, if we so wished, but please don't, so our input could be:

<label for="ourInput">Your name</label>
<input id="ourInput" type="text" aria-labelledby="someOtherText" aria-label="What is your name?" placeholder="What you called?" title="Full name">

<!-- Some text node anywhere else on the page -->
<p id="someOtherText">Tell me your name</p>

There's quite a lot going on there, isn't there? It felt equally as bad to type that, believe me.

So, before I explain, what is the actual name of the input, used in the Accessible name calc?

It's "Tell me your name", which depending on your level of knowledge of HTML, accessibility and ARIA, may come as a bit of a surprise.

So, in the above code snippet, we virtually threw everything at our input to give it a name, but we can only really have one winner and that winner will always be aria-labelledby, as it's like a toddler, it can shout really loud and be heard over the grown ups.

If we remove the aria-labelledby attribute, our input then has the name "What is your name?", because, aria-label is also quite shouty, not quite as shouty as aria-labelledby, this could be the slightly quieter twin of the aria-labelledby attribute toddler, not quite as shouty, but you can still hear them above almost everybody else.

If we then remove aria-label, our input then has the name "Your name", as the <label> element (with a reference to the input's ID, using the for="IDRef of the input", it's not as shouty as the ARIA attributes (toddlers), but it is the voice of reason within this hypothetical family analogy, it doesn't need to shout so loud (if used correctly).

Let's delete that <label> element, now our input's name becomes "What you called?", because the placeholder is like the family's teenager, it hardly ever speaks, it's sometimes there and often nobody has any idea where it's gone (yup, slight dig at placeholders there).

Finally, if we remove the placeholder attribute, we are of course just left with our title attribute, which is a bit like the family ghost (if that's a thing), some people can see it and some people will doubt its very existence.

So, the TL;DR is:

There is 1 more attribute in the Accessible name calc: aria-placeholder, I haven't discussed this as I don't know of a reason to ever recommend using it, when we could just use something that can be accessed by all users.

So which should we use?

The short answer is <label>, the long answer is, it almost always <label>. Labels are pretty much always going to be the better option, as if they are visible and situated next to the input with a correct programmatic relationship, then everybody benefits.

As an additional added bonus, clicking or tapping the label will force its related input to become focused, so the user can immediately start typing; this particularly benefits anybody who might have difficulty using a mouse or touchscreen, as the so called 'hit area' of the input becomes larger.

There are some situations where a visible label can perhaps be omitted, take a Site Search input, for example:

This tends to make these inputs identifiable, because of their location and the added affordance of the adjacent button, often we discover these without a visible label. How would we approach this? You could use a visually hidden <label>, which would still provide an accessible name, we'd lose the added bonus of a larger hit area, but we have a name. Alternatively, we could give our Search button an ID, so assuming the accessible name of the button is "Search", we could reference that with aria-labelledby, the following code snippet contains 3 examples:

// Using a hidden label
<label class="visually-hidden" for="ourInput">Search</label>
<input id="ourInput" type="text">
<button type="submit">Search</button>

// Button with text, using aria-labelledby
<input type="text" aria-labelledby="searchBtn">
<button type="submit" id="searchBtn">Search</button>

// Button with text, using aria-label
<input type="text" aria-label="Search">
<button type="submit">Search</button>

The hidden label and the aria-labelledby in this instance are both robust methods to naming an input where we don't have a visible label, as they both make a reference to some existing text, this means that translation tools will translate them for users of other languages. The aria-label method has some issues, in that not all translation software will be able to translate it.

If your Search button is an icon, as opposed to text, using aria-labelledby may not always be a suitable option, as if the button uses an aria-label for its accessible name, we still introduce a translation problem (because we are referencing an aria-label, which doesn't translate as well), but if our button has visually hidden text, then using aria-labelledby is a perfectly viable option, assuming our ID reference matches, of course.

<!-- Good example referencing actual text -->
<label for="ourInput">Your name</label>
<input id="ourInput" type="search" aria-labelledby="searchBtn">
<button type="submit" id="searchBtn">
<span class="visually-hidden">Search</span>

<!-- Not so good example, referencing an aria-label -->
<label for="ourInput">Your name</label>
<input id="ourInput" type="search" aria-labelledby="searchBtn">
<button type="submit" id="searchBtn" aria-label="Search"></button>

It's also worth noting that however we hide something in the DOM, whether that be with classes like .visually-hidden or .sr-only or even display properties such as display: none; or visibility: hidden; aria-labelledby can still derive the accessible name from that element, as it is designed to ignore all those display properties to form an accessible name.

Using a placeholder attribute

Placeholders introduce issues of their own, typically we encounter these with very low text contrast, so we fail them against WCAG 1.4.3 Contrast (Minimum) at Level AA, but then when the contrast is sufficient, they tend to make the inputs look like they have been pre-filled, which can be a source of confusion. Relying on a placeholder alone for an accessible name is quite a weak strategy, the moment a user types a single character in that field, it's gone, then if they get distracted or disturbed and forget what the field is for, they have to delete their input to get the placeholder back, which isn't a great experience for anybody.

Another issue with placeholders is that some screen readers will read both the label and the placeholder when a user encounters that input, which is a bit repetitive and we want to avoid stuffing lots of additional superfluous information into anything we create.

Using a title attribute

We should never use a title attribute as the only way of naming an input, keyboard users or touchscreen users never see them, so they're not a reliable way of naming inputs, this quote sums up their usage perfectly:

If you want to hide content from mobile and tablet users as well as assistive tech users and keyboard only users, use the title attribute
Steve Faulkner TPGi

The dangers of using ARIA

ARIA is a powerful tool, that can provide users of assistive technologies with additional information about parts of webpages, such as how to interact with them, their purpose, whether they are collapsed or expanded and much more. Remember that those 2 ARIA attributes we used, are our shouty little toddlers? Well, it's best to avoid adding ARIA labelling to inputs, unless strictly necessary, as we could end up with an a name that doesn't match what users can visually see.

The visible label must contain the accessible name

When we use ARIA on an input, that has a visible label, we run the risk of creating a mismatch of what a user can see and what the browser or the user's assistive technology names the input, the following code example demonstrates this risk:

<label for="ourInput">Search</label>
<input id="ourInput" type="text" aria-label="Look up all the things">
<button type="submit" id="searchBtn">Go</button>

In the above code, we have a visible label, using the <label> element, which also makes the correct association to the input with the id attribute, but, one of those shouty toddlers is there and they have a much louder voice. Now, our visible label does not match our accessible name as it has been overwritten, in fact, our example does not even include the visible label, which is the word "Search". This explicitly fails WCAG 2.5.3 Label in Name, at Level A. Not good, as this makes using the input a particular problem for users that control computers with voice commands, they may instruct their computer to "Click, search input" (or words to that effect) and nothing would happen, as the word search is not even included in the actual accessible name. They would then need to use the mouse grid, which is a much longer process. It's also worth pointing out that not all screen reader users are blind and not all blind people are completely blind, so there is a mismatch between what those users see and what they hear, which may be a source of confusion.

The exact wording of Label in Name is "The name must contain the text which is presented visually", so in order to meet that requirement, we'd need the word "Search" to appear in that aria-label, then technically it passes as it would be contained in the accessible name, but that doesn't always mean it's enough to work for everybody.

If we hide part of an accessible name, or use ARIA instead to overwrite the accessible name with more information, this won't work for users of MacOS/iOS VoiceControl, because it expects an exact match between the verbal instruction and the accessible name and they'll have to bring up the mouse grid, so it's a great practice to provide everybody with a nice clear label and avoid overwriting accessible names.

Sometimes we discover instructions hidden in ARIA, which is usually a misguided effort to help a screen reader user fill in an input or whatever, it's important to understand that accessibility is for everybody that needs it, not just one group, so we should avoid making the screen reader experience "better" at the cost of other users, such as voice users. With a little thought, we can provide the same comparable experience for everybody by using a correctly referenced <label>, if we need to add some instructions, such as a suggested format, provide everybody with those same instructions as part of the <label>. This way, everybody gets the same information, irrespective of how they are accessing the site.

Grouping labels

Sometimes we may have a group of related inputs that require input in a particular sequence, such as a a date of birth. There's all sorts of problems with these inputs if over-engineered, some examples being:

Three separate text inputs wrapped in a <fieldset> with a <legend> provides a much more error-proof solution, each field has a label, such as "Day", "Month" and "Year" and the

element has "Date of birth", such as in the following code example:

<legend>Date of birth</legend>
<label for="dayInput">Day</label>
<input id="dayInput" type="text">
<label for="monthInput">Month</label>
<input id="monthInput" type="text">
<label for="yearInput">Year</label>
<input id="yearInput" type="text">

The use of the <fieldset> provides a group role, which assists users in understanding the relationship between the three inputs, the group has an accessible name of "date of birth" and each field makes sense, as "Date of birth, year" etc, has sufficient context. A short write up by on how they arrived at this solution after testing with users can be read here, although avoid putting hints below inputs like in the linked example, as this will often be obscured by autofill suggestions, on your browser or password manager, so hints or errors could be missed by users. Also, ignore the placeholders, we don't need those either.

In the above example, it would be best to put the hint or even error in the <legend> element, as it will form part of the group name.

Wrapping up

  • The first thing you should reach for is a <label> element, although using an aria-labelledby can be a perfectly good substitute for site search inputs (as discussed earlier) and a limited amount of other use cases
  • Avoid using the title attribute
  • Avoid using placeholders
  • If Internationalisation matters (it should, right?), don't use aria-label
  • Use a <fieldset> and <legend> for input groups

Share on:


Site preferences

Please feel free to display our site, your way by finding the preferences that work best for you. We do not track any data or preferences at all, should you select any options in the groups below, we store a small non-identifiable token to your browser's Local Storage, this is required for your preferencesto persist across pages accordion be present on repeat visits. You can remove those tokens if you wish, by simply selecting Unset, from each preference group.


Code block theme

Code theme help

Code block themes can be changed independent of the site theme.

  • Default: (Unset) Code blocks will have the same theme as the site theme.
  • Light 1: will be default for users viewing the light theme, this maintains the minimum 7:1 (WCAG Level AAA) contrast ratio we have used throughout the site, it can be quite difficult to identify the differences in colour between various syntax types, due to the similarities in colour at that contrast ratio
  • Light 2: drops the contrast for syntax highlighting down to WCAG Level AA standards (greater than 4.5:1)
  • Dark: Syntax highlighting has a minimum contrast of 7:1 and due to the dark background differences in colour may appear much more perceivable


Motion & animation

Motion & animation help

  • Default (Unset): Obeys device settings, if present. If no preference is set, there are subtle animations on this site which will be shown. If you have opted for reduce motion, smooth scrolling as well as expanding and collapsing animations will no longer be present, fading transtitions and micro animations will still be still present.
  • None: All animations and transitions are completely removed, including fade transitions.


Underline all links

Underline all links help

  • Default (Unset): Most links are underlined, with a few exceptions such as: the top level links in the main navigation (on large screens), cards, tags and icon links.
  • Yes: Will add underlines to the exceptions outlined above, resulting in every link being underlined

Text and paragraphs

Font size (main content)

Font size help

This setting does not apply to the site's header or footer regions

  • Default (Unset): Font sizes are set to site defaults
  • Selecting Large or Largest will increase the font size of the main content, the size of the increase depends on various factors such as your display size and/or zoom level. The easiest way to determine which option suits you best would be to view this text after clicking either size's button
Letter spacing

Letter spacing help

  • Default (Unset): Default letter spacing applies
  • Increased: Multiplies the font size by 0.12 and adds the sum as spacing between each character
Line height

Line height help

  • Default (Unset): all text has a minimum line height of 1.5 times the size of the text
  • Increased: all text has a line height of twice the size of the text
Paragraph spacing

Paragraph spacing help

Paragraph spacing help
  • Default (Unset): The space between paragraphs is equivalent to 1.5 times the height of the paragraph's text
  • Increased: The space between paragraphs is equivalent to 2.25 times the height of the paragraph's text
Word spacing preference

Word spacing help

  • Default (Unset): No modifications to word spacing are present
  • Increased: Spaces between words are equivalent to 0.16 times the font size