Create a custom toggle component in Vue.js. 🎛
Vaibhav Khulbe

Vaibhav Khulbe @vaibhavkhulbe

About: ✦ Independent web developer/designer/blogger ✦ Framer Expert & Partner | Advocate at 10x Designers ✦ Hire me on Contra👇

Location:
India
Joined:
Oct 13, 2018

Create a custom toggle component in Vue.js. 🎛

Publish Date: Sep 11 '20
35 13

Making a custom component shouldn't be a mess. And what's better than using Vue's native features to create one! So let's do it. Let's make a custom or manual or whatever-you-want-to-call-it component from scratch!

Switch GIF

We have some switches to manufacture now...

What are we making❓

This:

Vue Custom Toggle Demo

I know, I know, it looks terrible, but let's just focus on the implementation :)

Kickstart the custom toggle 🦵

Step 1️⃣: The setup

Fire open your terminal to create a new Vue project:



vue create custom-toggle


Enter fullscreen mode Exit fullscreen mode

If you don't have the Vue CLI installed in your machine, you can find the installation steps on their official website.

Remove all other files and create the new ones just like what you see in the following project structure:



custom-toggle
│
└───public
│   │   index.html
└───src
│   │
│   └───components
│       │   Toggle.vue
│   │   App.vue
│   │   main.js
└───package.json


Enter fullscreen mode Exit fullscreen mode

As you see, our custom component will live in ./components/Toggle.vue file.

Step 2️⃣: Code App.vue

This is our entry point component. As you see, we have two things to display. First, is the toggle component itself and the text below that tells us the state of the toggle, whether it's turned on or off.

Under the <script>, use the data() method to return the default state of the component. Make it a boolean, so it can either be true or false. As I want to display the toggle to be "ON", hence I made it true by default.

Next, register the component which we'll make in the next step using the components option. Here's it's named appToggle. Make sure you import it correctly. Then register it on to the template making sure to use Vue's v-model directive to make two-way data-binding possible. Pass in the dataToggle property so that it can check the state dynamically.

As for the text below, we simply have a <p> tag which uses template syntax's string interpolation.

App.vue:



<template>
  <div>
    <app-toggle v-model="dataToggle"></app-toggle>
    <p style="text-align: center">Toggle: {{ dataToggle }}</p>
  </div>
</template>

<script>
import Toggle from "./components/Toggle";

export default {
  data() {
    return {
      dataToggle: true
    };
  },
  components: {
    appToggle: Toggle
  }
};
</script>


Enter fullscreen mode Exit fullscreen mode

Step 3️⃣: Code the toggle

Open up Toggle.vue file. Here we just need the two div elements (as we're making a custom element) for the "ON" and "OFF" states. These will be wrapped in a parent toggleContainer div.

In order to style them as we want, just give each an id of on and off respectively. The entire CSS styles applied are basic, so here's the styling you need:



.toggleContainer {
  margin-top: 40%;
  display: flex;
  justify-content: center;
  align-items: center;
}

#on,
#off {
  width: 40px;
  height: 20px;
  border-radius: 20px;
  background-color: lightgray;
  padding: 2px;
  text-align: center;
  margin: 10px -5px;
  cursor: pointer;
}

#on:hover,
#on.active {
  background-color: lightgreen;
}

#off:hover,
#off.active {
  background-color: lightcoral;
}


Enter fullscreen mode Exit fullscreen mode

Now comes the best part. In the script we first need to define the props object in order to pass data from App.vue to Toggle.vue. We only need the value of the parent component. This is because the prop we pass will determine which toggle is clicked, the "ON" or the "OFF". It's also useful to add dynamic CSS property changes.

As you can see from the above CSS code we have different background-color and active/hover pseudo-classes for both #on and #off. These are activated from the value prop. But for this thing to work, we need to use Vue's class/style binding feature with v-bind.

To implement this, we can either use v-bind:class or the shorthand syntax i.e. just :class. Here, just make the active object to be value (similar to dataToggle: true) in case of "ON" and the opposite active: !value (similar to dataToggle: false) in "OFF".

But we didn't implement what to do when we actually click on each of these toggle options! Ready for the last step? Here we go!

Add the @click click listener to the two children of the container. Pass on a new method switched() to it as shown:



<template>
  <div class="toggleContainer">
    <div id="on" @click="switched(true)" 
    :class="{active: value}">ON</div>
    <div id="off" @click="switched(false)" 
    :class="{active: !value}">OFF</div>
  </div>
</template>


Enter fullscreen mode Exit fullscreen mode

For the body of this method, we need to emit the new custom event on mouse click. Vue provides us with the $emit syntax for this functionality. The first parameter is the type of custom event, in our case, it's an input and the second parameter is isOn.

Toggle.vue:



<template>
  <div class="toggleContainer">
    <div id="on" @click="switched(true)" 
    :class="{active: value}">ON</div>
    <div id="off" @click="switched(false)" 
    :class="{active: !value}">OFF</div>
  </div>
