Components

Chip

Interactive filters, tags, and inputs with UiChip and UiChipGroup.

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.

PropValuesWhen it applies
variantoutline (default), elevatedAlways — it is the resting container
colorprimary (default), secondary, neutralOnly 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: '&#xe86f;' },
  { 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="&#xe152;" @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

PropTypeDefaultDescription
idstring | null—Rendered unchanged on the chip's root element.
textstring | null—Display text label.
iconCodestring | 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.
selectedbooleanfalseApplies the color fill and swaps the leading icon for a check mark.
disabledbooleanfalseDisables the chip.
closablebooleanfalseRenders a trailing remove button (input-chip behavior).
textOnlybooleanfalseRenders the borderless text-only chip variant.
closeLabelstring'Remove'Accessible label for the remove button.
customClassstring | 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

PropTypeDefaultDescription
optionsIChipOption[]—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.
modelValuestring | string[] | null—Selected id (single) or ids (multiple).
multiplebooleanfalseAllows selecting multiple chips.
ariaLabelstring | null—ARIA label describing the group.
customClassstring | 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);
}
VariableDefaultControls
--cffy-chip-bg-color / --cffy-chip-colortransparent / --cffy-on-backgroundBackground and text
--cffy-chip-border-color--cffy-outline-buttonBorder
--cffy-chip-radius--cffy-shape-controlCorners
Copyright © 2026