You can do an impressive amount of form validation with just HTML attributes. You can make the user experience pretty clean and clear with CSS selectors. But it does require some CSS trickery to get everything just right!
(You can) make the label look like a placeholder
First: always use real elements. Just that alone is a UX consideration all too many forms fail on. Placeholders are suggestions for valid input, like putting “Tulsa” in an input labeled “City”.
I’d say if the form is short and an obvious pattern (like sign up or log in), you could use the placeholder visual pattern, but use real labels instead.
Taking a form like…
<form action="#0" method="post">
<div>
<input type="text" id="first_name" name="first_name">
<label for="first_name">First Name</label>
</div>
<!-- ... --->
</form>
You use the <div>
form {
max-width: 450px;
// positioning context
> div {
position: relative;
// Looks like placeholder
> label {
opacity: 0.3;
position: absolute;
top: 22px;
left: 20px;
}
}
}
You don’t need to do any tricky cursor stuff, because it’s all semantically wired up already. If they click the area taken up by the label, it will activate the input. If they click the input, it will activate the input. Both correct.
The trick is putting the input first (semantically fine) so you can hide the label on focus:
form {
/* ... */
> div {
> input[type="text"],
> input[type="email"],
> input[type="password"] {
&:focus {
& + label {
opacity: 0;
}
}
}
}
}
Make certain inputs required
Perhaps the easiest possible validation on a form you can do is use the required
attribute to require a field. No faster way to catch an error than letting the browser do it if it can!
<input
required
type="text"
id="first_name"
name="first_name">
Positively indicate valid input values
Let users know a field has been entered correctly. The browser can give us this information through the :valid
CSS selector:
form {
> input[type="text"],
> input[type="email"],
> input[type="password"] {
// show success!
&:valid {
background: url(images/check.svg);
background-size: 20px;
background-repeat: no-repeat;
background-position: 20px 20px;
// continue to hide the label
& + label {
opacity: 0;
}
}
}
}
}
:valid
, in this case, is ensuring the required condition is met, but that selector is also useful for validating the type of input.
Show reminders about validation of type
You can also require an input’s value to be of a certain type, like email
or number
. Here’s examples of all of them.
<input id="email" name="email" required="" type="email">
That input is both required and required to be a valid email address format. Let’s do this for the UX:
- Tell the user about the requirements when the field is focused
- Remind them the field doesn’t have a valid value otherwise
But also… don’t show any reminders when the input is empty. As in, don’t assume an invalid state. It’s just kind of annoying and unnecessarily negative. In order to do that, we’ll need to know if the input is empty or not.
Sub trick! Testing if an input has a value or not
We want to do stuff with :valid
and :invalid
, but we don’t want to jump the gun with :invalid
and use it before the input has a value.
Is there a CSS selector to test if an input is empty? Not really! You’d think :empty
would be it, but it’s not. That’s for matching things like
… container elements with nothing inside them. Inputs are no-content elements already.
The trick is to make sure the input has a placeholder value, then:
input:not(:placeholder-shown) {
}
We’re not really using placeholder in our demo, but a value of a single space works:
<input type="text" placeholder=" ">
:placeholder-shown
is super useful for us here! It’s basically the secret selector for testing if an input currently has a value or not.
There is no IE or Firefox support though, which is particularly difficult to navigate around. With new features like this, @supports
is normally a savior, but…
/* This doesn't work */
@supports (input:placeholder-shown) {
input:not(:placeholder-shown) {
}
}
You can’t use @supports
for selectors, only property/values (e.g. @supports (display: flex)
)
Testing for placeholder support in JavaScript is easy enough:
var i = document.createElement('input');
if ('placeholder' in i) {
}
But there doesn’t appear to be a simple way to test for :placeholder-shown
. So…. this might just need to wait for deeper browser support to use on big production stuff.
Assuming wonderful support, this is how the logic would play out…
form {
> div {
> input[type="text"],
> input[type="email"],
> input[type="password"] {
// When input is...
// 1. NOT empty
// 2. NOT in focus
// 3. NOT valid
&:invalid:not(:focus):not(:placeholder-shown) {
// Show a light reminder
background: pink;
& + label {
opacity: 0;
}
}
// When that invalid input becomes in focus (and also still isn't empty)
&:invalid:focus:not(:placeholder-shown) {
// Show the more robust requirement instructions below.
& ~ .requirements {
max-height: 200px;
padding: 0 30px 20px 50px;
}
}
}
// <input> ~
// <label> ~
// <div class="requirements">
.requirements {
padding: 0 30px 0 50px;
color: #999;
max-height: 0;
transition: 0.28s;
overflow: hidden;
color: red;
font-style: italic;
}
}
}
You can create robust validations
It’s not just required
or type="email"
(and the like), you can also client-side validate things like length (e.g. minimum password length or maximum characters in bio textarea) and even go full-on regex.
Here’s an article on that. Say you wanted password requirements like
- At least 6 characters
- At least 1 uppercase character
- At least 1 lowercase character
- At least 1 number
You can do that like:
<input pattern="(?=.*\d)(?=.*[a-z])(?=.*[A-Z]).{6,}" type="password" id="password" name="password" required placeholder=" ">
Demo
I’m leaving in the :placeholder-shown
stuff here, which makes this not work great in Firefox and IE totally fine because it’s supported now, other than IE 11.
A lot of awesome tricks here, but I’m not sure if
opacity: 0
is the best approach for the labels. That prevents you from clicking into previously-entered text where the (invisible) label is overlapping it. How aboutdisplay: none
orpointer-events: none
?You could also kick the label off the page to the left or do the clip() thingy too. In this case it doesn’t hurt the clickability as…
What I have done in the past for labels inside inputs is visually hide the labels by using
display: block;
,height: 0;
,overflow: hidden;
on the labels…and just using the placeholder attribute for the visually seen labels…You can style the placeholder text with pseudo selectors…My question…is this OK? or is this semantically OK? My thought with this approach was screen readers would still read the labels…but they would be visually hidden to sighted users…
Chris, you’re right, but I mean clicking literally into the text. Like, in the middle of it. Enter a name into the First Name field, then try clicking between the first couple of characters. The input field will focus, but it will place the cursor at the end of the text. Not very friendly :)
Great point on the clicking INTO text thing!
Seems like this is the way to go:
(Alter selector relevant to demo.)
Another trick I used before to avoid clicking on the label instead of on the input text is to put the label its z-index below the field and give the input field a transparent background.
The field wrapper can give back a background.
What I also like to do if the design allows for it, move the label during focus to a visible area so a user can still see the label while typing.
Or better yet, make the label visible at all times! Especially when for example autofill is used I really like to check if all fields are autofilled correctly. This technique is nice but imho should only be used for very small forms(like a searchbar or login) where it doesn’t hurt the usability.
And I do wonder if all screenreaders work correctly when placing labels after inputs even if the for and id‘s are linked correctly.
That’s where the floating label pattern comes into play pretty nicely.
I wish I could reply to a reply, but hey.
What I want to add to the conversation is: I agree with everything @René said.
:placeholder-shown
is neat, I hadn’t heard of that one before.The bouncing back and forth between valid and invalid when you’re typing an email is kind of rough. You could do something like this:
Which accomplishes a few things.
1. As long as someone is typing reasonably quickly it won’t toggle between invalid an valid which naturally happens twice as you’re typing an email address
2. It won’t mess with non-email fields (that back-and-forth shouldn’t happen anywhere else, and immediate feedback is generally preferable)
3. There’s no delay if someone fixes an invalid email which I think is important
I dig it.
This is super clever! Like a
debounce()
method in CSS!Loved the :placeholder-shown trick! Is there any polyfill for unsupported browsers?
What if the field is selected, but nothing is typed into it? Different browsers treat placeholders differently. Some hide the placeholder right away as the field is selected. Others wait until typing has started.
In cases where it’s hidden on focus, it won’t necessarily tell you that the field has a value. It will only tell you that the placeholder is not being shown. And this might be an edge case, but it is totally possible. Right?
Great article! My only hesitance is in the validation messaging for e-mail address and password during content entry. A user starts typing and sees a red error until the content entry is valid. I’m seeing this on more sites and understand that it’s progressive validation that doesn’t require a revisit after a submit attempt. My UX when running into this is:
“I’m trying to put in a valid password, hopefully a good one that works with the requirements. This takes concentration and this message is distracting.”
“I don’t want to be told that I’m wrong until I am.”
I don’t think the timing is wrong but I question the type of feedback. I would prefer that password validation rules would be presenting prior to entry. I’d prefer the more abstract, IMO less distracting validation used for first and last name. I think the iconic cue is better feedback, though I’d still prefer not using an “X” icon.
I’m mindful that this is a UX matter and not so much a CSS one, but I thought I’d still offer this. :-)
@Eric Carlisle,
I’ve always been partial to MailChimp’s approach to the password field, showing the requirements up front, marking them off as they are met (when typing) and gives you the okay once the requirements are all met.
https://login.mailchimp.com/signup
Firefox has the custom pseudo selector
-moz-ui-invalid
which is exactly the detector you would want for invalid, shows invalid state only after blur or submit on first use but then on every character later.https://developer.mozilla.org/en/docs/Web/CSS/:-moz-ui-invalid
I would also strongly recommend using Webshim as a polyfill for form validation, it does a JS backup for everything using the native HTML5 markup where possible and a lot more.
Very clever! One negative side effect is that you cannot (easily) use your mouse to select the email address you entered.
super!
In my opinion, it’s in many cases not advisable to hide the label, as this may hurt the usability/accessibility. After having filled such a form, it’s getting hard to remember which label was for which field. It might be obvious with “first name” or email-address, but that’s not always the case. Furthermore re-checking if one has filled all fields correctly is hard as the corresponding labels are missing.
Therefore I like approaches, where the label is still shown, in a less intrusive way like this:
+1
This is just so cool,thanks guys
First of all, thank you for a great article.
My only question is how would you test the required attribute using Selenium or similar automated testing framework? I don’t think it would be possible to get the text of the message or check that the message has appeared because as I understood it doesn’t have any separate html markup on the page.
The requirements div has max-height: 0 as initial state and max-height > 0 on invalid input+focus.
That’s testable.
What’s already testable is the required attribute itself, populate or remove all other fields and do a scripted submit.
I have to admit I don’t have much experience with selenium and there are probably better ways to check.
Great stuff! Keep in mind that any validation done client-side can be disabled. So validation needs to exist in the backend as well unless you want to run the risk of incorrect or unsecure data being submitted through the form.
This is great for UX though!
I still don’t understand why should we use labels (as placeholders) instead of the proper placeholders which were designed for this purpose?
Placeholders and labels serve a different purpose.
Placeholders are designed to give a hint on how to fill in a field. Labels are designed to describe what should be filled in. Also, labels(unless hacked like in this post) stay visible when the field is populated.
e.g.
<label>EAN<input type=text required name=postal placeholder='only digits like 013983'></label>
https://www.w3.org/WAI/GL/wiki/Using_@placeholder_on_input
Thanks, I do understand the overall purpose of the labels but I still don’t understand why should we change their main purpose (meaning) and use them as placeholders instead?
Labels (as I understand it) weren’t designed for this,
instead as you said right they should describe what should be filled into input and always be visible.
Esthetics.
Designers want placeholders – programmers(and accessibility people etc) want labels.
So as a compromise we make labels look like placeholders.
Like some comments already, it can be done but it doesn’t mean it’s a good practice.
I totally agree with you, especially with this part: “it can be done but it doesn’t mean it’s a good practice.”.
But think about newbies who’ll read this article where Chirs Coyier, who has an authority in web development,
tells: “…you could use the placeholder visual pattern, but use real labels instead.”
and doesn’t mention anything about best practices.
Not sure if I am also missing the point here. But I agree with Konstantin why would you use labels as placeholders when you should be using the placeholder attr?
I had a friend tell me a heartbreaking story one time.
He was doing some web work for a high school for the blind. They did a lot of research, as it was their companies first time doing web work that needed an (obviously) high level of accessibility. During that research they watched a lot of kids using the web.
Some of those kids were headed off to college next year, and they were in the process of applying for colleges. Most colleges, you do that online. Web forms! Some of these web forms were so poorly constructed that it was literally impossible for them to understand what information should go in those fields. Mostly: no label attached to the input (via the
for
andid
connection).People would offer to help them, but they would angrily rebuff. They were going off to college. They were going off on their own. And on the very first step of their journey, they need a helping hand, because someone has a build a website that is literally impossible to use for some people.
My point in this article is that you can use the placeholder visual pattern with real labels. It’s useful sometimes, as I mention, particularly on form in a really tight space or with an obvious pattern. Accessibility doesn’t have to suffer. I also agree with people who think, most of the time, labels should always be visible (as well as properly constructed).
What’s the current conventional wisdom on, where it fits in fine with the visual design/styling plans, skipping the
for
andid
connection and simply wrapping thelabel
element around theinput
? Is it still OK to do that?Here’s my take on it, and I almost 100% agree with Chris, with maybe a small caveat. First and foremost, proper labels are always needed, regardless if you’re also going to use placeholders. It’s semantically correct and good for accessibility. René said it best with his “different purposes” comment. So there’s really two things here:
Should we use placeholders as “labels” (an omit real
<label>
‘s)? I can’t imagine a good reason for this. For me, I like to have one strategy for all my forms on a given project — what I mean is, one set of CSS and JS to rule all forms. So the strategy for a signup form is the same as for an “edit my account” form. The reason why placeholders are not a good substitute for labels (besides the accessibility reasons), is that if I come to a form filled with data already (such as “edit my account”) and there are no visible ways of knowing what the fields are because placeholders were used as labels, that’s going to be a problem.Should we use labels with CSS to position them in the same place a placeholder would go?. I understand what Gavin is saying (why reinvent the wheel?), and I understand Chris’ point about we always need labels, accessibility, etc. My opinion is that if you’re going to put labels in the position of placeholders using CSS because you “like that look”, at least do “float label” strategy (http://bradfrost.com/blog/post/float-label-pattern/) so that there’s not a problem when the form is in edit mode, so I can see what I’m editing.
Another thought:
These are really great examples of how HTML and CSS can give so much value before you even begin scripting. My only quibble is that instructions for formatting, password validity, etc should always be shown before you even start typing, as part of the label or at least before the input. Give people a chance to get it right first time! Anything else is making them guess your requirements, then telling them off when they guess wrong.
Here’s my take on the matter:
Fields which are empty are regarded as invalid in that Pen (when they are required).
Borders turn blue on focus if the field is required and grey if it’s not.
I just need to look into that regexp stuff a little more. Email validation works in most browsers but not in all. And there’s the issue with support of my CSS and the attributes as mentioned in the article here.
Another pro tip:
<label>
elements are the best candidates for “semantics” as far as form validation error messages are concerned. The label-to-input element ratio is many-to-one.https://stackoverflow.com/questions/6014544/which-is-more-semantic-html-for-error-messages#6014665
Thanks Chris for codepen. I really like this pattern.
How about this with floating labels? For usability I feel it’s always a good idea (especially for long forms) to keep the labels.
Funny timing here’s a new Medium post about form input placeholders being problematic:
https://medium.com/simple-human/10-reasons-why-placeholders-are-problematic-f8079412b960#.n97i6ghsy
I wasn’t aware, that the browser’s e-mail verification is so easily fooled:
name@domain
is enough to satisfy all browsers I’ve tested.
Adding a pattern attribute helps:
Luckily the browser isnt as strict as you are or otherwise I wouldnt be able to register several valid mail addresses. First issue: there are many tlds longer dan 3 chars. 2nd: the domain part can be something like an ip. 3rd: domain can even be just the tld or localhost.
I dont know about before the @ but Im guessing a lot more is allowed.
Yes René, this regex sucks, I just copied the first that came up in Google. But that’s not my point. I think from a UI point of view it’s confusing, when an obviously incorrect email address is validated with a checkmark. If you stress Google enough, you’ll find a RFC 5322 compliant regex. Or – to go the other way – you can use something just slightly better than what browser use (e.g. requiring an @ and a dot).
The complete regex sounds good but it’s way too heavy. And requiring a dot is still incorrect.
Wiki gives a nice list of do’s and don’ts: https://en.wikipedia.org/wiki/Email_address#Examples
Beyond the programming point of view:
Required fields and typecasting should only be seen as a hint for users that they should fill in fields. Any more than that is fooling yourself. You can check everything as good as you want using client side and server side validations but a user can still use bogus mail addresses if they want to do wrong. Even sending a verification mail can be fooled by using a temporary mailbox.
So what the browsers implemented is a great way for users to see if they didn’t fill in something incorrectly. Like putting a name inside the email field.
You might say a better regex would help users find typos but I seriously doubt the missing dot is a more common typo than all other letter typos combined. At least not in our databases.
Sorry if my post seems aggressive towards yours, it’s meant more general. I just have a strong opinion on this matter. Fed by a lot of websites where validation is used very very incorrectly. Probably by programmers who assume an email address is always [email protected] or every postal address in every country contains just a street name and street number. Not even mentioning postal codes…
Great read, thanks! While I understand the situation is not easy it is all about an user experience. We cant be disturbed and upset of different combinations of solutions which with certainty will neglect into a positive communication solution. Hence the different solution to many different thing. more article like this please!
Thanks for the Wikipedia link! I wasn’t aware, that name@domain actually IS a valid address. But I still believe, that a checkmark that pops up when I’m halfway done typing my email address is not helpful, even confusing.
In this case it seams better to me, to replace the browsers validation with JavaScript that kicks in onBlur. Or use Alex Zaworski’s suggestion with a transition-delay of 1 second or even more. I was baffled, when I typed my email address in the test form and that’s usually a hint, that other users might be too.
I totally agree, that email fields in many forms use crappy regexes. Many reject +addresses that I use very often and nobody wants to disable JS all the time to fill out a form with bad validation.
Huh? Sure there is. Just do
document.querySelector(":placeholder-shown");
. If it’s supported, it won’t throw aSyntaxError
.Tested in Firefox, Edge and IE11.
Love it. I do have one issue, which is that although my form uses the same basic structure, labels aren’t clickable as in the demos here. The only difference in styles that I can see between the demo and my setup is that my labels have a display property (changes to which have no impact on behavior).
What would affect the result of a click on a label element like this?
Instead of :placeholder-shown which appears not to be widely supported, why not detect if the input field has a value using Javascript? Something like this should do the trick (I’m using JQuery because I’m familiar with it but it’s not strictly needed) :
Placeholder text inside fields are a bad idea. Full stop.
It doesn’t matter whether they are semantically labels or placeholders. They have numerous problems, as Adam Silver’s article – posted by Brent – shows.
Worringly, the fact that the reknown Chris Coyier has posted this technique is likely to add to the perpetuation of this awful web trend.
It’s not about designers versus developers versus accessibility. It’s about user experience, for everyone. And unless you absolutely have to – which happens very rarely – you should never have placeholder text inside fields.
Other problems with what Chris is presenting:
inbuilt HTML5 validation messages are poorly worded and designed, and should be avoided like the plague
sometimes, the only thing indicating a validation failure is pink shading, which is inaccessible.
I endorse what other’s have said already in comments: just because you can do something doesn’t mean you should. This makes it all the more important for leaders in our community to be careful about what they propose.
I completely agree with everything Jessica said.
It makes me extremely sad to see developers and designers wasting their valuable time on something that is such a bad idea.
Please: there are so many other things that we need you to work on. Why not make an accessible type-head box instead, for example?
Just remember: never have placeholder text inside fields.