Create a simple On/Off slide toggle with CSS
Tags: css
Published: 2020-10-22 12:30:37

---
title: Create a simple On/Off slide toggle with CSS
published: true
description: In this tutorial, we'll create a simple on/off button that slides between the two states.
tags: css
cover_image: https://dev-to-uploads.s3.amazonaws.com/i/k9sas2uoccun5uk5abgg.jpg
---
*Cover photo by Wolfgang Mennel</a> on [Unsplash](https://unsplash.com/s/photos/switch-on-off?utm_source=unsplash&amp;utm_medium=referral&amp;utm_content=creditCopyText).*

I was asked the other day at work to change a two-button setup for managing the active status of a user into some kind of slide toggle widget.

![Button Sketch](https://dev-to-uploads.s3.amazonaws.com/i/sjkaql2748vyhr987d3m.jpg)
So instead of clicking a button to either enable/disable a user, there would be some kind of on/off toggle to change the user's status.

In the past, when I've had to do something like this I've just Googled a solution and then copied it into whatever project I've been working on.  

This time, I thought it would be nice to create my own from scratch understanding how to create such a widget.

Here's the finished result of the slide toggle:

{% codepen https://codepen.io/codebubb/pen/OJXRGyN %}

I opted to go for a simple slide toggle for on/off states using just HTML/CSS to make the widget more accessible and to give me a bit more a challenge!

Here's how I did it.

## The Markup

```html
<div class="custom-checkbox">
  <input id="status" 
         type="checkbox" 
         name="status">
  <label for="status">
    <div class="status-switch"
         data-unchecked="Off"
         data-checked="On">
    </div>
  </label>
</div>
```

Hopefully, the markup speaks for itself but here are some points if you're not sure what's going on above:

- We wrap everything in a `div` which we'll use to set an overall height and width for our toggle
- There is a checkbox `input` which we'll hide with our CSS styles, the main content will be inside the `label` element (which itself has a further `div` inside it)
- Specifying the `input`'s id inside the `for` attribute of the `label` element allows the user to check/uncheck the checkbox `input` element by clicking the `label` element
- The `div` inside the `label` has two data attributes (`data-unchecked` and `data-checked`) which will form the text for the two states of our slide toggle

Initially, I had tried using two radio button inputs for the slide toggle with each representing either an on or off state.

However, I only got so far with this approach before the styling became a nightmare so I decided to change the radios for a single checkbox which made everything much easier.

As the slide toggle can only have two states; either 'checked' or 'unchecked', it makes more sense to use a checkbox.

## The SCSS

The styling of the slide toggle could be done in plain CSS however, using SCSS makes working with the hierarchy of elements easier.

There's a reasonable amount so let's split it up into sections.

### The container element

```scss
.custom-checkbox {
  width: 260px;
  height: 60px;

  input#status {
    display: none;
```

The first thing we'll do is just set some dimensions for the slide toggle.  Changing the `width` and `height` values will scale all of the other elements to fit.

We'll also hide the input element so we don't see the default HTML checkbox `input` element leaving all of the customisation to the content inside the `label`.

### The label and inner div content

```scss
    + label {
      height: 100%;
      width: 100%;
      > .status-switch {
        cursor: pointer;
        width: 100%;
        height: 100%;
        position: relative;
        background-color: grey;
        color: white;
        transition: all 0.5s ease;
        padding: 3px;
        border-radius: 3px;
```

Using the adjacent sibling selector (the `+` symbol) we can select the `label` which is next to the `input` element.  

After ensuring the `height` and `width` is `100%` we target the inner `div` of the `label`, with the class of `.status-switch`.

This will be the 'unchecked', 'inactive' or 'off' state of the slide toggle.

Some key things here are to ensure the `position` is set to `relative` as we'll be absolutely positioning elements inside this and the `padding` value set will also be used to adjust the inner height and width of the 'slide' button too.

You can choose a `background-color` for the unchecked state here.

### The before and after pseudo-elements

```scss
        &:before,
        &:after {
          border-radius: 2px;
          height: calc(100% - 6px);
          width: calc(50% - 3px);
          display: flex;
          align-items: center;
          position: absolute;
          justify-content: center;
          transition: all 0.3s ease;
        }
```

The above is setting some common styles for the `before` and `after` pseudo-elements which will display the **On** / **Off** elements.

There's some basic flex styling to position the text content in the centre of each of the elements and we're using the value that we set in for `padding` in the previous step to reduce the `width` and `height` slightly so that there is a little bit of a border around the slide toggle button.

If you were to view the slide toggle element now, it would look a bit like this:

![Incomplete toggle widget](https://dev-to-uploads.s3.amazonaws.com/i/0bfbbeut3q73vzgpf0u8.jpg)

That's because of the `before` and `after` elements are not visible yet, and they have no content.

So let's add some separate styles to these to position them correctly.

### Positioning before and after

```scss
        &:before {
          background-color: white;
          color: black;
          box-shadow: 0 0 4px 4px rgba(#000, 0.2);
          left: 3px;
          z-index: 10;
          content: attr(data-unchecked);
        }
        
        &:after {
          right: 0;
          content: attr(data-checked);
        }
```

We'll make the `before` element have a white background which will form the 'button' like part of the slide toggle and set it's `left` property to `3px` which will again, preserve the border around the toggle.  

The `after` element will be positioned on the `right` hand-side of the containing element. 

Both of the elements will get their content set to the respective `data-attribute` we set in the initial markup.

Our slide toggle should look like this now:

![Inactive state](https://dev-to-uploads.s3.amazonaws.com/i/7fn3umpuwcwmhdqpq3yy.jpg)

### Updating the checked state

```scss
    &:checked + label > .status-switch {
      background-color: green;
 
      &:after {
        left: 0;
        content: attr(data-unchecked);
      }
 
      &:before {
        color: green;
        left: 50%;
        content: attr(data-checked);
      }
```

To finish off our slide toggle, we'll simply target the `:checked` state of the `input` element and drill down to the `.status-switch` class which is assigned to the inner `div` of the `label`.

Inside the selector, we can set a new `background-color` and then essentially just 'swap over' the `before` and `after` pseudo-elements.

We do this by updating their `left` positions and also updating their `content` properties.
 
Because of the `transition` properties that have been set up, the `before` element appears to glide into position and the `background-color` of the `.status-switch` fades in and out.

![Checked state](https://dev-to-uploads.s3.amazonaws.com/i/tn2epsly4ryb44lf78j8.jpg)

## Conclusion

There's a lot you can do to create your own custom inputs, buttons, toggles and sliders with just some CSS.

The aim of this is to make the code a little bit more accessible, removing the need for JavaScript.

I was surprised how relatively easy it was to create the styling for the slide toggle, once I had got to grips with the hierarchy of the elements and what should happen when the `input` is in a checked or unchecked status.

I've only made use of Sass nesting features in the completed code, just to try and make it as readable as possible but the example could be improved to make use of other Sass features such as variables, mixins etc. to make a more reusable and customisable slide toggle component.

Full code and demo is on Codepen: https://codepen.io/codebubb/pen/OJXRGyN

*Follow me on [Twitter (@codebubb)](https://twitter.com/codebubb) for more articles and videos.* 

*Have you got your own custom checkbox or slide toggle examples? Let me know in the comments below!*