I'm pretty happy with this little bit of scss. It covers pretty much all the pain points of proper form validation styling without the additional pain of unnecessary javascript. I thought it was worth sharing.
tl:dr
input{
//input styles here
&:not(:placeholder-shown):not(:focus):invalid {
//changed styles here
}
}
For the unititated, here's what that little tiny snippet of pre-compiled scss does - immediately following the first { is just your normal input styling. That's where all the boiler plate stuff like border: solid 1px #000; will live. It's that nested bit where the fun begins.
With that single line of code, you're able to style the input when the following criteria are all met: The placeholder object is not visible, the input itself is not currently in focus, and the content of the input is invalid.
For any currently active web developers out there working with scss, that above block is likely enough to get you rolling. Beyond this point I'm going to walk through some basics to try and shed light on why this little string is so nice.
Forms are somewhat famous in the annals of HTMLdom as unweidly little turds. Tough to wrangle with & frustrating to polish, they seem to live in their own dimension, with their own warped version of the rules.
Once you've forced them to mirror your design with all the htmling and cssing, you still need to make sure they work well, and an important part of that process is validation.
The goal of validation is simple: make sure your forms are filled out properly.
There are two things you're looking to accomplish with proper validation: you want to make sure your form is actually filled out, and you need to confirm it's filled out with appropriate content in appropriate fields (e.g. you don't want an email in a name field, or vice versa).
For the actual base validation, HTML5 has you mostly covered. There are some delightfully simple attributes to handle input validation baked right into the spec. Simply adding "required" to any HTML input tag will tell most modern browsers to interrupt form submission if a particular field isn't filled out:
<input type="text" name="name" required>
Pretty simple, right? So is the next bit, and it's pretty cool — you can add a pattern attribute to any input to restrict what a user will be able to enter:
<input type="text" name="name" pattern="[a-zA-Z ]*" required>
So now with that simple addition, I'll only accept plain-text characters and spaces in a name field. Elon's kid might not be able to send me an email, but you could technically add an exception to your patterns to let little X Æ A-12 through. I'm not too worried about it. When he's old enoough to use web forms, he'll probably be complaining that they still exist on ancient websites that don't accept signals directly from his brain, but I digress.
Patterns are neat and extremely flexible, and once you have a few in place, you're pretty much set with basic front-end validation. As an aside — I will not be delving into server-side validation, which is extremely important as well, especially in a modern age full of malicious bots.
At this stage, we're just trying to make sure your forms accept proper input and are easy to use.
If you use only HTML validation methods, most modern browsers have standard messaging styles in place to tell a user, "Hey, that isn't right." Which is probably good enough for many, but certainly not us, right?
So glad you agree.
It's simple. We want the form to look good, and respond to user input with intentionally polished states at every possible stage.
What we don't want, is to make a form that is a spazzy or hostile experience, changing states too often or telling a user they are wrong until they are right, etc. etc.
What do you mean by 'every stage'? It's just a form sitting on a page, right?
For the most part every form input has four possible states:
There are exceptions, but you don't often need to think beyond that list.
The next detail I don't want to skim over; Adding the "placeholder" attribute on an input will render a ghosted label that automatically disappears when any character is typed in a field:
<input type="text" name="name" placeholder="Name" pattern="[a-zA-Z ]*" required>
Without adding any styling, that 👆 will look something like this 👇
Note the behavior of the placeholder label; As soon as I start typing, it's gone. That's how we get to have fun with the placholder-targeting css: :not(:placeholder-shown).
input:not(:placeholder-shown){
boder: solid 1px red;
}
👆That would make the input border turn red the second a single character was typed into the input, since that's when the placeholder object is no longer there.
So now we just take it a tiny bit further — I'm pasting the same starting scss snippet here so you don't need to scroll back up:
input{
//input styles here
&:not(:placeholder-shown):not(:focus):invalid {
//changed styles here
}
}
This approach ensures that we only ever show the user an error if they are -not- typing, and the input is -not- in focus, and when the content of the input does -not- match your defined pattern (that :invalid bit at the end). This is to ensure a pleasant experience while someone is actually typing.
Just to further drive this home, imagine you used a pattern for an input that required a length of at least 6 characters. If you didn't wait for the user to leave the input (this is called a blur event, or "on blur" in nerdy dev speak) before checking - it would display whatever error styling you put in place to a user -while- they are typing, until they reached your requirement of 6.
Imagine asking a child to spell their name and yelling "wrong" repeatedly until they finished.
While that would arguably be hilarious, it would make you look like an ass.
Check out how I used this method on my own contact form — I'm obviously going further with the styling, but this method uses zero javascript, allows me to restrict input patterns and allows me to wait until a user leaves an input before I tell them I am suspicious of their intent.
I assume there isn't anyone with the number 1 for a legal name, or that the chance of someone with that name coming to my site to send me a message is so rare that I'm willing to risk offense.
So anyway. That's my little scss share for the day. To learn way more about this action than I'm willing to share here, go check out mozilla's excellent resource on inputs.
Thanks for stopping by. Go kick the world in the face.