Be part of JetBrains PHPverse 2026 on June 9 – a free online event bringing PHP devs worldwide together.

vincej's avatar
Level 15

Vue 3 : how to create a checkbox switch

HI All, I am upgrading a Vue 2 site to a Vue 3 site. Under Vue 2 I was able to create a checkbox switch. However, now, under Vue3 this no longer works. Ok, I am using Bootstrap 5 and the docs tell me that the BS5 switch will default to square checkbox if it can't deliver a switch. I have scoured the internet and people have created a switch by long winded and complex manual JS and CSS. Does anyone know how to do this with a small amount of CSS? Here is the code I am currently using drawn from BS5. https://getbootstrap.com/docs/5.2/forms/checks-radios/#switches

I am not keen on converting to Tailwind. My site is now too big for that.

<td class="col-4">
                <div class="form-check form-switch">
                    <input
                        type="checkbox"
                        class="form-check-input"
                        role="switch"
                        :id="child.child_id"
                        v-model="child.status"
                        :true-value="1"
                        :false-value="0"
                    >
                    <label class="form-check-label" v-bind:for="child.child_id">Absent / Present</label>
                </div>
            </td>
0 likes
13 replies
martinbean's avatar

@vincej This is something I’ve done a couple of times myself. You can create a custom input component for switches:

<template>
    <div class="form-check form-switch">
        <input
            class="form-check-input"
            role="switch"
            type="checkbox"
            v-bind:checked="modelValue"
            v-bind:id="id"
            v-bind:name="name"
            v-bind="$attrs"
            v-on:input="onInput"
        >
        <label class="form-check-label" v-bind:for="id">
            <slot></slot>
        </label>
    </div>
</template>

<script>
export default {
    props: {
        id: {
            required: true,
            type: String,
        },
        modelValue: {
            default: false,
            required: true,
            type: Boolean,
        },
        name: {
            required: true,
            type: String,
        },
    },
    emits: [
        'update:modelValue',
    ],
    inheritAttrs: false,
    setup(props, { emit }) {
        const onInput = (event: Event) => emit('update:modelValue', event.target.checked);

        return {
            onInput,
        };
    },
};
</script>

If you store this in a file called BootstrapSwitch.vue, then you can use it in your other components using a v-model directive:

<template>
    <bootstrap-switch
        id="active-switch"
        name="active"
        v-model="item.active"
    />
<template>

<script>
import BootstrapSwitch from './BootstrapSwitch.vue';

export default {
    components: {
        BootstrapSwitch,
    },
    setup() {
        const item = getItemObjectFromSomewhere();

        return {
            item,
        };
    },
};
</script>
vincej's avatar
Level 15

You are a rockstar! Thank you. I will give it a try and report back when I am successful.

1 like
vincej's avatar
Level 15

@martinbean Hi Martin - I'm back. I'm not a person who will just copy and paste other peoples code, so I have been endeavouring to understand everything within the code you sent me. Furthermore I am quite new to Vue, especially Vue3. So, it has taken me a bit of time to workout the new composition API etc.

Anyway - I have tried the code and I am getting an error, perhaps you are using TS?

