Skip to main content

Vue.js Checkbox and Radio Inputs

Introduction

Form controls are a crucial part of web applications, allowing users to input data and make selections. Among these controls, checkboxes and radio buttons are particularly important for gathering user choices. Vue.js provides elegant ways to work with these input types, making it easy to bind data, validate selections, and create dynamic form experiences.

In this tutorial, we'll explore how to:

  • Create and bind checkbox inputs in Vue.js
  • Work with single and multiple checkbox selections
  • Implement radio button groups
  • Apply validation to these form controls
  • Use checkbox and radio inputs in real-world scenarios

By the end, you'll have a solid understanding of how to integrate these form controls into your Vue applications.

Basic Checkbox Binding

Single Checkbox Binding

Let's start with a single checkbox that binds to a boolean value:

html
<template>
<div>
<input type="checkbox" id="subscribe" v-model="subscribed">
<label for="subscribe">Subscribe to newsletter</label>

<p>Subscription status: {{ subscribed ? 'Subscribed' : 'Not subscribed' }}</p>
</div>
</template>

<script>
export default {
data() {
return {
subscribed: false
}
}
}
</script>

In this example:

  • We create a checkbox input with the v-model directive bound to the subscribed data property
  • v-model automatically handles the two-way binding
  • When the checkbox is checked, subscribed becomes true; when unchecked, it becomes false
  • We use this value to conditionally display the subscription status

Multiple Checkbox Binding

For multiple checkboxes that need to be bound to an array of values:

html
<template>
<div>
<h3>Select your interests:</h3>

<input type="checkbox" id="coding" value="coding" v-model="interests">
<label for="coding">Coding</label>

<input type="checkbox" id="design" value="design" v-model="interests">
<label for="design">Design</label>

<input type="checkbox" id="marketing" value="marketing" v-model="interests">
<label for="marketing">Marketing</label>

<p>Selected interests: {{ interests.join(', ') }}</p>
</div>
</template>

<script>
export default {
data() {
return {
interests: []
}
}
}
</script>

With multiple checkboxes:

  • All checkboxes are bound to the same array (interests) using v-model
  • Each checkbox has a unique value attribute
  • When a checkbox is checked, its value is added to the array
  • When unchecked, the value is removed from the array
  • This makes it easy to track multiple selections

Radio Button Implementation

Radio buttons allow users to select only one option from a group:

html
<template>
<div>
<h3>Select your preferred contact method:</h3>

<input type="radio" id="email" value="email" v-model="contactPreference">
<label for="email">Email</label>

<input type="radio" id="phone" value="phone" v-model="contactPreference">
<label for="phone">Phone</label>

<input type="radio" id="mail" value="mail" v-model="contactPreference">
<label for="mail">Mail</label>

<p>You prefer to be contacted by: {{ contactPreference }}</p>
</div>
</template>

<script>
export default {
data() {
return {
contactPreference: 'email' // Default selection
}
}
}
</script>

Key points about radio buttons:

  • All radio inputs in the same group share the same v-model
  • Each radio button has a unique value
  • Only one option can be selected at a time
  • Setting an initial value in the data property will pre-select that radio button

True-value and False-value Customization

Sometimes you might want a checkbox to represent values other than true and false. Vue allows this with the true-value and false-value attributes:

html
<template>
<div>
<input
type="checkbox"
id="consent"
v-model="userConsent"
:true-value="'yes'"
:false-value="'no'"
>
<label for="consent">I agree to the terms and conditions</label>

<p>User consent: {{ userConsent }}</p>
</div>
</template>

<script>
export default {
data() {
return {
userConsent: 'no' // Initial value
}
}
}
</script>

In this example:

  • The checkbox will set userConsent to 'yes' when checked
  • When unchecked, it will be set to 'no'
  • This is useful when you need specific string values rather than booleans

Dynamic Checkbox and Radio Options

Often, you'll want to generate checkbox or radio options dynamically from data:

html
<template>
<div>
<h3>Select technologies you know:</h3>

<div v-for="tech in technologies" :key="tech.value">
<input
type="checkbox"
:id="tech.value"
:value="tech.value"
v-model="selectedTechnologies"
>
<label :for="tech.value">{{ tech.label }}</label>
</div>

<p>You know: {{ selectedTechnologies.join(', ') }}</p>

<h3>Select your primary role:</h3>
<div v-for="role in roles" :key="role.value">
<input
type="radio"
:id="role.value"
:value="role.value"
v-model="selectedRole"
>
<label :for="role.value">{{ role.label }}</label>
</div>

<p>Your role is: {{ selectedRole }}</p>
</div>
</template>

<script>
export default {
data() {
return {
selectedTechnologies: [],
selectedRole: '',
technologies: [
{ value: 'vue', label: 'Vue.js' },
{ value: 'react', label: 'React' },
{ value: 'angular', label: 'Angular' },
{ value: 'svelte', label: 'Svelte' }
],
roles: [
{ value: 'frontend', label: 'Frontend Developer' },
{ value: 'backend', label: 'Backend Developer' },
{ value: 'fullstack', label: 'Full Stack Developer' },
{ value: 'designer', label: 'UI/UX Designer' }
]
}
}
}
</script>

