Bootstrap 5 components designed for Vue.js
This component is part of the CoreUI for Vue.js UI components library, which offers all Bootstrap components designed to work seamlessly with Vue.js.
If you want to use Bootstrap 5 in a Vue.js environment while also needing advanced components that Bootstrap does not offer and dedicated developer support, then this library is the best solution for you.
Learn how to use CoreUI’s Vue Chip Input component with Bootstrap styles for flexible, framework-consistent UI.
Overview
The CoreUI Vue Chip Input component lets users enter multiple values as chips inside a single field. Use it as a tag input, multi-value selector, or token field for skills, categories, email recipients, and more. The chip input component supports keyboard-friendly entry, chip removal, and optional selection for bulk actions.
- Type values and press Enter or a separator to create chips
- Chips can be removable and selectable
- The input stays inline and grows as you type
- Form integration is supported with a hidden input when
nameis provided - Full v-model support for reactive data binding
When to use Chip Input
Use the Vue Chip Input component when you need:
- A tag input or token field for free-form multi-value entry
- An email or recipient input where users add multiple addresses
- A skills or category selector in forms
- A filterable multi-select that integrates with standard HTML forms
Basic example
Use CChipInput to render a multi-value field with predefined chips and inline input.
<template>
<CChipInput v-model="tags" placeholder="Type and press Enter..." />
</template>
<script setup>
import { ref } from 'vue'
import { CChipInput } from '@coreui/vue-pro'
const tags = ref(['Vue.js', 'TypeScript', 'CoreUI'])
</script> With label
Use the label prop for accessibility and better UX.
<template>
<CChipInput id="skills-input" v-model="skills" label="Skills" placeholder="Add skill..." />
</template>
<script setup>
import { ref } from 'vue'
import { CChipInput } from '@coreui/vue'
const skills = ref(['Problem Solving', 'Teamwork', 'Communication'])
</script> Sizes
Use size="sm" and size="lg" to match surrounding form controls.
<template>
<div>
<div class="mb-3">
<CChipInput
id="skillsInputSm"
v-model="smallTags"
label="Small"
size="sm"
placeholder="Add a small chip"
/>
</div>
<div class="mb-3">
<CChipInput
id="skillsInputDefault"
v-model="defaultTags"
label="Default"
placeholder="Add a default chip"
/>
</div>
<div>
<CChipInput
id="skillsInputLg"
v-model="largeTags"
label="Large"
size="lg"
placeholder="Add a large chip"
/>
</div>
</div>
</template>
<script setup>
import { ref } from 'vue'
import { CChipInput } from '@coreui/vue-pro'
const smallTags = ref(['Small chip'])
const defaultTags = ref(['Default chip'])
const largeTags = ref(['Large chip'])
</script> Color variants
Use chipClassName to apply contextual chip colors based on chip text.
<template>
<div>
<CChipInput
v-model="colorTags"
:chip-class-name="(value) => `chip-${value}`"
placeholder="Add color name (primary, secondary, etc.)"
/>
<p class="mt-2 text-muted">
<small>Try adding: primary, secondary, success, danger, warning, info</small>
</p>
</div>
</template>
<script setup>
import { ref } from 'vue'
import { CChipInput } from '@coreui/vue-pro'
const colorTags = ref(['primary', 'secondary', 'success', 'danger'])
</script> Static chip class
Apply a single class to all chips.
<template>
<CChipInput v-model="tags" chip-class-name="chip-info" placeholder="Add tagged items..." />
</template>
<script setup>
import { ref } from 'vue'
import { CChipInput } from '@coreui/vue'
const tags = ref(['Tagged', 'Items'])
</script> Separator
By default, chips are created when the user types a comma ,. Change the separator using the separator prop.
<template>
<div>
<CChipInput v-model="tags" separator=";" placeholder="Type and use ; to separate..." />
<p class="mt-2 text-muted">
<small>Use semicolon (;) as separator</small>
</p>
</div>
</template>
<script setup>
import { ref } from 'vue'
import { CChipInput } from '@coreui/vue-pro'
const tags = ref(['Item 1'])
</script> No separator
Set separator to empty string or null to disable automatic chip creation on typing. Users must press Enter.
<template>
<div>
<CChipInput v-model="tags" :separator="null" placeholder="Type and press Enter..." />
<p class="mt-2 text-muted">
<small>Separator disabled - use Enter key to create chips</small>
</p>
</div>
</template>
<script setup>
import { ref } from 'vue'
import { CChipInput } from '@coreui/vue-pro'
const tags = ref(['Press Enter'])
</script> Maximum chips
Limit the number of chips with maxChips.
<template>
<div>
<CChipInput v-model="tags" :max-chips="5" placeholder="Max 5 chips" />
<p class="mt-2 text-muted">
<small>{{ tags.length }}/5 chips - {{ 5 - tags.length }} remaining</small>
</p>
</div>
</template>
<script setup>
import { ref } from 'vue'
import { CChipInput } from '@coreui/vue-pro'
const tags = ref(['One', 'Two', 'Three'])
</script> Create on blur
By default, typing a value and blurring the input creates a chip. Disable this with createOnBlur.
<template>
<div>
<CChipInput v-model="tags" :create-on-blur="false" placeholder="Must press Enter" />
<p class="mt-2 text-muted">
<small>Blurring won't create a chip - you must press Enter</small>
</p>
</div>
</template>
<script setup>
import { ref } from 'vue'
import { CChipInput } from '@coreui/vue-pro'
const tags = ref(["Blur won't create"])
</script> Disabled
Disable the component to prevent interaction.
<template>
<CChipInput disabled :model-value="['Read', 'Only', 'Disabled']" />
</template>
<script setup>
import { CChipInput } from '@coreui/vue'
</script> Readonly
Use readOnly to display chips without allowing changes.
<template>
<CChipInput read-only :model-value="['Read', 'Only', 'Mode']" />
</template>
<script setup>
import { CChipInput } from '@coreui/vue'
</script> Selectable chips
Enable chip selection with the selectable prop. Use the @select event to track selected chips.
<template>
<div>
<CChipInput
v-model="items"
selectable
placeholder="Click chips to select them..."
@select="handleSelect"
/>
<p v-if="selectedItems.length" class="mt-3 text-muted small">
Selected: {{ selectedItems.join(', ') }}
</p>
<p v-else class="mt-3 text-muted small">No chips selected</p>
</div>
</template>
<script setup>
import { ref } from 'vue'
import { CChipInput } from '@coreui/vue-pro'
const items = ref(['Apple', 'Banana', 'Cherry', 'Date', 'Elderberry'])
const selectedItems = ref([])
const handleSelect = (selected) => {
selectedItems.value = selected
}
</script> Form integration
When name is provided, a hidden input is rendered for standard form submission.
<template>
<CForm @submit.prevent="handleSubmit">
<CChipInput v-model="tags" name="tags" label="Tags" placeholder="Add tags..." />
<CButton type="submit" color="primary" class="mt-2">Submit</CButton>
<div v-if="submitted" class="mt-2 text-success">
<small>Form submitted with tags: {{ submittedTags }}</small>
</div>
</CForm>
</template>
<script setup>
import { ref } from 'vue'
import { CForm, CButton } from '@coreui/vue'
import { CChipInput } from '@coreui/vue-pro'
const tags = ref(['Tag1', 'Tag2'])
const submitted = ref(false)
const submittedTags = ref('')
const handleSubmit = () => {
submitted.value = true
submittedTags.value = tags.value.join(', ')
setTimeout(() => {
submitted.value = false
}, 3000)
}
</script> Events
The component emits several events for tracking changes:
@update:modelValue- Main v-model event with updated values array@change- Fires when values change@add- Fires when a chip is added (receives the new value)@remove- Fires when a chip is removed (receives the removed value)@input- Fires when the text input value changes@select- Fires when selected chips change (whenselectableis true)
<template>
<div>
<CChipInput
v-model="tags"
placeholder="Type to trigger events..."
@add="onAdd"
@remove="onRemove"
/>
<div v-if="events.length" class="mt-3 p-3 bg-light rounded">
<h6>Event Log:</h6>
<ul class="list-unstyled small mb-0">
<li v-for="(event, index) in events.slice(-5)" :key="index">
<span class="badge bg-secondary me-2">{{ event.type }}</span>
{{ event.value }}
</li>
</ul>
</div>
</div>
</template>
<script setup>
import { ref } from 'vue'
import { CChipInput } from '@coreui/vue-pro'
const tags = ref(['Demo', 'Events'])
const events = ref([])
const onAdd = (value) => {
events.value.push({ type: 'add', value })
}
const onRemove = (value) => {
events.value.push({ type: 'remove', value })
}
</script> Keyboard behavior
The Chip Input component supports comprehensive keyboard interaction:
In the text input
- Enter: Create a chip from the current input value
- Backspace (when input is empty): Focus the last chip
- Delete (when input is empty): Focus the last chip
- ArrowLeft (at start of input): Focus the last chip
- Escape: Clear the input and blur
On a focused chip
- Backspace / Delete: Remove the chip
- ArrowLeft / ArrowRight: Navigate between chips
- Home / End: Jump to first/last chip
- Enter / Space (if selectable): Toggle chip selection
Usage with v-model
For reactive data binding, use v-model:
<template>
<div>
<CChipInput v-model="tags" placeholder="Type and press Enter..." />
<div class="mt-3 text-body-secondary">Current values: {{ tags.join(', ') || '(empty)' }}</div>
</div>
</template>
<script setup>
import { ref } from 'vue'
import { CChipInput } from '@coreui/vue-pro'
const tags = ref(['Vue', 'React', 'Angular'])
</script> Default values
For initial values without reactive binding, use defaultValue:
<template>
<div>
<CChipInput
:default-value="['HTML', 'CSS', 'JavaScript']"
placeholder="Add more..."
@change="handleChange"
/>
<div class="mt-3 text-body-secondary">Last change: {{ lastChange || 'No changes yet' }}</div>
</div>
</template>
<script setup>
import { ref } from 'vue'
import { CChipInput } from '@coreui/vue-pro'
const lastChange = ref('')
const handleChange = (values) => {
lastChange.value = values.join(', ')
}
</script> Paste support
Users can paste multiple values at once. If the pasted text contains the separator character, it’s automatically split into multiple chips.
<template>
<div>
<CChipInput v-model="tags" placeholder="Try pasting: apple,banana,cherry" />
<p class="mt-2 text-muted">
<small>Paste comma-separated values to create multiple chips at once</small>
</p>
</div>
</template>
<script setup>
import { ref } from 'vue'
import { CChipInput } from '@coreui/vue-pro'
const tags = ref([])
</script> Examples with real-world scenarios
Email recipients
<template>
<CChipInput v-model="recipients" label="To:" placeholder="Add recipients..." separator=";" />
</template>
<script setup>
import { ref } from 'vue'
import { CChipInput } from '@coreui/vue'
const recipients = ref(['[email protected]'])
</script> Skills selector
<template>
<CChipInput
v-model="skills"
label="Your skills"
:max-chips="10"
placeholder="Add your skills..."
:chip-class-name="'chip-primary'"
/>
</template>
<script setup>
import { ref } from 'vue'
import { CChipInput } from '@coreui/vue-pro'
const skills = ref(['JavaScript', 'Vue.js', 'TypeScript'])
</script> Product tags
<template>
<CChipInput
v-model="tags"
label="Product tags"
placeholder="Add tags..."
size="sm"
:chip-class-name="'chip-info'"
/>
</template>
<script setup>
import { ref } from 'vue'
import { CChipInput } from '@coreui/vue-pro'
const tags = ref(['electronics', 'gadgets', 'tech'])
</script>