Tag
Overviewimport { Tag, TagGroup } from '@nili/ui';This is the library’s own overview page, rendered live. Switch the language or the theme in the header and it follows.
Appearances
Two treatments — Stroke on white, or Gray on a filled chip.
import { Tag } from "@nili/ui"
export function Example() {
return (
<>
<Tag appearance="stroke">Stroke</Tag>
<Tag appearance="gray">Gray</Tag>
</>
)
}States
selected marks an applied tag and adds aria-pressed when the tag is selectable. disabled greys it out and drops it from the tab order.
import { Tag } from "@nili/ui"
export function Example() {
const [selected, setSelected] = useState<string[]>([])
return (
<>
<Tag
selected={selected.includes("design")}
onSelect={() => toggle("design")}
>
Design
</Tag>
<Tag disabled>{t('states.disabled')}</Tag>
</>
)
}Leading slot
startAdornment covers every Figma Type in one prop — an icon, an avatar, a flag, a brand mark. As an enum they would be mutually exclusive, and a seventh kind would need a library release.
import { Tag, Avatar, CountryFlag, Icon } from "@nili/ui"
import { RiPriceTag3Line } from "@remixicon/react"
export function Example() {
return (
<>
<Tag startAdornment={<Icon icon={RiPriceTag3Line} />}>
{t('slot.icon')}
</Tag>
<Tag startAdornment={<Avatar size="3xs" name="Ada Lovelace" tone="blue" />}>
Ada Lovelace
</Tag>
<Tag startAdornment={<CountryFlag code="ir" size="xs" />}>
{t('slot.iran')}
</Tag>
<Tag sublabel="24">{t('slot.withSublabel')}</Tag>
</>
)
}Dismissible
onDismiss shows the remove button. dismissLabel is required alongside it — an ✕ has no accessible name, and “button” is all a screen reader would get.
import { Tag, TagGroup } from "@nili/ui"
export function Example() {
const [tags, setTags] = useState(["Design", "Engineering"])
return (
<TagGroup label={t('group.filters')}>
{tags.map((tag) => (
<Tag
key={tag}
onDismiss={() => setTags((c) => c.filter((t) => t !== tag))}
dismissLabel={`Remove ${tag}`}
>
{tag}
</Tag>
))}
</TagGroup>
)
}Tag
extends Omit< ComponentPropsWithoutRef<'span'>, 'onSelect' >
Variant axes — from the component’s cva definition
| Prop | Type | Default | Notes |
|---|---|---|---|
| appearance | stroke | gray | stroke | |
| disabled | boolean | false | |
| selected | boolean | false | The tag is currently applied — adds `aria-pressed` when selectable. |
| dismissible | 'true' | 'false' | false |
Other props
| Prop | Type | Default | Notes |
|---|---|---|---|
| children | ReactNode | — | |
| aria-label | string | — | |
| startAdornment | ReactNode | — | Leading slot. Covers all six of Figma's `Type` values — Left Icon, Avatar, Country, Brand, Company — without making them mutually exclusive. |
| sublabel | ReactNode | — | Muted text after the label. Figma's "Sublabel". |
| onSelect | () => void | — | Makes the label a button — a filter chip you can toggle. |
| onDismiss | () => void | — | Shows the remove button. |
| dismissLabel | string | — | Accessible name for the remove button. Required alongside `onDismiss`: an ✕ has no accessible name, and "button" is all a screen reader would get. |
TagContent
internalVariant axes — from the component’s cva definition
| Prop | Type | Default | Notes |
|---|---|---|---|
| interactive | 'true' | 'false' | false |
TagDismiss
internalTagGroup
extends ComponentPropsWithoutRef<'div'>
Other props
| Prop | Type | Default | Notes |
|---|---|---|---|
| children | ReactNode | — | |
| aria-label | string | — | |
| label | string | — | Accessible name for the set, e.g. `'Tags'`. |