# Easy Toggle Switches
2019-02-18
Sometimes there is a need to use toggle elements in-place of the default `checkbox` inputs. The problem is, I tend to see a lot of developers reaching for plugins or JavaScript components in order to implement these toggles.
*This is overkill*. You can create your own custom `input` elements to mimic toggles perfectly with just a small amount of CSS.
## What we will be building
![Easy toggle switches](/public/images/easy-toggle-switches.png)
[Live CodePen Example](https://codepen.io/bradleytaunt/pen/bGgbajY)
## The HTML
The build structure for these toggles is really simple, we only need:
- a parent container to hold all our corresponding elements
- a checkbox `input` element (which we will hide)
- an empty label designed to represent the slider
- a text label that references the `input`
/* Main toggle parent container */
/* Checkbox input, hidden with CSS */
/* The toggle slider element */
/* The text label to the right of the slider */
And that's everything we need for the HTML.
**ProTip:** Don't forget to increment both the `id` and `for` attributes when adding additional toggles. This seems like a no-brainer but it's overlooked more than you think.
## The CSS
To get things started we will add the styling to the `.toggle-switch` item directly (using `flexbox` in this demo for easier layout).
**Sidenote**: You will notice the inclusion of CSS variables in this demo - if you are unfamiliar with how to use root variables in CSS, take a look at one of my previous posts: CSS variables.
:root {
--primary-color: #4A90E2;
}
.toggle-switch {
align-items: center;
display: flex;
font-size: 14px;
justify-content: center;
margin: 20px 0;
}
Next we will hide the default browser checkbox element since we won't be needing it:
.toggle-input {
position: absolute;
visibility: hidden;
z-index: -1;
}
Let's also add some base styling for the `label` containing the text corresponding to it's `input` sibling:
.toggle-label {
color: #ccc;
cursor: pointer;
font-weight: bold;
padding-left: 10px;
text-shadow: 1px 1px 0 rgba(255,255,255,0.3);
transition: ease all .3s;
}
Now we target the `.toggle-slider` label and add the styling for the main slider base:
/* This is just the main slider base */
.toggle-slider {
background: #eee;
border-radius: 9999px;
box-shadow: inset 0 2px 4px rgba(0,0,0,0.1),
inset 0 4px 8px rgba(0,0,0,0.1),
0 1px 1px rgba(255,255,255,1);
cursor: pointer;
display: inline-block;
height: 20px;
position: relative;
transition: all ease .3s;
width: 40px;
}
We *could* include a separate element for the circle toggle switcher itself, but instead we will use the `:before` pseudo element:
.toggle-slider:before {
background: white;
border-radius: 9999px;
box-shadow: 0 4px 8px rgba(0,0,0,0.1),
0 2px 4px rgba(0,0,0,0.2);
content:'';
height: 16px;
left: 2px;
position: absolute;
top: 2px;
transition: all ease .3s;
width: 16px;
}
### Interaction
Right now we just have a static toggle that does nothing when the user interacts with it. Let's change that by moving the pseudo element's position based on the checkbox `input` state and updating the label text color:
.toggle-input:checked + .toggle-slider {
background: var(--primary-color);
}
.toggle-input:checked + .toggle-slider:before {
/* Move 100% of the width minus it's own width plus initial 'left' */
left: calc(100% - 18px);
}
.toggle-input:checked ~ .toggle-label {
color: var(--primary-color);
}
And because we already included the `transition` property on both the base slider and label text, everything animates nicely between state changes.
## Final code
To make things easier, you can find the HTML & CSS is their entirety below:
### HTML