Tags: input



Unlabelled search fields

Adam Silver is writing a book on forms—you may be familiar with his previous book on maintainable CSS. In a recent article (that for some reason isn’t on his blog), he looks at markup patterns for search forms and advocates that we should always use a label. I agree. But for some reason, we keep getting handed designs that show unlabelled search forms. And no, a placeholder is not a label.

I had a discussion with Mark about this the other day. The form he was marking up didn’t have a label, but it did have a button with some text that would work as a label:

<input type="search" placeholder="…">
<button type="submit">

He was wondering if there was a way of using the button’s text as the label. I think there is. Using aria-labelledby like this, the button’s text should be read out before the input field:

<input aria-labelledby="searchtext" type="search" placeholder="…">
<button type="submit" id="searchtext">

Notice that I say “think” and “should.” It’s one thing to figure out a theoretical solution, but only testing will show whether it actually works.

The W3C’s WAI tutorial on labelling content gives an example that uses aria-label instead:

<input type="text" name="search" aria-label="Search">
<button type="submit">Search</button>

It seems a bit of a shame to me that the label text is duplicated in the button and in the aria-label attribute (and being squirrelled away in an attribute, it runs the risk of metacrap rot). But they know what they’re talking about so there may well be very good reasons to prefer duplicating the value with aria-label rather than pointing to the value with aria-labelledby.

I thought it would be interesting to see how other sites are approaching this pattern—unlabelled search forms are all too common. All the markup examples here have been simplified a bit, removing class attributes and the like…

The BBC’s search form does actually have a label:

<label for="orb-search-q">
Search the BBC
<input id="orb-search-q" placeholder="Search" type="text">
<button>Search the BBC</button>

But that label is then hidden using CSS:

position: absolute;
height: 1px;
width: 1px;
overflow: hidden;
clip: rect(1px, 1px, 1px, 1px);

That CSS—as pioneered by Snook—ensures that the label is visually hidden but remains accessible to assistive technology. Using something like display: none would hide the label for everyone.

Medium wraps the input (and icon) in a label and then gives the label a title attribute. Like aria-label, a title attribute should be read out by screen readers, but it has the added advantage of also being visible as a tooltip on hover:

<label title="Search Medium">
  <span class="svgIcon"><svg></svg></span>
  <input type="search">

This is also what Google does on what must be the most visited search form on the web. But the W3C’s WAI tutorial warns against using the title attribute like this:

This approach is generally less reliable and not recommended because some screen readers and assistive technologies do not interpret the title attribute as a replacement for the label element, possibly because the title attribute is often used to provide non-essential information.

Twitter follows the BBC’s pattern of having a label but visually hiding it. They also have some descriptive text for the icon, and that text gets visually hidden too:

<label class="visuallyhidden" for="search-query">Search query</label>
<input id="search-query" placeholder="Search Twitter" type="text">
<span class="search-icon>
  <button type="submit" class="Icon" tabindex="-1">
    <span class="visuallyhidden">Search Twitter</span>

Here’s their CSS for hiding those bits of text—it’s very similar to the BBC’s:

