Labels as placeholders
Tags: beginners, html, css, a11y
Published: 2020-05-04 10:27:50

Yesterday I was trying to find a nice-looking design for a Sign Up/Login form. And because I am learning how to make my projects more accessible, my wish was to find a modern design keeping in mind label elements. But there is this tendency now for keeping the info inside the inputs, and many tutorials show how to make this but only with placeholders, avoiding to use labels or ARIA at all. 

After seeing appealing designs I didn't want to choose between them and the labels... So I didn't.

##INITIAL HTML/CSS##

Let's show this with a basic form: a label for each input, and both wrapped inside a container (the order of the elements is important for using the right selectors later). Don't worry if they look a little messy now, we'll fix that.

{% codepen https://codepen.io/drowvoloper/pen/LYpOBqM %}


Now we want to set label's position as absolute, in order to free it and being able to simulate the position of a real placeholder. Don't forget that parent position must be relative or you will find unexpected issues.

This is the only step you will need to write placeholders: use them as a reference for positioning your labels!

{% codepen https://codepen.io/drowvoloper/pen/wvKPEao %}

##THE SELECTORS##

Ok, so we have the labels where the placeholders should be. But there is an evident issue: they don't disappear when we  focus or write inside the input field. We could use JavaScript for this...

![An indignant woman saying "But it's not necessary"](https://3.bp.blogspot.com/-BF36iZOT464/XD_No7Q-wgI/AAAAAAAAH6Q/N3q5p6IPCyA08iZJl0xukFTRMoq4NGj8gCLcBGAs/s400/not.gif) 


The reason we needed to place the label elements after their corresponding input fields is because we are going to use `element1 ~ element2` CSS selector. This let us style element2 (label, for us) when it's preceded by element1 (input field). You could also use `element1 + element2` selector, but then you could not place other elements between the input and its label (such as icons or error messages).

``` css
input ~ label {
 /* Block will be applied to all the sibling labels which are predeceded by an input*/
}


input + label {
 /* This will be applied only to the first sibling label when it is placed immediately after the input */
}
```

Unfortunately using just `input ~ label` will remove our labels, so we need to use a more specific selector which allows us to change the style only when we want (on focus and when the field is not blank). This will be possible with `element:focus` and `element:not(:placeholder-shown)` selectors. The first one is triggered when the element is focused by the user and the second selector works only when the placeholder is not shown (that is, when the input field has some text!). 

These two selectors will help us to hide the labels dynamically, relying on the input field's status.

![A man doing funny gestures and saying "Wait a moment"](https://media2.giphy.com/media/l0MYG9ihyGho5nXC8/giphy.gif?cid=ecf05e47d92e68dedde9914dedc5bdc86e3f07a50b636165&rid=giphy.gif) 

"Wait, didn't you say that placeholders weren't necessary?". Well... technically we don't have to WRITE anything! You will only need to leave a blank space like this: `placeholder=" "`. You could actually write something there, but some screen readers does read placeholders, and it would double the info for those users. This can be useful if you wanna provide additional information specifically for them, though. [You can find a way to hide placeholders visually here](https://stackoverflow.com/questions/30794947/hide-placeholder-with-css).

##Now, how do we hide the labels?##

Remember! we are trying to make this form accessible, so the approach can't be setting label's display property to "none", as this will remove the element from the document. I thought setting the color font to "transparent" would make the trick, but it evidently triggered unexpected -not really- behaviour since the text is still selectable. 

Although opacity: 0 worked for NVDA, other screen readers won't read it, so it's not an option either. We want to hide the text visually, but keeping the access to the labels for assistive technologies even if the field is not blank.

![Hermione, a Harry Potter's character, with a thoughtful look](https://www.reactiongifs.com/r/ewis1.gif)

Finally, after looking for information through some threads about accessibility, I decided to use `z-index` property. The reason is screen readers (I used NVDA and ChromeVox) didn't notice the change, and it doesn't affect the keyboard usability in this case.  

```css
input:focus ~ label,
input:not(:placeholder-shown) ~ label {
  z-index: -1;
}
```

I was really surprised when I tried to search "index" or "z-index" as key words in big, old accessibility blogs/sites and I couldn't find anything. Even [w3C](https://www.w3.org/WAI/search/?q=z-index) has nothing about it. This is a good sign for me, since they always talk about bad habits or accessibility issues as a result of poor HTML elements and CSS use. 


![A monkey plush, flipping out](https://media1.tenor.com/images/f99504c04228473ddcc9b16d07eb3de1/tenor.gif?itemid=17074006) 

However, I read somewhere this may cause some penalties by search engines. If this is something you worry about, another [SEO friendly and accesible options for hiding elements](https://css-tricks.com/snippets/css/accessibilityseo-friendly-css-hiding/) are explained by Chris Coyier in CSS-Tricks.  


{% codepen https://codepen.io/drowvoloper/pen/oNjoPdg %}

And that's it!

Note: Hiding labels visually is not a good UX/UI practice and it shouldn't be done specially for large forms, but this can be fun with learning purposes. 

I hope you enjoyed and/or learned something new! If you found issues or know how to improve this, I would be happy to learn more. 

All the best and keep safe!