How to create a pure CSS toggle button…?

Balint Hudecz
2 min readNov 30, 2021

My general experience with programming is that you learn new skills and techniques on the job, which can be often painful as one can easily spend hours figuring out stuff or browsing tutorials…

For an application that I am developing, I wanted a simple, pure CSS toggle switch with the following parameters:

  • have text on the button not next to it
  • be symmetrical on both sides regardless of text
  • be reusable in any setting, avoid having to set width based on text length

It turned out that there aren’t so many great tutorials out there so here is what I came up with (codepen link):

HTML

<input type=”checkbox” id=”toggle” class=”toggleCheckbox” />
<label for=”toggle” class=’toggleContainer’>
<div>Looooong</div>
<div>Short</div>
</label>

CSS

First, let’s hide the original checkbox:

.toggleCheckbox {
display: none;
}

Format the label:

.toggleContainer {
position: relative;
display: grid;
grid-template-columns: repeat(2, 1fr);
width: fit-content;
border: 3px solid #343434;
border-radius: 20px;
background: #343434;
font-weight: bold;
color: #343434;
cursor: pointer;
}

Part of the magic happens here. We are creating a two-column grid for the labels and we fit the width to the content. As we defined the same fraction size for the two columns, we will get equal width on both sides regardless of content. Just to note that for the position if you use absolute, you don’t need to set width: fit-content; — it really depends on how you want to use it.

To create the toggle:

.toggleContainer::before {
content: '';
position: absolute;
width: 50%;
height: 100%;
left: 0%;
border-radius:20px;
background: white;
transition: all 0.3s;
}

Here instead of fixing the width and height, we are using percentages to always have the button stretched to half of the width of the whole container.

To format the text containers and bring them forward:

.toggleContainer div {
padding: 6px;
text-align: center;
z-index: 1;
}

To move the button:

.toggleCheckbox:checked + .toggleContainer::before {
left: 50%;
}

And finally to add some text colour changes:

.toggleCheckbox:checked + .toggleContainer div:first-child{
color: white;
transition: color 0.3s;
}
.toggleCheckbox:checked + .toggleContainer div:last-child{
color: #343434;
transition: color 0.3s;
}
.toggleCheckbox + .toggleContainer div:first-child{
color: #343434;
transition: color 0.3s;
}
.toggleCheckbox + .toggleContainer div:last-child{
color: white;
transition: color 0.3s;
}

Please shout out if you plan to use it in your project (I am just interested)!

--

--