No Time Dad

A blog about web development written by a busy dad

Easy Toggle Button Example with Plain CSS

Intro

I was working on building an sample pricing page (post coming soon) based on some examples I saw on the TailwindUI components page and I noticed one of the components had a really slick looking toggle button for switching between monthly and yearly billing. You can’t actually see how the toggle on their site behaves because it is a paid component, but I took an educated guess and I think I came up with a pretty nice variation of the toggle button in plain css with a tiny bit of JavaScript.

Getting Started

We’ll assume that the toggle button will be part of a larger page and probably have its own container element, so we’ll focus on the toggle button itself here. I won’t make any assumptions about the element container here, leaving that part up to you.

For our example, our toggle button will just toggle “On” and “Off” but you can obviously toggle whatever text you’d like. The text itself is irrelevant to the functionality of the toggle button. I used the css class name header__on_off because for my use case the toggle button will end up in a header container.

We want the background to sort of dissappear behind the buttons, so the header__on_off container div will share the same border-radius as the buttons. We’ll create a custom property for this so it can be changed easily for all of the elements as needed.

For the buttons themselves, I like big buttons so we’ll add a decent amount of padding with the header__on_off_button class. We’ll also use border-radius with the --shared-radius custom css property we created.

Here is the html and css that we’ll start with. Below that you’ll find an example of what the toggle button looks like so far.

:root {
  --shared-radius: 0.5rem
}

.header__on_off {
  display: inline-block;
  background-color: lightgrey;
  border-radius: var(--shared-radius);
}

.header__on_off_button {
  border-radius: var(--shared-radius);
  padding: 1rem 3rem;
}
<div class="header__on_off">
  <button class="header__on_off_button">On</button>
  <button class="header__on_off_button">Off</button>
</div>

Creating the Toggle

Right now there is no indication that our element is a toggle. It just looks like two big buttons next to each other. We’ll want to start out with one of the buttons “blending” into the background so it appears that the other button is the selected button. For the deselected button to blend in to the background, we’ll change the background-color of the button to match the background-color of the parent div, and we’ll remove the default border on the button.

For the selected button, we’ll change the background-color to white and add a box-shadow. This will really make the button stand-out on the page and it should be clear to the user which button is the selected one. The updated CSS, HTML, and example element are below. Note that because we are using background-color: lightgrey in two places I created a custom property for it.

:root {
  --shared-radius: 0.5rem;
  --shared-bg-color: lightgrey;
}

.header__on_off {
  display: inline-block;
  background-color: var(--shared-bg-color);
  border-radius: var(--shared-radius);
}

.header__on_off_button {
  border-radius: var(--shared-radius);
  padding: 1rem 3rem;
}

.header__on_off_button__selected {
  background-color: white;
  box-shadow: 0 4px 8px 0 rgba(0, 0, 0, 0.1);
}

.header__on_off_button__deselected {
  border: none;
  background-color: var(--shared-bg-color);
}
<div class="header__on_off">
  <button class="header__on_off_button header__on_off_button__selected">On</button>
  <button class="header__on_off_button header__on_off_button__deselected">Off</button>
</div>

Adding the Toggle Action

The toggle button element looks great now, but it doesn’t actually do anything yet. When either button is clicked on we need them both to switch to the opposite class. So a button with the class header__on_off_button__selected should switch to header__on_off_button__deselected and vice versa when clicked.

We’ll add a JavaScript function that will use a toggle method to change the classes on each button. The toggle method is supported by most browsers except some versions of IE. We are going to use document.getElementById in our JavaScript function, so we’ll be added id attributes to our button elements too.

Our CSS will remain the same, but we are going to add an onclick handler to each button, as well as a function to our <script> tag in our html file.

<div class="header__on_off">
  <button onclick="toggleSelected()" class="header__on_off_button header__on_off_button__selected">On</button>
  <button onclick="toggleSelected()" class="header__on_off_button header__on_off_button__deselected">Off</button>
</div>

...
<script>
function toggleSelected() {
  const selectedClass = "header__on_off_button__selected";
  const deselectedClass = "header__on_off_button__deselected";
  document.getElementById('on-button').classList.toggle(deselectedClass);
  document.getElementById('off-button').classList.toggle(selectedClass);
}
</script>

Final Product and Thoughts

So there you have it. A pretty simple toggle button with what I think is a small amount of css, js, and html. The toggle doesn’t really do much, but it can easily be extended to show and hide other elements on the page or do other fun things on your page. I guess you could also add some transition effects or something similar, but I personally like to keep things fast. I think it is a better user experience.

Below are the final versions of the css and html, as well as the final toggle itself (same as previous section).

:root {
  --shared-radius: 0.5rem;
  --shared-bg-color: lightgrey;
}

.header__on_off {
  display: inline-block;
  background-color: var(--shared-bg-color);
  border-radius: var(--shared-radius);
}

.header__on_off_button {
  border-radius: var(--shared-radius);
  padding: 1rem 3rem;
}

.header__on_off_button__selected {
  background-color: white;
  box-shadow: 0 4px 8px 0 rgba(0, 0, 0, 0.1);
}

.header__on_off_button__deselected {
  border: none;
  background-color: var(--shared-bg-color);
}
<div class="header__on_off">
  <button onclick="toggleSelected()" class="header__on_off_button header__on_off_button__selected">On</button>
  <button onclick="toggleSelected()" class="header__on_off_button header__on_off_button__deselected">Off</button>
</div>

...
<script>
function toggleSelected() {
  const selectedClass = "header__on_off_button__selected";
  const deselectedClass = "header__on_off_button__deselected";
  document.getElementById('on-button').classList.toggle(deselectedClass);
  document.getElementById('off-button').classList.toggle(selectedClass);
}
</script>