Benefits of dynamic generation:

  • More maintainable as options come from data
  • Easier to update or load from an API
  • Consistent styling and behavior
  • Reduced HTML duplication

Form Validation with Checkboxes and Radio Buttons

You often need to validate that required checkboxes are checked or that one radio option is selected. Here's how to implement basic validation:

html
<template>
<div>
<form @submit.prevent="submitForm">
<h3>Conference Registration</h3>

<div>
<input
type="checkbox"
id="terms"
v-model="formData.acceptTerms"
>
<label for="terms">I accept the terms and conditions</label>
<p v-if="errors.terms" class="error">{{ errors.terms }}</p>
</div>

<div>
<h4>Select your ticket type:</h4>
<div v-for="ticket in ticketOptions" :key="ticket.value">
<input
type="radio"
:id="ticket.value"
:value="ticket.value"
v-model="formData.ticketType"
>
<label :for="ticket.value">{{ ticket.label }}</label>
</div>
<p v-if="errors.ticketType" class="error">{{ errors.ticketType }}</p>
</div>

<button type="submit">Register</button>

<div v-if="isSubmitted" class="success">
Form submitted successfully!
</div>
</form>
</div>
</template>

<script>
export default {
data() {
return {
formData: {
acceptTerms: false,
ticketType: ''
},
ticketOptions: [
{ value: 'standard', label: 'Standard ($99)' },
{ value: 'premium', label: 'Premium ($199)' },
{ value: 'vip', label: 'VIP ($299)' }
],
errors: {
terms: '',
ticketType: ''
},
isSubmitted: false
}
},
methods: {
submitForm() {
// Reset errors
this.errors = {
terms: '',
ticketType: ''
};

// Validate form
let isValid = true;

if (!this.formData.acceptTerms) {
this.errors.terms = 'You must accept the terms and conditions';
isValid = false;
}

if (!this.formData.ticketType) {
this.errors.ticketType = 'Please select a ticket type';
isValid = false;
}

// Submit if valid
if (isValid) {
// Here you would typically send the data to your server
console.log('Form submitted:', this.formData);
this.isSubmitted = true;
}
}
}
}
</script>

<style scoped>
.error {
color: red;
font-size: 0.8rem;
}
.success {
color: green;
margin-top: 10px;
padding: 10px;
border: 1px solid green;
background-color: #f0fff0;
}
</style>

Key validation concepts:

  • Check required checkboxes are checked
  • Verify that a radio option is selected
  • Display appropriate error messages
  • Prevent form submission if validation fails
  • Provide feedback on successful submission

Real-World Example: Product Configuration Form

Let's examine a practical example of using checkboxes and radio buttons for a product configuration form:

html
<template>
<div class="product-configurator">
<h2>Custom Laptop Builder</h2>

<div class="form-section">
<h3>Processor</h3>
<div v-for="option in processorOptions" :key="option.id">
<input
type="radio"
:id="`processor-${option.id}`"
:value="option"
v-model="selectedOptions.processor"
name="processor"
>
<label :for="`processor-${option.id}`">
{{ option.name }} - ${{ option.price }}
</label>
</div>
</div>

<div class="form-section">
<h3>Add-ons</h3>
<div v-for="addon in addonOptions" :key="addon.id">
<input
type="checkbox"
:id="`addon-${addon.id}`"
:value="addon"
v-model="selectedOptions.addons"
>
<label :for="`addon-${addon.id}`">
{{ addon.name }} - ${{ addon.price }}
</label>
</div>
</div>

<div class="summary">
<h3>Configuration Summary</h3>
<div v-if="selectedOptions.processor">
<strong>Processor:</strong> {{ selectedOptions.processor.name }}
(${{ selectedOptions.processor.price }})
</div>

<div v-if="selectedOptions.addons.length > 0">
<strong>Add-ons:</strong>
<ul>
<li v-for="addon in selectedOptions.addons" :key="addon.id">
{{ addon.name }} (${{ addon.price }})
</li>
</ul>
</div>

<div class="total">
<strong>Total Price:</strong> ${{ calculateTotal() }}
</div>

<button @click="submitConfiguration" class="order-button">
Place Order
</button>
</div>
</div>
</template>

<script>
export default {
data() {
return {
selectedOptions: {
processor: null,
addons: []
},
processorOptions: [
{ id: 1, name: "Base Model (i3, 3.2GHz)", price: 200 },
{ id: 2, name: "Enhanced Model (i5, 3.8GHz)", price: 300 },
{ id: 3, name: "Performance Model (i7, 4.5GHz)", price: 450 }
],
addonOptions: [
{ id: 1, name: "Extra 8GB RAM", price: 80 },
{ id: 2, name: "1TB SSD Upgrade", price: 120 },
{ id: 3, name: "Wi-Fi 6 Card", price: 30 },
{ id: 4, name: "Extended Warranty", price: 100 }
]
}
},
methods: {
calculateTotal() {
let total = 0;

// Add processor price
if (this.selectedOptions.processor) {
total += this.selectedOptions.processor.price;
}

// Add all selected add-ons
this.selectedOptions.addons.forEach(addon => {
total += addon.price;
});

return total;
},
submitConfiguration() {
// Validate configuration
if (!this.selectedOptions.processor) {
alert("Please select a processor option");
return;
}

// Here you would send the configuration to your server
const orderDetails = {
processor: this.selectedOptions.processor,
addons: this.selectedOptions.addons,
totalPrice: this.calculateTotal()
};

console.log("Order submitted:", orderDetails);
alert("Your configuration has been submitted!");
}
}
}
</script>

