Vue Checkbox Component with v-model

I find it helpful to create custom Vue components for Vue projects. The custom component encapsulates implementation details for the project’s components including extra divs and their styling. This can become an uncumberance with situations like a checkbox component. I want to use v-model, but it’s not straightforward to do because of how v-model works with checkboxes. I’m going to demonstrate how I create custom checkbox container and input components and make them work properly with v-model.

Input Checkbox Component

This is the input checkbox component that I use. Note that v-model behaves differently with certain elements. For input text it works on the value attr and the input event. On a checkbox it works on the checked attr and the change event.

In my component I’m adapting its checkbox which uses checked and change to use value and input so v-model works properly on the component.

There might be a better way, but I haven’t found it.

<template>
  <div class="">
    <div class="">
      <input
        :id="id"
        :name="name"
        type="checkbox"
        class=""
        v-bind:checked="value"
        v-on:change="$emit('input', $event.target.checked)"
      />
    </div>
    <div class="">
      <label :for="id">
        {{ name }}
      </label>
    </div>
  </div>
</template>

<script>
props: {
  id: {
    type: String
  },
  name: {
    type: String
  },
  value: {
    type: Boolean
  }
}
</script>

Container Component

I use a container component on something like this because I want to create the children explicitly depending on implementation of that fieldset.

<template>
  <fieldset class="input-checkbox-container">
    <slot></slot>
  </fieldset>
</template>

<style>
.input-checkbox-container {
}
</style>

<script>
module.exports = {
  props: ['id', 'name']
};
</script>

Usage

Now for a demonstration of composition with this approach.

<template>
  <form>
    <input-checkbox-container id="widgets" name="Widgets">
      <input-checkbox id="foo" name="Foo" v-model="obj.foo"></input-checkbox>
      <input-checkbox id="bar" name="Bar" v-model="obj.bar"></input-checkbox>
    </input-checkbox-container>
  </form>
</template>

<script>
module.exports = {
  data: function () {
    return {
      obj: {}
    };
  },
  components: {
    InputCheckboxContainer,
    InputCheckbox
  }
};
</script>