</template>

<script>
export default {
  props: ["value"],
  methods: {
    switched(isOn) {
      this.$emit("input", isOn);
    }
  }
};
</script>

<style scoped>
.toggleContainer {
  margin-top: 40%;
  display: flex;
  justify-content: center;
  align-items: center;
}

#on,
#off {
  width: 40px;
  height: 20px;
  border-radius: 20px;
  background-color: lightgray;
  padding: 2px;
  text-align: center;
  margin: 10px -5px;
  cursor: pointer;
}

#on:hover,
#on.active {
  background-color: lightgreen;
}

#off:hover,
#off.active {
  background-color: lightcoral;
}
</style>


Enter fullscreen mode Exit fullscreen mode

And you've done it! 🥳 See how the text below the toggle changes from "true" to "false" and back!

You just made a custom toggle with Vue.js in a matter of minutes, that's what I like about this framework. It's really quick to make such components.

If you're stuck somewhere in the code or just want to interact with the output, I've embedded the CodeSandbox project below:


Where to next? 🤔

Brush up your custom component making skills with the following resources:


Thanks for reading, I appreciate it! Have a good day. (✿◕‿◕✿)


Can you spot the difference? 😝

Image source: https://t.co/rhSnxZLNJa#DevHumour #WFH #RemoteWorking pic.twitter.com/MRmH1aKB9u

— Microsoft Developer UK (@msdevUK) September 10, 2020

📫 Subscribe to my weekly developer newsletter 📫

PS: From this year, I've decided to write here on DEV Community. Previously, I wrote on Medium. If anyone wants to take a look at my articles, here's my Medium profile.

Comments 13 total

  • Pascal Schilp
    Pascal SchilpSep 11, 2020

    This switch is not accessible, and not usable with keyboard navigation. You should really consider reading up on how to make custom components like these accessible before sharing wrong information.

    Here are some good resources:
    w3.org/TR/wai-aria-1.1/#switch
    scottaohara.github.io/aria-switch-...
    erikkroes.nl/blog/accessible-html-...

    • Jordan Kicklighter
      Jordan KicklighterSep 11, 2020

      And I would add to this: styling based on an ID is not considered good practice, nor is using an ID like "on" or "off" in a component that will be reused. According to spec, ID should be unique on the whole page.

      • Vaibhav Khulbe
        Vaibhav KhulbeSep 11, 2020

        Hey Jordan, I agree, but this is not a full-fledged application. It's just a demo of how to start writing a custom component.

        Also, please provide some external resources to back off your statements, this would help others to understand more.

        • Jordan Kicklighter
          Jordan KicklighterSep 11, 2020

          Sure, I recognize that it's just a demo and there may be some merit in just getting things out there for people to see. That said, it's a demo targeted toward a fairly beginner level audience. These subtle behaviors are often not addressed in anything new programmers will learn, and I feel that it's a disservice to allow poor programming habits to show up in an example meant for teaching people. Arguably, you should never be okay with poor practices in any code you write, if they could be easily avoidable; but this problem is even worse when you have an audience that may have never seen any of the techniques and will learn bad habits while trying to understand everything going on in the example.

          Short version: it being a demo is precisely the reason you should follow best practices.

          Edit: first sentence in this doc developer.mozilla.org/en-US/docs/W...

          • Pascal Schilp
            Pascal SchilpSep 11, 2020

            Exactly — this may not be a full-fledged application, but if a new dev comes here, reads this, recreates this toggle with non-unique IDs, and reuse a bunch of that component on their page/app, they will end up with multiple non-unique IDs on their page. Its a bad practice, and a poor example for new developers.

    • Vaibhav Khulbe
      Vaibhav KhulbeSep 11, 2020

      Hi Pascal! You're right accessibility is highly important! But as you can see, this article is just focussed on "how to make a custom component". It's just about coding the component, adding other things like accessibility can surely be done. This was just to get a demo or a quick-start. :)

      Also, thanks for adding the resources, they will definitely help!

      • Pascal Schilp
        Pascal SchilpSep 11, 2020

        Making it not accessible is not how you make a component. Youve just excluded a lot of people from being able to use the component, and even worse, youve taught a bunch of other people the wrong way to make a component.

        If its not accessible, its not finished. “Adding” accessibility is not a bonus; its a requirement

  • Vaibhav Khulbe
    Vaibhav KhulbeSep 11, 2020

    Thanks Ayushi! Your comment is highly appreciated. 😊

  • ビノタ
    ビノタSep 12, 2020

    As another comment said that it is not a11y friendly. I strongly recommend to use input[type=checkbox] and use css to style it. Or, you can put an input[type=checkbox] that only visible to screen readers, then hide your divs on screen readers.

  • Abhigyan
    AbhigyanSep 12, 2020

    How did you create that GIF at the topmost?

Add comment