DEV Community

Cover image for Creating a CSS-Only Toggle Switch
Dom (dcode)
Dom (dcode)

Posted on


Creating a CSS-Only Toggle Switch

In today's post I wanted to share a technique which I use to create pure CSS toggle switches. This is very easy to implement, and is a stylish replacement to regular checkbox HTML inputs.

Video Tutorial

If you prefer this tutorial in the form of a video, check it out on my YouTube channel, dcode:

What makes this CSS-only?

In order to make this solution CSS-only we're going to be using traditional <input type="checkbox"> elements but they're going to be hidden through CSS.

Our CSS will then make use of the :checked pseudo-class and the general sibling combinator (~) to dynamically apply either a "on" or "off" style to our switch.

Writing the HTML

Let's start with the HTML. For this, we're going to be wrapping everything inside a <label> element. This will allow us to click anywhere within the wrapper and it will toggle the state of our hidden checkbox.

<label class="toggle" for="myToggle">
    <input class="toggle__input" name="" type="checkbox" id="myToggle">
    <div class="toggle__fill"></div>
Enter fullscreen mode Exit fullscreen mode

Ensure the for attribute of the <label> matches up with the id of the input field, as shown above.

As you can see, we have the regular input field and we have the fill element. The fill element represents everything visible, including the circle slider itself.

Moving onto the CSS

The first thing to do is to define a few variables to control the dimensions of the toggle switch - this allows us to change the "width" in one place, and everything will be sized based on this number.

While we're here, let's display the .toggle as inline-block so it flows easier and ensure the correct cursor is displayed:

.toggle {
    --width: 40px;
    --height: calc(var(--width) / 2);
    --border-radius: calc(var(--height) / 2);

    display: inline-block;
    cursor: pointer;
Enter fullscreen mode Exit fullscreen mode

Next, we can hide the actual input field:

.toggle__input {
    display: none;
Enter fullscreen mode Exit fullscreen mode

Styling the switch fill

Now we're done with the wrapper, let's move onto the switch itself. For this, we can use the variables defined above and apply some basic styles:

.toggle__fill {
    position: relative;
    width: var(--width);
    height: var(--height);
    border-radius: var(--border-radius);
    background: #dddddd;
    transition: background 0.2s;
Enter fullscreen mode Exit fullscreen mode

Notice the transition - this is in place to ensure we get a smooth animation as the background color changes from grey to green (as we'll see shortly).

Styling the switch circle (or slider)

For the circle, we can make use of the ::after pseudo-element in CSS - let's create it like this:

.toggle__fill::after {
    content: "";
    position: absolute;
    top: 0;
    left: 0;
    height: var(--height);
    width: var(--height);
    background: #ffffff;
    box-shadow: 0 0 10px rgba(0, 0, 0, 0.25);
    border-radius: var(--border-radius);
    transition: transform 0.2s;
Enter fullscreen mode Exit fullscreen mode

Most of these are self-explanatory but as shown we're using position: absolute to position the circle in the top left corner before setting a width and height via defined variables.

Getting the toggle to work

As mentioned earlier, the toggle is going to work by using the :checked pseudo-class and the general sibling combinator.

Let's define a couple of rules below, which will be activated when the <input> is checked:

.toggle__input:checked ~ .toggle__fill {
    background: #009578;

.toggle__input:checked ~ .toggle__fill::after {
    transform: translateX(var(--height));
Enter fullscreen mode Exit fullscreen mode

As we can see, translateX is used here to push the circle to the right side. In order for this to line up, it must be pushed the same amount as the height of the container.

And that's it! The toggle switch should be fully functional. If anyone else has suggestions for improvement or different styles, please leave them in the replies below šŸ˜

Top comments (2)

djdingle247 profile image

I have a question about the JavaScript rabble sort you did on YouTube. I was wondering if you could help. Iā€™m following you on Twitter @djdingle247 . Can you reach out there?

The AI Brief

AI generated git commit messages

Minimize the struggle of remembering what you just coded. AI-generated commits make it easier to manage projects and keep track of changes. The Nutlope/aicommits project demonstrates how AI can improve commit messages.

I open sourced an AI that creates any UI in seconds

Make AI-generated user interfaces a breeze. This open-source project harnesses the power of generative AI technologies like chatGPT to create versatile, quick, and intuitive UI components.

Use AI to commit like a PRO in 1 second

Upgrade your commit message game with AI. Boost your productivity by using ChatGPT to generate commit messages and avoid context switching. OpenCommit is an open-source library that helps you achieve this easily.

Build your own ChatGPT starter kit

Train AI models on custom data for improved domain-specific knowledge. Combine the power of WebView technologies and this starter kit to train your ChatGPT model on specific websites, allowing for better-optimized outcomes.