<style scoped>
.product-configurator {
max-width: 600px;
margin: 0 auto;
padding: 20px;
}

.form-section {
margin-bottom: 20px;
padding: 15px;
border: 1px solid #ddd;
border-radius: 5px;
}

.summary {
margin-top: 30px;
padding: 20px;
background: #f8f9fa;
border-radius: 5px;
}

.total {
margin-top: 20px;
font-size: 1.2em;
}

.order-button {
margin-top: 20px;
padding: 10px 20px;
background: #4caf50;
color: white;
border: none;
border-radius: 4px;
cursor: pointer;
}

.order-button:hover {
background: #45a049;
}
</style>

This real-world example demonstrates:

  • Using radio buttons for mutually exclusive options (processor choice)
  • Using checkboxes for optional add-ons
  • Real-time price calculation based on selections
  • Form validation before submission
  • Structured data organization for complex forms

Advanced Considerations and Best Practices

Custom Components

For larger applications, consider creating reusable checkbox and radio components:

html
<!-- CustomCheckbox.vue -->
<template>
<div class="custom-checkbox">
<input
type="checkbox"
:id="id"
:checked="modelValue"
@change="$emit('update:modelValue', $event.target.checked)"
v-bind="$attrs"
>
<label :for="id">
<slot></slot>
</label>
</div>
</template>

<script>
export default {
props: {
id: {
type: String,
required: true
},
modelValue: {
type: Boolean,
default: false
}
},
emits: ['update:modelValue']
}
</script>

<style scoped>
.custom-checkbox {
display: flex;
align-items: center;
margin-bottom: 8px;
}
/* Add custom styling for your checkbox here */
</style>

Usage:

html
<template>
<div>
<custom-checkbox
id="terms-agreement"
v-model="agreedToTerms"
>
I agree to the terms and conditions
</custom-checkbox>

<p>Agreed: {{ agreedToTerms }}</p>
</div>
</template>

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

export default {
components: {
CustomCheckbox
},
data() {
return {
agreedToTerms: false
}
}
}
</script>

Accessibility Considerations

Always ensure your form controls are accessible:

  • Use proper <label> elements for all inputs
  • Group related controls with <fieldset> and <legend>
  • Ensure sufficient color contrast
  • Provide error messages that are clear and associated with the relevant inputs
  • Support keyboard navigation
html
<template>
<div>
<fieldset>
<legend>Notification Preferences</legend>

<div class="checkbox-group">
<input type="checkbox" id="email-notif" v-model="notifications.email">
<label for="email-notif">Email notifications</label>
</div>

<div class="checkbox-group">
<input type="checkbox" id="sms-notif" v-model="notifications.sms">
<label for="sms-notif">SMS notifications</label>
</div>

<div class="checkbox-group">
<input type="checkbox" id="push-notif" v-model="notifications.push">
<label for="push-notif">Push notifications</label>
</div>
</fieldset>
</div>
</template>

<script>
export default {
data() {
return {
notifications: {
email: true,
sms: false,
push: true
}
}
}
}
</script>

Summary

In this guide, we explored how to work with checkbox and radio inputs in Vue.js:

  • Basic checkbox binding with single boolean values
  • Multiple checkbox binding with arrays
  • Radio button implementation for single selections
  • Customizing input values with true-value and false-value
  • Creating dynamic form controls from data
  • Implementing form validation for checkbox and radio inputs
  • Building a real-world product configurator

These form controls are essential building blocks for creating interactive forms in your Vue applications. When implemented correctly, they provide intuitive interfaces for users to make selections and provide input.

Additional Resources and Exercises

Further Reading

Practice Exercises

  1. Tiered Pricing Form: Create a form that uses radio buttons to select a subscription tier (Basic, Pro, Enterprise) and checkboxes to select optional add-on features. Calculate and display the total price.

  2. Quiz Application: Build a simple quiz with radio buttons for single-answer questions and checkboxes for multiple-answer questions. Include validation and score calculation.

  3. User Preferences Panel: Create a settings page that uses checkboxes and radio buttons to save user preferences (theme, notifications, privacy settings) and persists them to localStorage.

  4. Advanced Survey Form: Create a multi-section survey with various question types including checkbox and radio options. Include validation to ensure all required questions are answered.

By mastering checkbox and radio inputs in Vue.js, you'll be able to create more interactive and user-friendly forms in your applications.



If you spot any mistakes on this website, please let me know at [email protected]. I’d greatly appreciate your feedback! :)