Display
10 components for showing — not capturing — content. Static surfaces, badges, loading placeholders, dividers.
Avatar
interface Props {
src?: string
alt?: string
fallback?: string // initials when src fails
size?: 'xs' | 'sm' | 'md' | 'lg' // 'md'
}<Avatar :src="user.avatar" :fallback="user.name" />
<Avatar fallback="AB" size="lg" />Badge
interface Props {
color?: 'primary' | 'neutral' | 'success' | 'warning' | 'error' | 'info' // 'primary'
variant?: 'solid' | 'soft' | 'subtle' | 'outline' // 'soft'
size?: 'xs' | 'sm' | 'md' // 'sm'
label?: string
}Slot default overrides label.
<Badge color="success">Live</Badge>
<Badge color="warning" variant="outline">Draft</Badge>
<Badge :label="`${count} new`" />Chip
Like a Badge but with optional icon + remove action. Use for selected tags, filter pills.
interface Props {
label?: string
color?: string // CSS color, named, or hex
removable?: boolean
icon?: string
size?: 'sm' | 'md' | 'lg'
variant?: 'solid' | 'soft' | 'outline' // 'soft'
}Emits remove when the × is clicked.
<Chip
v-for="tag in tags"
:key="tag"
:label="tag"
removable
@remove="removeTag(tag)"
/>Card
Surface container with optional header / body / footer regions and a hover-revealed action strip.
interface Props {
title?: string
description?: string
variant?: 'default' | 'outline' | 'muted' // 'default'
hoverable?: boolean
interactive?: boolean // cursor-pointer
}Slots: header (overrides title/description), accessory (right side of header), default (body), footer, footer-end, actions (hover-revealed).
<Card title="Marketing 2026" description="Shared with 4 people" hoverable interactive>
<template #accessory>
<Badge color="info">Org</Badge>
</template>
<p>Last opened 2 days ago.</p>
<template #actions>
<Button variant="ghost" icon="i-lucide-edit" />
<Button variant="ghost" color="error" icon="i-lucide-trash" />
</template>
</Card>Icon
Iconify wrapper. Accepts the i-lucide-check / i-heroicons-home shorthand and rewrites to Iconify's lucide:check / heroicons:home.
interface Props {
name?: string
}<Icon name="i-lucide-folder" />
<Icon name="mdi:robot" /> <!-- raw iconify also works -->Invalid / sentence-y values render nothing rather than throw.
Kbd
Render a keyboard shortcut. Auto-maps cmd → ⌘ on Mac, Ctrl on Win/Linux. Resolves alt / option → ⌥, shift → ⇧, etc.
interface Props {
keys: string | string[]
size?: 'xs' | 'sm' | 'md' // 'sm'
}<Kbd keys="cmd+k" /> <!-- ⌘ K -->
<Kbd :keys="['shift', '/']" /> <!-- ⇧ / -->Progress
Bar (horizontal) or circle (SVG). Indeterminate mode for unknown duration.
interface Props {
value?: number // 0
max?: number // 100
color?: string // brand by default
size?: 'xs' | 'sm' | 'md' | 'lg'
indeterminate?: boolean
label?: boolean // show "37%" inline
variant?: 'bar' | 'circle' // 'bar'
}<Progress :value="uploaded" :max="total" label />
<Progress variant="circle" indeterminate size="lg" />Skeleton
Pulsing loading placeholder. Rectangular, rounded, circle, or multi-line text.
interface Props {
width?: string // CSS length; default '100%'
height?: string // CSS length; default '1rem'
rounded?: boolean
circle?: boolean
lines?: number // when >0, renders that many text-line skeletons
}<Skeleton circle width="2.5rem" />
<Skeleton :lines="3" />
<Skeleton height="120px" rounded />Separator
Horizontal or vertical divider, with optional centered label.
interface Props {
orientation?: 'horizontal' | 'vertical' // 'horizontal'
label?: string
color?: 'default' | 'accent' | 'success' | 'warning' | 'error' | 'info' // 'default'
}Slot default overrides the label for custom content.
<Separator />
<Separator label="OR" />
<Separator orientation="vertical" color="accent" />Empty
Centered empty-state placeholder. Use inside lists / boards when there's nothing to show yet.
interface Props {
icon?: string
title?: string
description?: string
}Slot default is the action area.
<Empty
icon="i-lucide-folder-open"
title="No folders yet"
description="Create your first folder to start organizing."
>
<Button @click="newFolder">New folder</Button>
</Empty>