Tag group
Tags on one line: as many as fit, then +N with the rest in a tooltip. The row never wraps and never grows.
Playground
Change the controls to try each prop. The preview fills the group with five skills; the code under it lists only the props you changed.
import { TagGroup } from '@/ui/tag-group';<TagGroup label="Skills" className="w-36" />Fit and overflow
When every tag fits there is no count. Otherwise the group shows whole tags only, then +N; a tag is never cut in half. Tags sit 4px apart, and the group measures again when its width changes, such as when a column is resized.
import { Tag } from '@/ui/tag';
import { TagGroup } from '@/ui/tag-group';
const skills = ['Python', 'Spark', 'SQL', 'Airflow', 'dbt'];
export default function TagGroupFitAndOverflow() {
return (
<div className="flex flex-col gap-150">
<TagGroup label="Skills" className="w-70">
{skills.slice(0, 3).map((skill) => (
<Tag key={skill}>{skill}</Tag>
))}
</TagGroup>
<TagGroup label="Skills" className="w-36">
{skills.map((skill) => (
<Tag key={skill}>{skill}</Tag>
))}
</TagGroup>
</div>
);
}One long tag
Only the first tag may shorten, with an ellipsis, so something always shows.
import { Tag } from '@/ui/tag';
import { TagGroup } from '@/ui/tag-group';
const sectors = ['Machine learning infrastructure', 'Fintech', 'Payments', 'Lending', 'Insurance'];
export default function TagGroupOneLongTag() {
return (
<TagGroup label="Sectors" className="w-40">
{sectors.map((sector) => (
<Tag key={sector}>{sector}</Tag>
))}
</TagGroup>
);
}Tags with an option colour
An option with a colour keeps it as the tag's 6px dot; the tag stays white with ink text. The colour is the option's, never the group's.
import { Tag } from '@/ui/tag';
import { TagGroup } from '@/ui/tag-group';
export default function TagGroupOptionColours() {
return (
<TagGroup label="Labels" className="w-60">
<Tag color="blue">Fintech</Tag>
<Tag color="plum">Series B</Tag>
<Tag color="teal">London</Tag>
<Tag color="green">Hiring</Tag>
</TagGroup>
);
}In a table cell
Pass inCell inside a table. The cell is the focus stop, so +N leaves the Tab order; the cell's editor shows every tag.
import { Tag } from '@/ui/tag';
import { TagGroup } from '@/ui/tag-group';
const skills = ['Python', 'Spark', 'SQL', 'Airflow', 'dbt'];
export default function TagGroupInACell() {
return (
<div role="grid" aria-label="Candidates" className="w-120 rounded-large bg-surface text-body shadow-[inset_0_0_0_1px_var(--color-border)]">
<div role="row" className="flex h-9 items-center">
<span role="gridcell" className="w-45 shrink-0 px-150 font-medium">
Maya Chen
</span>
<span role="gridcell" tabIndex={0} className="flex h-9 w-50 items-center border-s border-border px-150 outline-none focus-visible:outline-2 focus-visible:-outline-offset-2 focus-visible:outline-border-focused focus-visible:outline-solid">
<TagGroup label="Skills" inCell>
{skills.map((skill) => (
<Tag key={skill}>{skill}</Tag>
))}
</TagGroup>
</span>
</div>
</div>
);
}Tag
Descriptive metadata someone chose: Inbox tags, skills, sectors, guests on a meeting. An outlined chip with a colour dot. It labels a record; it never says where the record stands.
Truncated text
One line that ends in an ellipsis when it runs out of room. The full text shows in a tooltip, and only while the line is clipped.