Chip
UiChip renders a single tappable chip. UiChipGroup renders a set of chips from an options array and manages selection with v-model — use it for filters and tag pickers. For static status labels, use UiBadge instead.
Variant and color
Chips have two independent axes. variant styles the container the chip rests in; color is the fill it takes once it is selected.
| Prop | Values | When it applies |
|---|---|---|
variant | outline (default), elevated | Always — it is the resting container |
color | primary (default), secondary, neutral | Only while the chip is selected |
An unselected chip never carries a color, so a group reads as a set of empty containers until something is picked. Selection is what paints it.
<template>
<!-- Outline container, primary fill once selected -->
<UiChip text="Any time" selected />
<!-- Elevated containers keep their shadow through selection -->
<UiChip text="Nonstop" variant="elevated" selected />
<!-- Neutral fill for low-emphasis filters -->
<UiChip text="Economy" color="neutral" selected />
</template>
UiChipGroup accepts both and applies them to every option it renders:
<template>
<UiChipGroup
v-model="sort"
:options="options"
variant="elevated"
color="neutral"
aria-label="Sort results"
/>
</template>
Single-select filter chips
In single mode, modelValue is string | null. Clicking the selected chip deselects it.
<script setup lang="ts">
import { ref } from 'vue'
const status = ref<string | null>(null)
const options = [
{ id: 'active', text: 'Active' },
{ id: 'paused', text: 'Paused' },
{ id: 'archived', text: 'Archived' },
]
</script>
<template>
<UiChipGroup v-model="status" :options="options" aria-label="Filter by status" />
</template>
Multi-select chips
Set multiple to model a string[].
<script setup lang="ts">
import { ref } from 'vue'
const tags = ref<string[]>([])
const options = [
{ id: 'vue', text: 'Vue', iconCode: '' },
{ id: 'nuxt', text: 'Nuxt' },
{ id: 'ts', text: 'TypeScript' },
]
</script>
<template>
<UiChipGroup v-model="tags" :options="options" multiple aria-label="Filter by tag" />
</template>
Closable tag list
Set closable on an option to render a trailing remove button. UiChipGroup emits remove with the option id — you own the removal logic.
<script setup lang="ts">
import { ref } from 'vue'
const tags = ref([
{ id: '1', text: 'Design', closable: true },
{ id: '2', text: 'Frontend', closable: true },
])
function onRemove(id: string) {
tags.value = tags.value.filter(tag => tag.id !== id)
}
</script>
<template>
<UiChipGroup :options="tags" @remove="onRemove" />
</template>
Use UiChip directly
<template>
<UiChip text="Filter chip" icon-code="" @click="onClick" />
<UiChip text="Selected" selected />
<UiChip text="Elevated" variant="elevated" />
<UiChip text="Disabled" disabled />
<UiChip text="Removable" closable close-label="Remove tag" @remove="onRemove" />
</template>
UiChip props
| Prop | Type | Default | Description |
|---|---|---|---|
id | string | null | — | Rendered unchanged on the chip's root element. |
text | string | null | — | Display text label. |
iconCode | string | null | — | Leading Material Symbols code point. Replaced by a check mark while selected. |
variant | 'outline' | 'elevated' | 'outline' | Container style while the chip is unselected. |
color | 'primary' | 'secondary' | 'neutral' | 'primary' | Fill applied once the chip is selected. No effect while unselected. |
selected | boolean | false | Applies the color fill and swaps the leading icon for a check mark. |
disabled | boolean | false | Disables the chip. |
closable | boolean | false | Renders a trailing remove button (input-chip behavior). |
textOnly | boolean | false | Renders the borderless text-only chip variant. |
closeLabel | string | 'Remove' | Accessible label for the remove button. |
customClass | string | string[] | Record<string, boolean> | null | — | Extra classes. |
Emits: click (MouseEvent) when the chip body is clicked; remove when the trailing remove button of a closable chip is clicked.
Slots: default renders after the text (e.g. a trailing badge), in addition to text.
UiChipGroup props
| Prop | Type | Default | Description |
|---|---|---|---|
options | IChipOption[] | — | Chip options: { id, text, iconCode?, disabled?, closable? }. |
variant | 'outline' | 'elevated' | 'outline' | Container style applied to every option. |
color | 'primary' | 'secondary' | 'neutral' | 'primary' | Selected fill applied to every option. |
modelValue | string | string[] | null | — | Selected id (single) or ids (multiple). |
multiple | boolean | false | Allows selecting multiple chips. |
ariaLabel | string | null | — | ARIA label describing the group. |
customClass | string | string[] | Record<string, boolean> | null | — | Extra classes for the group container. |
Emits: update:modelValue when the selection changes; remove with the option id when a closable option's remove button is clicked.
UiChipGroup renders a role="group" container. In single-select mode, clicking the currently selected chip clears the selection (sets modelValue to null).CSS variables
Set these on :root, or on any wrapper to restyle only the chips inside it. Selected chips keep the theme's tonal colors, and the elevated and text variants their own surface and border. Hover and pressed backgrounds come from the shared state layer.
:root {
--cffy-chip-radius: var(--cffy-radius-full);
}
| Variable | Default | Controls |
|---|---|---|
--cffy-chip-bg-color / --cffy-chip-color | transparent / --cffy-on-background | Background and text |
--cffy-chip-border-color | --cffy-outline-button | Border |
--cffy-chip-radius | --cffy-shape-control | Corners |