3 State Switches are not tough - Ultimate guide to CSS Switches using CSS only
Tags: html, css, webdev, ui
Published: 2023-09-20 17:36:18

Hi there, when it comes to switches most people look for modern libraries but building core is very important.
Creating switches are very easy. Today I will be sharing the guide to create CSS switches.

**We'll be seeing -**

1. 2 state switches
2. 2 state switches with custom icons.
3. 3 state switches


**2 State Switches**

For creating switches you need a way to figure out the active states. If you are using JavaScript then there are lot of ways you can do it by dynamically adding classes on click. When it comes to css we have one very popular way which is by using the input type checkbox. Which changes it's state and you can target that state easily with CSS only. 

_Check the below html structure -_


```
<div class="switch1-container">
      <h5> Simple two state switch</h5>
      <div class="switch1">
        <input type="checkbox" id="switch1-input"/>
        <label for="switch1-input"></label>
        <span class="switch-bg"></switch>
      </div>
</div>
```
_Note - Here in this html structure for giving the bg to the switch I experimented with a separate span and used absolute positioning. You can achieve the similar behavior using the ::before pseudo element._

Main thing to know here is that for getting the on status for the switch we can use the checked state of the input element.
You can easily get it on input using `:checked` pseudo class.

For styling the CSS switch button we have to make use of the input label. The good thing is when you click on the label then input states gets toggled. So hide the input and design the label with good looking round circle.

Once you designed the b and the circle now for moving the circle with the bg to give feel like a switch. Make use of `transform` property. Use `translateX` to move the circle and add `transition` on `transform` to make it smooth. 🙃

That's it 
Your switch is ready. 🫡


Checkout the Css below to understand what we discussed. 
Practical knowledge is more important you know.😎

```
*{
  margin:0;
  padding:0;
}
*,*::before,*::after{
  box-sizing:border-box;
}

:root{
    --clr-primary: #d9d9d9;
  --clr-secondary:#fafafa;
  --clr-clear:#ffffff;
  --clr-grey: #6d6d6d;
  --clr-dark:#1e1e1e;
  --ff-base:'Inter', sans-serif;
  --fw-regular: 400;
  --fs-200:0.875rem;
  --fs-300:1rem;
  --fs-400:1.125rem;
  --fs-500:1.375rem;
  --fs-600:1.75rem;
  --fs-700:3.25rem;
    
}
html{
  color-scheme: dark;
}
body{
  font-family: var(--ff-base);
  font-size: var(--fs-300);
  font-weight: var(--fw-regular);
}

.container{
  max-width:80%;
  margin: auto;
  height:100dvh;
  display:grid;
  grid-template-columns:repeat(auto-fit,minmax(200px,1fr));
/*   justify-content:center; */
  padding: 4rem;
}

input{
  display:none;
  cursor: pointer;
}
label{
  cursor: pointer;
}

.switch1-container h5{
  margin-bottom: 1rem;
}
.switch1{
  position:relative;
  border-radius: 30px;
  width:6rem;
  height:2.5rem;
  background: #ccc;
  display:flex;
  align-items:center;
  transition: .3s background-color ease;
}
.switch-bg{
  background-color: #eceeef;
  position:absolute;
  top:4px;
  left:5px;
  width:90%;
  height:80%;
  border-radius:30px;
  transition: background-color .2s ease-out;
}


.switch1 label {
  background-color:white;
  border: 1px solid #bbb;
  display:inline-block;
  width:24px;
  height:24px;
  border-radius:50%;
  display:inline-block;
  vertical-align:bottom;
  margin:5px 8px;
  z-index:2;
  transition: transform .3s ease;
  
}
.switch1 input:checked + label{
  transform: translateX(56px);
}
.switch1 input:checked + label + .switch-bg {
  background-color: dodgerblue;
}

```
 
**2 State Switches with Custom Icon**
For adding the icon to your switches is very easy you can use various way of doing that. **I picked it using css only even no extra Html.** I used fontawesome for directly using icons in the stylesheet. The one I created is useful when you want to toggle between dark and night mode. 😎

Just add this to your styles sheet and in Html file.