SyntaxError: /Users/vincejacobs/Sites/KidsClub/resources/js/Pages/Test.vue: Unexpected token, expected "," (23:30)

  21 |     inheritAttrs: false,
  22 |     setup(props, { emit }) {
> 23 |         const onInput = (event: Event) => emit('update:modelValue', event.target.checked);
     |                               ^
  24 |
  25 |         return {
  26 |             onInput,
 

Once we get past this, I hope you don't mind educating me a bit with one or two other bits.

Many thanks again! Cheers Vince

Sinnbeck's avatar

@vincej that does indeed seem like a type declaration :) just remove it

const onInput = (event) => emit('update:modelValue', event.target.checked);
vincej's avatar
Level 15

@martinbean Hi yah, I'm making some progress. First off, I am using Inertia and I have the data object appearing in Vue dev tools for my page. I put the code into a file BootstrapSwitch.vue as instructed. However I am not sure what I am doing wrong with respect to the imported bootstrap-switch template. I've been hunting around on the web and Jeffrey's tutorial and I understand that these are attributes, but I am failing at getting something to work.

<bootstrap-switch
        id="active-switch"
        name="active"
        v-model="item.active"
    />

This is what I have got, Children is what is coming n from Inertia

<template>

        <bootstrap-switch
            id="active-switch"
            name="active"
            v-model="children"
        />

    <tr v-for="child in Children" :key="child.child_id">
        <td>
         {{child}}
        </td>
    </tr>
</template>

<script>
import BootstrapSwitch from '../components/BootstrapSwitch.vue';

export default {
    components: {
        BootstrapSwitch,
    },
    setup() {
        const children = 'Children';

        return {
            children,
        };
    },
};
</script>


Many thanks for all your help!

martinbean's avatar

@vincej I don’t really understand what you’re trying to create a “switch” on if children is some sort of array or object?

You should be binding some sort of boolean to v-model instead, as it’s a checkbox. So it toggles between “true” and “false” values. You can’t pass an array/object as the value of a checkbox.

vincej's avatar
Level 15

@martinbean Thanks for coming back and helping out! I am a self confessed Vue newb who has spent tool long using raw JS. Yes, children is an array. I have a table which needs to loop through children names. The switch will apply true or false to their status. Ok, so, I applied a boolean to the attribute and it gave me an error. I'm sorry for being so stupid, but I really am not sure what to do with this.

Many thanks

VueCompilerError: v-model value must be a valid JavaScript member expression.
at /Users/vincejacobs/Sites/KidsClub/resources/js/Pages/Test.vue:6:22
4  |              id="active-switch"
5  |              name="active"
6  |              v-model="false"
   |                       ^^^^^
7  |          />
8  |  


vincej's avatar
Level 15

@martinbean Thank you for that. That gives me a good clue where I am going wrong. I will spend some more time with the Vue docs and Jeffrey's tutorial. This is all a world away from raw JS / JQuery. Cheers.

vincej's avatar
Level 15

@martinbean Hi Martin, Back gain.

I really want to say that I appreciate you helping me and I do not take it for granted. I spent the day with Jeffrey's LC tutorial on Vue 3 as well as the day with the Vue 3 docs as well as scouring the web, and I am obviously not seeing what you are doing in your code as I can not make it work. Specifically the v-model thing.

I understand that v-model provides two way binding. I understand that within BootstrapSwitch you have made it a requirement which triggers the component. What I am missing is that I my table uses 1 and 0 for true / false . I am getting the children coming through on the rendered blade view in my table. However I just do not see what I am missing to get BladeSwitch to work. Maybe I need to apply the below to change child_status to boolean true/false?? How should I do that? Many thanks !

:true-value="1"
:false-value="0"

Many Thanks!

<template>

        <div class="container">
            <h5 class="heading ml-4">Children Absent / Present</h5>
            <div class="border_charts">
                <table class="table ">
                    <thead>
                    <tr class="col-4">
                        <th class="tableHeading col-4">First Name</th>
                        <th class="tableHeading col-4">Last Name</th>
                        <th class="tableHeading col-4 ">Absent / Present</th>
                    </tr>
                    </thead>
                    <tbody>
                    <tr v-for="child in Children" :key="child.child_id">
                        <td class="col-4"><a :href="'/getchild/'+ child.child_id">{{child.childFirstName}}</a></td>
                        <td class="col-4"> {{child.childLastName}}</td>
                        <td class="col-4">
                            <bootstrap-switch
                                id={{child.child_id}}
                                name="absentPresent"
                                v-model={{child.status}} />				// This does not work
                        </td>
                    </tr>
                    </tbody>
                </table>
            </div>
        </div>
    </template>


<script>
import BootstrapSwitch from '../components/BootstrapSwitch.vue';

export default {
    components: {
        BootstrapSwitch,
    },

    props:{Children:Array}
}
</script>


projectasphaliea's avatar

@vincej personally I’d use the SFC/Composite like this.

<script setup>
import BootstrapSwitch from ’../components/BootstrapSwitch.vue’;

defineProps({
 Children: {
     type: Array,
     required: false,
     default() {
         return [];
     }
 }
});
</script>
vincej's avatar
Level 15

@martinbean I'm sorry martin, I can't get your code to work no matter what I do. I have standard square checkboxes appearing in my view all checked positive, which is the default in Vue3. One challenge I have is that child.status is a boolean, however, it is 1 or 0, not true or false. There is a way of converting this using true-value = 1, false-value=0 however, I don't know how to apply that to your code. BTW ... if I'm not mistaken you are in the UK. Nice, I lived there for most of my life. Cheers.

Please or to participate in this conversation.