Tailwind & Vue turorial: Build your own custom "checkbox" cover image

Tailwind & Vue turorial: Build your own custom "checkbox"

Stratulat Alexandru • January 12, 2019

tutorial tailwind vue

In my previous post, we've built a custom switch component with Tailwind & Vue. No CSS. 26 lines of code. Building cool components has never been so easy. I've not been using Tailwind for so long, but it has already motivated me to start this blog.

Here is what we're going to build (examples are interactive):

Let's start by creating a new file called, let's say VCheckbox.vue.

1. The main container

<template>
  <div class="w-5 h-5 rounded border border-grey inline-flex justify-center items-center bg-white"></div>
</template>

Breakdown of the classes:

  • w-5 Width 1.25rem
  • h-5 Height 1.25rem
  • rounded .25rem rounded corners
  • border 1px border
  • border-grey Grey border color
  • inline-flex Display inline flex
  • justify-center Center content horizontally
  • items-center Center content vertically
  • bg-white White background

2. The check icon

We'll use something very simple, like this:

<svg
  xmlns="http://www.w3.org/2000/svg"
  viewBox="0 0 512 512"
>
  <path
    d="M504.502,75.496c-9.997-9.998-26.205-9.998-36.204,0L161.594,382.203L43.702,264.311c-9.997-9.998-26.205-9.997-36.204,0
  c-9.998,9.997-9.998,26.205,0,36.203l135.994,135.992c9.994,9.997,26.214,9.99,36.204,0L504.502,111.7
  C514.5,101.703,514.499,85.494,504.502,75.496z"
  ></path>
</svg>

No we'll just put it inside our container, but first:

  • Give it a 50% width using the class w-1/2 (the height will be auto adjusted)
  • Set the fill color of the SVG to the current text color using the class fill-current
  • Give it a white text color using the class text-white so it would look "invisible"

Example:

<template>
  <div class="w-5 h-5 rounded border border-grey inline-flex justify-center items-center bg-white">
    <svg
      class="w-1/2 fill-current text-white"
      xmlns="http://www.w3.org/2000/svg"
      viewBox="0 0 512 512"
    >
      <path
        d="M504.502,75.496c-9.997-9.998-26.205-9.998-36.204,0L161.594,382.203L43.702,264.311c-9.997-9.998-26.205-9.997-36.204,0
      c-9.998,9.997-9.998,26.205,0,36.203l135.994,135.992c9.994,9.997,26.214,9.99,36.204,0L504.502,111.7
      C514.5,101.703,514.499,85.494,504.502,75.496z"
      ></path>
    </svg>
  </div>
</template>

3. The value prop

To be able to use v-model on the component like this:

<v-checkbox v-model="someVariable" />

specify a value prop inside the component.

<script>
export default {
  props: {
    value: {
      type: Boolean,
      required: true,
    },
  },
};
</script>

By default, to trigger updates on the v-model variable from inside a component, we have to emit an input event. It doesn't sound quite good in context of a "checkbox", so we'll rename the event to change.

Example:

<script>
export default {
  model: {
    event: 'change',
  },
  props: {
    value: {
      type: Boolean,
      required: true,
    },
  },
};
</script>

Now just emit the change event when our checkbox is clicked:

<template>
  <div
    class="w-5 h-5 rounded border border-grey inline-flex justify-center items-center bg-white"
    @click="$emit('change', !value)"
  >
    <svg
      class="w-1/2 fill-current text-white"
      xmlns="http://www.w3.org/2000/svg"
      viewBox="0 0 512 512"
    >
      <path
        d="M504.502,75.496c-9.997-9.998-26.205-9.998-36.204,0L161.594,382.203L43.702,264.311c-9.997-9.998-26.205-9.997-36.204,0
      c-9.998,9.997-9.998,26.205,0,36.203l135.994,135.992c9.994,9.997,26.214,9.99,36.204,0L504.502,111.7
      C514.5,101.703,514.499,85.494,504.502,75.496z"
      ></path>
    </svg>
  </div>
</template>

4. Active background & border

The last thing to do is to update container's background & border colors based on the value.

<template>
  <div
    :class="{ 'bg-indigo border-indigo': value }"
    class="w-5 h-5 rounded border border-grey inline-flex justify-center items-center bg-white"
    @click="$emit('change', !value)"
  >
    <svg
      class="w-1/2 fill-current text-white"
      xmlns="http://www.w3.org/2000/svg"
      viewBox="0 0 512 512"
    >
      <path
        d="M504.502,75.496c-9.997-9.998-26.205-9.998-36.204,0L161.594,382.203L43.702,264.311c-9.997-9.998-26.205-9.997-36.204,0
      c-9.998,9.997-9.998,26.205,0,36.203l135.994,135.992c9.994,9.997,26.214,9.99,36.204,0L504.502,111.7
      C514.5,101.703,514.499,85.494,504.502,75.496z"
      ></path>
    </svg>
  </div>
</template>

See how the icon "magically" appears? Feels like a hacky approach to me. 😆

Full Example

The last thing I would add to the container classes is cursor-pointer.

<template>
  <div
    :class="{ 'bg-indigo border-indigo': value }"
    class="w-5 h-5 rounded border border-grey inline-flex justify-center items-center bg-white cursor-pointer"
    @click="$emit('change', !value)"
  >
    <svg
      class="w-1/2 fill-current text-white"
      xmlns="http://www.w3.org/2000/svg"
      viewBox="0 0 512 512"
    >
      <path
        d="M504.502,75.496c-9.997-9.998-26.205-9.998-36.204,0L161.594,382.203L43.702,264.311c-9.997-9.998-26.205-9.997-36.204,0
            c-9.998,9.997-9.998,26.205,0,36.203l135.994,135.992c9.994,9.997,26.214,9.99,36.204,0L504.502,111.7
            C514.5,101.703,514.499,85.494,504.502,75.496z"
      ></path>
    </svg>
  </div>
</template>

<script>
export default {
  model: {
    event: 'change',
  },
  props: {
    value: {
      type: Boolean,
      required: true,
    },
  },
};
</script>

Note: In this example we didn't cover transitions, since they aren't available in Tailwind by default. I recommend this Tailwind plugin glhd-tailwindcss-transitions. After installation you can use the transition class on the container.

Sign up for new posts

No spam. Unsubscribe at any time.