How to Create a Custom Toggle Switch Component in Vue.js
Custom toggle switches are a pain to code from scratch. So many lines for such a simple UI widget! In this quick tutorial, we will learn how to build a fully encapsulated toggle switch component in Vue.js. The component we’re building is used currently on boot.dev’s login page. Go take a look to see a live demo.
The HTML Template
<template>
<div>
<span
class="toggle-wrapper"
role="checkbox"
:aria-checked="value.toString()"
tabindex="0"
@click="toggle"
@keydown.space.prevent="toggle"
>
<span class="toggle-background" :class="backgroundStyles" />
<span class="toggle-indicator" :style="indicatorStyles" />
</span>
</div>
</template>
The toggle-wrapper is what it sounds like, the parent div for our component. The toggle-background will be the pill-shaped oval and the toggle-indicator is the circle that we will animate to move back and forth.
The JavaScript
export default {
props: {
value: {
type: Boolean,
required: true,
},
},
computed: {
backgroundStyles() {
return {
"gold-mid": this.value,
"gray-lighter": !this.value,
};
},
indicatorStyles() {
return { transform: this.value ? "translateX(14px)" : "translateX(0)" };
},
},
methods: {
toggle() {
this.$emit("input", !this.value);
},
},
};
We have setup the component such that the user of the component can use the v-model attribute to get/set the current state of the switch. We have setup the backgroundStyles and indicatorStyles to dynamically change some CSS for us as the state updates.
The CSS
.gold-mid {
background-color: #666666;
}
.gray-lighter {
background-color: #c2c2c2;
}
.toggle-wrapper {
display: inline-block;
position: relative;
cursor: pointer;
width: 32px;
height: 18px;
border-radius: 9999px;
}
.toggle-wrapper:focus {
outline: 0;
}
.toggle-background {
display: inline-block;
border-radius: 9999px;
height: 100%;
width: 100%;
box-shadow: inset 0 2px 4px rgba(0, 0, 0, 0.1);
transition: background-color 0.4s ease;
}
.toggle-indicator {
position: absolute;
height: 14px;
width: 14px;
left: 2px;
bottom: 2px;
background-color: #ffffff;
border-radius: 9999px;
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
transition: transform 0.4s ease;
}
The only particularly interesting thing going on here is the fade in/out of the gold color on the background and the movement of the toggle-indicator. Both of these are accomplished with the transition CSS attribute.
Hopefully this saves you some time building out one of the more common UI/UX components in Vue! It’s the small things like this that give applications the professional flourish that keep users engaged. Be sure to reach out to me directly with feedback or questions!
Related Articles
Vue History Mode - Support Legacy Hash URLs
Jul 15, 2020 by Lane Wagner - Boot.dev co-founder and backend engineer
When we first launched the boot.dev’s single-page-app, we were using Vue Router’s default hash routing. Hash routing looks ugly to the end-user, and when you want to be able to share parts of your app via direct link those hashes can get really annoying.
How to Rerender a Vue Route When Path Parameters Change
Jul 07, 2020 by Lane Wagner - Boot.dev co-founder and backend engineer
In single-page apps that use the Vue Router, it’s common to create a path parameter that changes the behavior of a route. Often a problem occurs however when a user alters the path manually in the address bar. Manually changing the URL does not rerender the view! This can cause unexpected behavior because mounted() hooks don’t fire and nested components don’t reload.
Simple Setup - Vue Linting in VS Code
Jun 17, 2020 by Lane Wagner - Boot.dev co-founder and backend engineer
I’m a gopher by nature, so I expect consistent styling and linting in my codebases. More importantly, I don’t like to think about styling. I like to type haphazardly and then have my editor apply styles automatically on save (ctrl+s, cmd+s). If you are the same way, hopefully, this will help you in your next Vue.js project.