Image

vue-3-forms

4 min read
Last update: December 19, 2021

Base Checkbox

Previously in this course we created reusable components for two important HTML inputs: the BaseInput and the BaseSelect for the input and select elements, respectively.

In this lesson, we take on a new challenge of creating a reusable base component for our checkbox inputs. The goal remains the same, the component should be highly reusable and able to accept v-model bindings.

Let’s dive right in!


First, we’ll create a new file, BaseCheckbox.vue inside the components folder.

We are going to add a template block, and copy the input with type checkbox in our SimpleForm.vue file which holds the control for the “Catering” into it.

📃BaseCheckbox.vue

<template>
    <input type="checkbox" v-model="event.extras.catering" class="field" />
    <label>Catering</label>
</template>

Labels first

As we’ve done in our other components, we’re going to tackle the label first. We need to make sure that we have a way to inject a label into this component, so we’re going to add a label prop so that the parent can pass it down to our component.

Let’s go ahead and add that property, and bind it to the label tag.

📃BaseCheckbox.vue

<template>
    <input type="checkbox" v-model="event.extras.catering" class="field" />
    <label v-if="label">{{ label }}</label>
</template>

<script>
    export default {
        props: {
            label: {
                type: String,
                default: ''
            }
        }
    }
</script>

Notice that we’ve added a v-if condition to check to see that the label property is set before we render the <label> element. There’s no real reason to render an empty label tag, and worse - we don’t want to label it as an empty string!

There are several accessibility considerations when talking about labels and inputs, and what we’ve been doing so far will mostly not be accessible. However, in a later lesson we will revisit these components when we take a look at the basics of accessibility in forms.

---

## Making it v-model capable

Now that our label has been set up, let’s move on to making it so that the component can accept `v-model` bindings.

Checkboxes have a few quirks that we need to keep in mind before we start setting up our bindings. The first one is that checkbox inputs bind their state to a `checked` property, and not directly to `value`.

The property `value` of checkboxes is not usually used on the frontend, since its main purpose is to provide a value when submitted to the backend via a submit button. If omitted, this `value` defaults to `on`, which is fine for most apps — since most forms will be handled via some asynchronous posting and the passed variables to the backend are controlled by the frontend code.

The second thing we need to keep in mind, is that inputs with type `checkbox` don’t trigger `input` events, but `change` events whenever they are selected and unselected.

Now that we are armed with this knowledge, let’s add our `modelValue` prop, which will hold the first part of our two way binding: allowing the parent to inject a state for the checkbox.

**📃BaseCheckbox.vue**

```javascript
props: {
label: {
type: String,
default: ''
},
modelValue: {
type: Boolean,
default: false
}
}
```

Next, let’s go into the `template` and replace the `v-model` binding that was copy-pasted from the demo form earlier with our new `:checked` binding into our `modelValue` prop.

**📃BaseCheckbox.vue**

```html
<template>
    <input type="checkbox" :checked="modelValue" class="field" />
    <label v-if="label">{{ label }}</label>
</template>
```

Finally, we need to emit `update:modelValue` whenever we want to alert the parent that the checkbox has been toggled. We will listen to the `@change` event on the input element, and emit the new checked state of our element whenever it fires.

**📃BaseCheckbox.vue**

```html
<input type="checkbox" :checked="modelValue" @change="$emit('update:modelValue', $event.target.checked)" class="field" />
```

Notice that for checkboxes we are not emitting the target’s value through `$event.target.value`, but instead the checked status through `$event.target.checked`.

---

## Using our new component

Now that our component is ready, we can go back to `SimpleForm.vue` and replace both the “Catering” and “Live music” checkboxes with our brand new `BaseCheckbox` component.

**📃SimpleForm.vue**

```html
<h3>Extras</h3>
<div>
    <BaseCheckbox v-model="event.extras.catering" label="Catering" />
</div>

<div>
    <BaseCheckbox v-model="event.extras.music" label="Live music" />
</div>
```

Let’s head over to our browser and toggle the checkboxes on and off to make sure the bindings are working.

![https://firebasestorage.googleapis.com/v0/b/vue-mastery.appspot.com/o/flamelink%2Fmedia%2Fextras.opt.jpg?alt=media&token=1f96bbdc-0007-4ce4-b8d9-1c315a7096d1](https://firebasestorage.googleapis.com/v0/b/vue-mastery.appspot.com/o/flamelink%2Fmedia%2Fextras.opt.jpg?alt=media&token=1f96bbdc-0007-4ce4-b8d9-1c315a7096d1)

---

## Wrapping up

Checkboxes have a few quirks that we had to learn in order to create our `BaseCheckbox` component.

In our next lesson, we are going to tackle our final component, the `BaseRadio` for radio buttons, and we’ll take a look at what makes them special and, sometimes, hard to deal with.

See you there!