.visuallyhidden {
  border: 0;
  clip: rect(0 0 0 0);
  height: 1px;
  margin: -1px;
  overflow: hidden;
  padding: 0;
  position: absolute;
  width: 1px;

That’s exactly the CSS recommended in the W3C’s WAI tutorial.

Flickr have gone with the aria-label pattern as recommended in that W3C WAI tutorial:

<input placeholder="Photos, people, or groups" aria-label="Search" type="text">
<input type="submit" value="Search">

Interestingly, neither Twitter or Flickr are using type="search" on the input elements. I’m guessing this is probably because of frustrations with trying to undo the default styles that some browsers apply to input type="search" fields. Seems a shame though.

Instagram also doesn’t use type="search" and makes no attempt to expose any kind of accessible label:

<input type="text" placeholder="Search">
<span class="coreSpriteSearchIcon"></span>

Same with Tumblr:

<input tabindex="1" type="text" name="q" id="search_query" placeholder="Search Tumblr" autocomplete="off" required="required">

…although the search form itself does have role="search" applied to it. Perhaps that helps to mitigate the lack of a clear label?

After that whistle-stop tour of a few of the web’s unlabelled search forms, it looks like the options are:

  • a visually-hidden label element,
  • an aria-label attribute,
  • a title attribute, or
  • associate some text using aria-labelledby.

But that last one needs some testing.

Update: Emil did some testing. Looks like all screen-reader/browser combinations will read the associated text.

Pseudo and pseudon’t

I like CSS pseudo-classes. They come in handy for adding little enhancements to interfaces based on interaction.

Take the form-related pseudo-classes, for example: :valid, :invalid, :required, :in-range, and many more.

Let’s say I want to adjust the appearance of an element based on whether it has been filled in correctly. I might have an input element like this:

<input type="email" required>

Then I can write some CSS to put green border on it once it meets the minimum requirements for validity:

input:valid {
  border: 1px solid green;

That works, but somewhat annoyingly, the appearance will change while the user is still typing in the field (as soon as the user types an @ symbol, the border goes green). That can be distracting, or downright annoying.

I only want to display the green border when the input is valid and the field is not focused. Luckily for me, those last two words (“not focused”) map nicely to some more pseudo-classes: not and focus:

input:not(:focus):valid {
  border: 1px solid green;

If I want to get really fancy, I could display an icon next to form fields that have been filled in. But to do that, I’d need more than a pseudo-class; I’d need a pseudo-element, like :after

input:not(:focus):valid::after {
  content: '✓';

…except that won’t work. It turns out that you can’t add generated content to replaced elements like form fields. I’d have to add a regular element into my markup, like this:

<input type="email" required>

So I could style it with:

input:not(:focus):valid + span::after {
  content: '✓';

But that feels icky.

Update: See this clever flexbox technique by Hugo Giraudel for a potential solution.

Placehold on tight

I’m a big fan of the placeholder attribute introduced in HTML5. In my book, I described the cowpath it was paving:

  1. When a form field has no value, insert some placeholder text into it.
  2. When the user focuses on that field, remove the placeholder text.
  3. If the user leaves the field and the field still has no value, reinstate the placeholder text.

That’s the behaviour that browsers mimicked when they began implementing the native placeholder functionality. I think Opera was first. Now all the major browsers support it.

But in some browsers, the details of that behaviour have changed slightly. In Chrome and Safari, when the user focuses on the field, the placeholder text remains. It’s not until the user actually begins to type that the placeholder text is removed.

Now, personally speaking, I’m not keen on this variation. It seems that I’m not alone. In an email to the WHATWG, Markus Ernst describes the problems that he’s noticed in user-testing where users are trying (and, of course, failing) to select the placeholder text in order to delete it before they begin typing.

It seems that a relevant number of users do not even try to start typing as long as the placeholder text remains visible.

But this isn’t so clear-cut. A quick straw poll at the Clearleft showed that opinions were divided on this. Some people prefer the newer behaviour …however it quickly became apparent that the situations they were thinking of were examples of where placeholder has been abused i.e. attempt to act as a label for the form field. In that situation, I agree, it would definitely be more useful for the labelling text to remain visible for as long as possible. But that’s not what placeholder is for. The placeholder attribute is intended to show a short hint (such as an example value)—it should be used in addition to a label; not instead of a label. I tend to use example content in my placeholder value and I nearly always begin with “e.g.”:

<label for="fn">Your Name</label>
<input id="fn" name="fn" type="text" placeholder="e.g. Joe Bloggs">

(Don’t forget: generating placeholders from datalists can be a handy little pattern.)

So if you’re using placeholder incorrectly as a label, then the WebKit behaviour is probably what you want. But if you’re using placeholder as intended, then the behaviour in the other browsers is probably more desirable. If you want to get Safari and Chrome to mimic the behaviour of the other browsers, here’s a handy bit of CSS (from that same thread on the WHATWG mailing list):

[placeholder]:focus::-webkit-input-placeholder {
  color: transparent;

You can see that in action on search forms at The Session for recordings, events, discussions, etc.

Now, if you do want your label—or input mask—to appear within your form field and remain even when the user focuses on the field, go ahead and do that. Use a label element with some CSS and JavaScript trickery to get the effect you want. But don’t use the placeholder attribute.

Months and years

While I was in San Francisco for the last Event Apart of the year in December, Luke pulled me aside while he was preparing for his A Day Apart workshop on mobile web design. As befits the man who literally wrote the book on web forms and also wrote the the book on mobile-first design, Luke was planning to spend plenty of time covering input on mobile devices and he wanted my opinion on one of the patterns he was going to mention.

Let’s say you’ve got your typical checkout form asking for credit card details. The user is going to need to specify the expiry date of their credit card, something that historically would have been done with select elements, like so:

With the introduction of the new input types in HTML5, we can now just use input type="month".

That’s particularly nice on mobile devices that support input type="month" like Mobile Safari since iOS5.

input type="month"

But the behaviour on non-supporting browsers would be to display just like input type="text" …not ideal for inputting a date.

So the pattern that Luke proposed was to start with the traditional double drop-downs for month and year, and then use feature detection to replace them with input type="month" in supporting browsers.

That was an angle I hadn’t thought of. Usually when I’m implementing new HTML5 input types (like input type="number") I put the new type in the markup and then try to come up with JavaScript polyfills for older non-supporting browsers. In this case though, the old-fashioned way is what goes in the markup and JavaScript does the enhancing for newer browsers.

The only downside is that some the desktop browsers that do support input type="month" do so in a way that—from a UI standpoint—seems like a step backwards from simply having two selects: Safari displays it with a spinner control like input type="number", while Opera shows an entire Calendar (days’n’all).

Anyway, I threw a quick hack together as a proof of concept so you can see it in action. I’m sure you can improve upon it. Feel free to do so.