Paulund

How To Create A Toggle VueJS Component

In this tutorial we're going to build a form component for a checkbox but styled as a toggle.

The functionality for this toggle will be just like a checkbox but will move the toggle when the checkbox is checked. We will also need to style this differently depending on the state of the checkbox.

Form Component

First we need to decide how we want to use the component and work backwards from here. As this is a form component it will be nice if we can add this to existing forms by using a html tag `form-toggle` and assign the `v-model` to a value in the parent component.
<form-toggle v-model="checked" id="checkbox" label="Toggle" />

VueJS Toggle Component

First we'll create the html for the template part of the VueJS component. This will need to include the checkbox and the label used on the form.
<template>
    <div class="my-2">
        <div class="toggle">
            <input type="checkbox" :id="id" :name="id" value="1" v-on:change="updateValue($event.target.value)" :checked="isChecked" />
            <label :for="id"></label>
        </div>
        <p class="inline-block">{{ label }}</p>
    </div>
</template>

The important element of the above code is the checkbox element.

<input type="checkbox" :id="id" :name="id" value="1" v-on:change="updateValue($event.target.value)" :checked="isChecked" />

It has a number of attributes that will apply the logic to the component so it's important we talk through what these do.

Type is the normal HTML attributes that will define this as a checkbox.

:id is a way of us to use VueJS variable as the value for a HTML attribute therefore :id="id" will output the value of this.id inside on a id attribute. :name is used the same way as id we just display the id variable inside the attribute.

The value of the checkbox is 1.

Then we use v-on:change which will run a method on the change event of the checkbox. In this example we'll call the updateValue method and pass in the current value of the checkbox.

:checked will decide if the checkbox is in a checked state or not.

JavaScript For The Toggle Component

Below is the code we need to change if the checkbox is checked or not and then emit the new value to the parent object allowing us to use `v-model` on the parent object.
<script>
  export default {
    props: ['id', 'label', 'value'],

    methods: {
      updateValue: function () {
        let value = 0

        if(this.value === 0) {
          value = 1
        }

        this.$emit('input', value)
      }
    },

    computed: {
      isChecked() {
        return this.value === 1
      }
    }
  }
</script>

The first data point we need to define is the props for the component, we're going to use ID, label and value.

props: ['id', 'label', 'value'],

The methods we need to create is updateValue which will emit the current value to the parent component.

    methods: {
      updateValue: function () {
        let value = 0

        if(this.value === 0) {
          value = 1
        }

        this.$emit('input', value)
      }
    },

Then we can use a computed method to decide if we show the checkbox as checked or unchecked depending on the current value of the checkbox. This will be used on the checked attribute of the checkbox.

    computed: {
      isChecked() {
        return this.value === 1
      }
    }

The id is to populate the id and name attribute on the checkbox. The value prop will allow us to pass in a default checked/unchecked state.

Styling The Toggle

Finally to style the checkbox as a toggle we can use a previous article to help, looking at [How To Style A Checkbox With CSS](https://paulund.co.uk/how-to-style-a-checkbox-with-css) we can pick any of the checkboxes and use this for the CSS on the toggle.
<style lang="scss">
    .toggle {
        display: inline-block;
        position: relative;
        cursor: pointer;
        height: 2rem;
        width: 4rem;
        background: #3490dc;
        border-radius: 9999px;
        margin-bottom: 1rem;
        input[type=checkbox] {
            visibility: hidden;
        }
        label {
            display: block;
            width: 22px;
            height: 22px;
            border-radius: 50%;
            transition: all .5s ease;
            cursor: pointer;
            position: absolute;
            top: 5px;
            z-index: 1;
            left: 7px;
            background: #ddd;
        }
        input[type=checkbox]:checked + label {
            left: 35px;
            background: #FFF;
        }
    }
</style>

This will create a pill like toggle and changes the colour of the dot from grey to white depending on if the checkbox is checked/unchecked.

Below is the full code you can use as for your VueJS Toggle component.

<template>
    <div class="my-2">
        <div class="toggle">
            <input type="checkbox" :id="id" :name="id" value="1" v-on:change="updateValue($event.target.value)" :checked="isChecked" />
            <label :for="id"></label>
        </div>
        <p class="inline-block">{{ label }}</p>
    </div>
</template>

<style lang="scss">
    .toggle {
        display: inline-block;
        position: relative;
        cursor: pointer;
        height: 2rem;
        width: 4rem;
        background: #3490dc;
        border-radius: 9999px;
        margin-bottom: 1rem;
        input[type=checkbox] {
            visibility: hidden;
        }
        label {
            display: block;
            width: 22px;
            height: 22px;
            border-radius: 50%;
            transition: all .5s ease;
            cursor: pointer;
            position: absolute;
            top: 5px;
            z-index: 1;
            left: 7px;
            background: #ddd;
        }
        input[type=checkbox]:checked + label {
            left: 35px;
            background: #FFF;
        }
    }
</style>

<script>
  export default {
    props: ['id', 'label', 'value'],
    methods: {
      updateValue: function () {
        let value = 0
        if(this.value === 0) {
          value = 1
        }
        this.$emit('input', value)
      }
    },
    computed: {
      isChecked() {
        return this.value === 1
      }
    }
  }
</script>