**Html**
```
<div class="switch2-container">
      <h5> Simple two state siwtch with custom icon</h5>
      <div class="switch2">
        <input type="checkbox" id="switch2-input"/>
        <label for="switch2-input"></label>
        <span class="switch-bg"></switch>
      </div>
    </div>
```
**Css**
```

.switch2-container h5{
  margin-bottom: 1rem;
}
.switch2{
  position:relative;
  border-radius: 30px;
  width:6rem;
  height:2.5rem;
  background: #ccc;
  display:flex;
  align-items:center;
  transition: .3s background-color ease;
}
.switch2-bg{
  background-color: #eceeef;
  position:absolute;
  top:4px;
  left:5px;
  width:90%;
  height:80%;
  border-radius:30px;
  transition: background-color .2s ease-out;
}


.switch2 label {
/*   background-color:white; */
/*   border: 1px solid #bbb; */
  display:inline-block;
  width:24px;
  height:24px;
  border-radius:50%;
  display:inline-block;
  vertical-align:bottom;
  margin:3px 8px 0px;
  z-index:2;
  transition: transform .3s ease;
  
}
.switch2 input:checked + label{
  transform: translateX(56px);
}
.switch2 input:checked + label + .switch-bg {
  background-color: dodgerblue;
}

.switch2 label::before{
  font: var(--fa-font-solid);
  content: "\f185";
  color: gold;
  font-size: 1rem;
  border: 1px solid #ccc;
  border-radius: 50%;
  padding: 4px;
}
.switch2 input:checked + label::before{
  content: "\f186";
  color:gold;
  border: none;
}
.switch2 input:checked + label + .switch-bg{
  background: black;
}
```

**_Now the third one is the powerful one._**
**_3 State Switches_**

![The godfather](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/dfknq5keo1r2xd7manq7.gif)

For this one I use input type `radios` because of one good behavior that when you have radio group and each has same name attribute then if you select one then the other one will be de-selected automatically.

I created my html structure like this.

```
 <div class="switch3-container">
      <h5> Simple three state siwtch</h5>
      <div class="switch3">
        <input type="radio" id="switch3-radio1" name="radio"/>
        <label for="switch3-radio1">FrontEnd</label>
        
        <input type="radio" id="switch3-radio2" name="radio"/>
        <label for="switch3-radio2">BackEnd</label>
        
        <input type="radio" id="switch3-radio3" name="radio"/>
        <label for="switch3-radio3">FullStack</label>

      </div>
    </div>

``` 
For this I have used three html input elements with type `radio`.
Each has it's own label for showing the text.
For highlighting the selected option, I have use the `::before` pseudo element on `.switch3`.

_Thanks to new `:has` selector of css which made this more easier and cleaner html as well._

Check the css below - 

```
.switch3-container h5{
  margin-bottom: .7rem;
}
.switch3
{
  
  position: relative;
  height:50px;
  display:flex;
  justify-content:space-around;
}
.switch3 label{
  padding: 1rem;
  z-index:1;
}
.switch3::before{
  content: '';
  position: absolute;
  left:0;
  width: 34%;
  height: 100%;
  background: #14142a;
  border: 1px solid #fff;
  border-radius: 12px;
  opacity: .5;
  transition: .5s left ease;
}

.switch3:has(#switch3-radio1:checked)::before{
  left: 0%;
}
.switch3:has(#switch3-radio2:checked)::before{
  left: 33%;
}
.switch3:has(#switch3-radio3:checked)::before{
  left: 66%;
}
```
That's how all three looks like. 

![Toggle switches using css only with three state switch](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/r0pn066te2zwqmuq46j1.png)


Experiment with my codepen - [Codepen Live](https://codepen.io/Navdeep-Mishra-the-solid/pen/abPVEEz)

{% codepen https://codepen.io/Navdeep-Mishra-the-solid/pen/abPVEEz %}

Similarly we can create 4 state switch as well. 
If you have any doubts or questions, feel free to discuss in the comments. 
Any better approach? let's discuss. 😎

Thanks for reading.
Please follow for more Webdev content. 😉

Navdeep M.