Animating forms like a semi pro ✨
Tags: css, tutorial, webdev, beginners
Published: 2019-12-31 12:31:32

---
title: Animating forms like a semi pro ✨
published: true
description: Showing the different states of a form is important and easy!
tags: css, tutorial, webdev, beginners
cover_image: https://thepracticaldev.s3.amazonaws.com/i/opbkjb2volx43tor3a25.jpg
---

**Have you ever come across a form which used placeholders in stead of labels? THE HORROR.**

Placeholders disappear after you start writing, but also when they're prefilled by Chrome for example. This means you can't check if Google put your address actually in the address input, all in all; VERY bad user experience (UX).

This article is about the front end of forms only, I'm no expert in posts and javascript validation.

[Head straight to the fancy stuff](#the-fancy-form).

#### Semantics
Animating forms like a semi pro begins with a good setup of a form.


```html
<form class="form">
  <div class="form__input-container form__input-container--text">
    <input type="text" class="form__input form__input--text" id="firstname" name="firstname" placeholder=" " />
    <label class="form__label form__label--text" for="firstname">First name: </label>
  </div>
  [...]
</form>
```

I use [BEM](http://getbem.com/introduction/) syntax for classes, this makes it really easy to style similar elements like inputs, but for clarity's sake I'll just use the element names in this article.

I encased the input and label in a div, this will make it much easier to style later on. I added a `name` attribute to the input element, without this the input is useless and will not send any data. I used the `for` attribute on the label to link it to the ID attribute on the input, now if you click the label you'll focus on the input. I added the label after the input to be able to style it with sibling selectors :).


#### Pseudo classes!
Form elements have a lot of [pseudo classes](https://developer.mozilla.org/en-US/docs/Web/CSS/Pseudo-classes) available, you can check the state of an input with things like `:valid`, `:checked` etc.

```scss
input:checked + label::after {
  left: 0.3rem;    
}
```
*Selecting the label's ::after pseudo element that is a sibling of the checked input.*

It's possible to add multiple pseudo classes at once:

```scss
input:placeholder-shown:not(:focus) + label { 
  position: static;
  padding: 10px 20px;
  font-size: 1rem;
}

```
The `:placeholder-shown` pseudo class is still experimental, you should only use it for enhancements, not features. It's an amazing enhancement though, you do need to **put a placeholder attribute on the input element for it to work**, but it can be empty!


The [`:not`](https://developer.mozilla.org/en-US/docs/Web/CSS/:not) pseudo class allows you to check if an input is not `:focus`ed, CRAZY inception type stuff, but very fun.


#### Validating with css
Some types of input elements (like `type="email"`) have their own built in validation, you can also add a pattern attribute to inputs to be able to validate them with css.
It always reaaally bugged me that validation already started before you were even done typing. I admitted before that `:placeholder-shown` is not well supported so this is more of a future thing, but I found a way to only show errors and validation after you filled an input and weren't focussed on it anymore:

```scss
input:not(:placeholder-shown):not(:focus):invalid {
  border-bottom: red 2px solid;
}
        
input:not(:placeholder-shown):not(:focus):valid {
  border-bottom: green 2px solid;
}
```

#### Animating custom radio buttons
I always create custom radio buttons and because it is still not possible to animate the browser's standard ones I create them by using `::before` and `::after` [pseudo elements](https://dev.to/cydstumpel/making-magic-with-before-and-after-pseudo-elements-2fb2).

```scss
input[type="radio"] + label {
  position: relative;
  display: block;
  padding-left: 30px;
  border-radius: 1rem 0 0 1rem; // t
  overflow: hidden;
}

// we're actually creating our own radio button styles
input[type="radio"] + label::before,
input[type="radio"] + label::after {
  content: '';
  position: absolute;
  left: 0;
  top: 0;
}
input[type="radio"] + label::before {
  // this makes up the border around the input
  width: 1rem;
  height: 1rem;
  border: 1px solid black;
  border-radius: 50%;
}
input[type="radio"] + label::after {
  // this makes up the dot to indicate if it's selected or not
  width: 0.5rem;
  height: 0.5rem;
  background: black;
  border-radius: 50%;
  top: 50%;
  left: -10px;
  // because the label has a `overflow: hidden` style the dot will be invisible at -10px
  transform: translateY(-50%);
  transition: left 0.4s;
}
input[type="radio"] {
  opacity: 0;
  width: 0;
  height: 0;
  padding: 0;
}
input[type="radio"]:checked + label::after {
  left: 0.3rem; // this makes the dot visible again, only when the input is checked.
}
```

#### Editing focus states
I know the standard focus states of really every browser is to say the least probably not conformant to your website's style. But before you remove it all together think about the keyboard dependent users out there! It's really easy to add some kind of focus style (it doesn't need to be dotted or blue) and it's not only disabled people who use the keyboard it's also a lot of developers!

*N.B. You can do a lot more with pseudo classes this is just the tip of the iceberg, for example you can check if an input is `:disabled`. 
Css/HTML validation is **not** an alternative to JavaScript validation, it's a lot easier to do complex checks with a script than write it in an input pattern attribute.*


#### The fancy form
{% codepen https://codepen.io/Sidstumple/pen/xxbXrON %}