Chip
Vue data-displayCompact, removable tag — typically used inside `tags-input` or as a filter pill. Seven variants (`default`, `filled`, `outlined`, `elevated`, `success`, `warning`, `destructive`), three sizes, and an optional close button.
Also available for React ->Installation
$ pnpm dlx shadcn-vue@latest add https://uipkge.dev/r/vue/chip.json$ npx shadcn-vue@latest add https://uipkge.dev/r/vue/chip.json$ yarn dlx shadcn-vue@latest add https://uipkge.dev/r/vue/chip.json$ bunx shadcn-vue@latest add https://uipkge.dev/r/vue/chip.json
Or with the named registry:
npx shadcn-vue@latest add @uipkge/chip
Examples
Props
| Name | Type / Values | Default | Required |
|---|---|---|---|
variant | 'default''filled''outlined''elevated''success''warning''destructive' | — | optional |
size | 'sm''default''lg' | — | optional |
class | HTMLAttributes['class'] | — | optional |
closable | boolean | — | optional |
Dependencies
Files (4)
-
app/components/ui/chip/Chip.vue 1 kB
<script setup lang="ts"> import type { HTMLAttributes } from 'vue' import { X } from 'lucide-vue-next' import { cn } from '@/lib/utils' import { chipVariants } from './chip.variants' // Inlined unions: SFC compiler can't extract runtime props from // `ChipVariants['variant'] | ['size']`. const props = defineProps<{ variant?: 'default' | 'filled' | 'outlined' | 'elevated' | 'success' | 'warning' | 'destructive' size?: 'sm' | 'default' | 'lg' class?: HTMLAttributes['class'] closable?: boolean }>() const emit = defineEmits<{ close: [] }>() </script> <template> <span :class="cn(chipVariants({ variant, size }), props.class)"> <slot /> <button v-if="closable" type="button" aria-label="Remove item" class="focus-visible:ring-ring hover:bg-foreground/10 ml-0.5 inline-flex min-h-6 min-w-6 items-center justify-center rounded-full focus-visible:ring-1 focus-visible:outline-none" @click.stop="emit('close')" > <X class="size-3" aria-hidden="true" /> </button> </span> </template> -
app/components/ui/chip/ChipGroup.vue 1.5 kB
<script setup lang="ts"> import type { HTMLAttributes } from 'vue' const props = withDefaults( defineProps<{ class?: HTMLAttributes['class'] selected?: string[] multiple?: boolean filter?: boolean column?: boolean mandatory?: boolean max?: number disabled?: boolean }>(), { selected: () => [], multiple: false, filter: false, column: false, mandatory: false, disabled: false, }, ) const emit = defineEmits<{ 'update:selected': [value: string[]] }>() function isSelected(value: string) { return props.selected.includes(value) } function toggle(value: string) { if (props.disabled) return let newSelected: string[] if (props.multiple) { if (isSelected(value)) { newSelected = props.selected.filter((v) => v !== value) } else { if (props.max && props.selected.length >= props.max) { newSelected = [...props.selected.slice(1), value] } else { newSelected = [...props.selected, value] } } } else { if (isSelected(value) && !props.mandatory) { newSelected = [] } else { newSelected = [value] } } emit('update:selected', newSelected) } </script> <template> <div :class="['flex flex-wrap gap-2', column ? 'flex-col' : '', filter ? 'flex-wrap' : '', props.class]" :data-chip-group="true" :data-multiple="multiple || undefined" :data-filter="filter || undefined" > <slot :selected="selected" :multiple="multiple" :filter="filter" :is-selected="isSelected" :toggle="toggle" /> </div> </template> -
app/components/ui/chip/chip.variants.ts 1.6 kB
import type { VariantProps } from 'class-variance-authority' import { cva } from 'class-variance-authority' /** * Variant definitions live in their own file (rather than the package * `index.ts`) so consuming Vue SFCs can import without creating a circular * dependency through the index. See card.variants.ts for the canonical * example + the SSR symptom that motivated the split. */ export const chipVariants = cva( 'inline-flex items-center justify-center gap-1 rounded-full text-xs font-medium w-fit whitespace-nowrap shrink-0 transition-colors duration-200 overflow-hidden focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2', { variants: { variant: { default: 'bg-muted text-muted-foreground hover:bg-muted/80', filled: 'bg-primary text-primary-foreground hover:bg-primary/90', outlined: 'border border-current bg-transparent hover:bg-accent', elevated: 'bg-primary/10 text-primary shadow-sm hover:bg-primary/20', success: 'bg-[var(--success)]/10 text-[var(--success)] dark:text-[var(--success)] hover:bg-[var(--success)]/20', warning: 'bg-[var(--warning)]/10 text-[var(--warning)] dark:text-[var(--warning)] hover:bg-[var(--warning)]/20', destructive: 'bg-destructive/10 text-destructive dark:text-destructive hover:bg-destructive/20', }, size: { sm: 'h-6 px-2 text-xs', default: 'h-7 px-2.5 text-xs', lg: 'h-8 px-3 text-sm', }, }, defaultVariants: { variant: 'default', size: 'default', }, }, ) export type ChipVariants = VariantProps<typeof chipVariants> -
app/components/ui/chip/index.ts 0.3 kB
export { default as Chip } from './Chip.vue' export { default as ChipGroup } from './ChipGroup.vue' // Re-export variant API from the sibling file (kept separate to avoid the // Component.vue <-> index.ts circular import that broke dev SSR for Card). export { chipVariants, type ChipVariants } from './chip.variants'
Raw manifest: https://uipkge.dev/r/vue/chip.json