Create a custom toggle component in Vue.js. 🎛
Tags: vue, javascript, webdev, tutorial
Published: 2020-09-11 13:26:08

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](https://media.giphy.com/media/3rgXBETfAu65Gw6jwA/giphy.gif)
<figcaption>We have some switches to manufacture now...</figcaption>

---

## What are we making❓

This:

![Vue Custom Toggle Demo](https://dev-to-uploads.s3.amazonaws.com/i/e88byv9y75qffomhpngs.gif)
<figcaption>I know, I know, it looks terrible, but let's just focus on the implementation :)</figcaption>

## Kickstart the custom toggle 🦵

#### Step 1️⃣: The setup

Fire open your terminal to create a new Vue project:

```js
vue create custom-toggle
```

If you don't have the [Vue CLI](https://cli.vuejs.org/) installed in your machine, you can find the installation steps on their [official website](https://cli.vuejs.org/guide/installation.html).

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
```
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()`](https://vuejs.org/v2/api/#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`](https://vuejs.org/v2/api/#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](https://vuejs.org/v2/guide/syntax.html?#Interpolations). 

> App.vue:

```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>
```

#### 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:

```css
.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;
}
```

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](https://vuejs.org/v2/api/#props) 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](https://vuejs.org/v2/guide/class-and-style.html) with [`v-bind`](https://vuejs.org/v2/api/#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`](https://vuejs.org/v2/api/#v-on) click listener to the two children of the container. Pass on a new method `switched()` to it as shown:

```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>
```

For the body of this method, we need to _emit_ the new [custom event](https://vuejs.org/v2/guide/components-custom-events.html) 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:

```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>
```
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:

{% codesandbox quiet-mountain-58r1c %}

---

## Where to next? 🤔

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

- [Components Basics — Vue.js](https://vuejs.org/v2/guide/components.html) 
- [Creating Custom Inputs With Vue.js by Joseph Zimmerman](https://www.smashingmagazine.com/2017/08/creating-custom-inputs-vue-js/) 
- [Adding v-model Support to Custom Vue.js Components by Joshua Bemenderfer](https://www.digitalocean.com/community/tutorials/vuejs-add-v-model-support) 
- [Learn Vue 2: Part 25 - Custom Input Components by Laracasts](https://www.youtube.com/watch?v=hsat438PfSU&ab_channel=Laracasts)

---

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

---
<blockquote class="twitter-tweet" data-partner="tweetdeck"><p lang="en" dir="ltr">Can you spot the difference? 😝<br><br>Image source: <a href="https://t.co/rhSnxZLNJa">https://t.co/rhSnxZLNJa</a><a href="https://twitter.com/hashtag/DevHumour?src=hash&amp;ref_src=twsrc%5Etfw">#DevHumour</a> <a href="https://twitter.com/hashtag/WFH?src=hash&amp;ref_src=twsrc%5Etfw">#WFH</a> <a href="https://twitter.com/hashtag/RemoteWorking?src=hash&amp;ref_src=twsrc%5Etfw">#RemoteWorking</a> <a href="https://t.co/MRmH1aKB9u">pic.twitter.com/MRmH1aKB9u</a></p>&mdash; Microsoft Developer UK (@msdevUK) <a href="https://twitter.com/msdevUK/status/1303957157323431936?ref_src=twsrc%5Etfw">September 10, 2020</a></blockquote>
<script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
---

#### [📫 Subscribe to my weekly developer newsletter 📫](https://mailchi.mp/f59beeac6b9b/devupdates)

##### 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](https://medium.com/@vaibhavkhulbe)'s my Medium profile.