nili/ui
All components

Tag

Overview
10 exports5 variant axes15 props4 files
import { 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.

StrokeGray
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.

static
DefaultSelectedDisabledSelected
selectable (try it)
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.

IconAda LovelaceIranWith sublabel24
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.

DesignEngineeringResearchMarketing
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>
  )
}