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 -
- 2 state switches
- 2 state switches with custom icons.
- 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
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.
Experiment with my codepen - Codepen Live
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.
Top comments (10)
Using DEV.to's embed functionality, you can attach examples that actually run on sites like CodePen.
I had only thought about syntax highlighting.
triple-backtick language-name
code
triple backtick
Wasn't aware of embedding before.
Ohh! I didn't knew this before. 😉 Thanks for sharing. 💓
Nice one. I'd add styles for disabled state yet.
Yes, actually I literally forgot that 😂😅
I tried your sample in Firefox and couldn't get the tri-state switch to work. Perhaps there's some CSS feature that doesn't exist there yet?
Yes, I also noticed that. It's due to the
:has
not fully implemented in firefox.See - connect.mozilla.org/t5/ideas/when-...
I'll provide alternate solution without
:has
selector.@phillip27 I have added a solution for without
:has
which works with firefox too.This is really cool. Thanks!
good afternoon, thank you very much for your help! Hello from St.Petersburg)