Tag
FreeA removable label used for categorisation, filtering, and multi-value inputs. Includes an optional close button for removal. Tags can be interactive (clickable to filter) or static (display only). Used in filter bars, form fields, and content metadata.
12 variants
Variants
| Variant | Description | When to use |
|---|---|---|
| Default | Neutral tag with optional close button for removal. | Use for general categorisation — skills, topics, filters. |
| Removable | ||
| Selectable |
Usage Guidelines
Keep tag labels concise — one to three words.
Use tags for status information — use Badge instead.
Include a close button for removable tags with aria-label="Remove [tag name]".
Make tags too small to read or tap — minimum height 28px.
Use consistent tag styles within a group.
Mix removable and non-removable tags in the same group without visual distinction.
Allow tags to wrap to multiple lines in constrained containers.
Use more than 6 colour variants — limit categories to maintain scannability.
Code
<div class="lex-tag-group" role="list" aria-label="Selected skills">
<span class="lex-tag" role="listitem">
<span class="lex-tag__label">React</span>
<button class="lex-tag__remove" aria-label="Remove React">
<svg width="14" height="14" viewBox="0 0 24 24" fill="none"
stroke="currentColor" stroke-width="2">
<line x1="18" y1="6" x2="6" y2="18" />
<line x1="6" y1="6" x2="18" y2="18" />
</svg>
</button>
</span>
<span class="lex-tag" role="listitem">
<span class="lex-tag__label">TypeScript</span>
<button class="lex-tag__remove" aria-label="Remove TypeScript">
<svg width="14" height="14" viewBox="0 0 24 24" fill="none"
stroke="currentColor" stroke-width="2">
<line x1="18" y1="6" x2="6" y2="18" />
<line x1="6" y1="6" x2="18" y2="18" />
</svg>
</button>
</span>
</div>.lex-tag {
display: inline-flex;
align-items: center;
gap: var(--lex-tag-gap, 4px);
padding: 0 var(--lex-tag-px, 10px);
height: var(--lex-tag-height, 28px);
font-size: var(--lex-tag-font-size, 13px);
font-weight: 500;
border-radius: var(--lex-tag-radius, var(--lex-radius-sm));
background: var(--lex-tag-bg, var(--lex-bg-surface-subtle));
color: var(--lex-tag-text, var(--lex-text-primary));
line-height: 1;
}
.lex-tag__remove {
display: inline-flex;
align-items: center;
justify-content: center;
width: 18px;
height: 18px;
border: none;
background: transparent;
border-radius: var(--lex-radius-xxs);
cursor: pointer;
color: var(--lex-tag-remove-color, var(--lex-text-muted));
transition: background 150ms ease, color 150ms ease;
}
.lex-tag__remove:hover {
background: var(--lex-tag-remove-bg-hover, rgba(0, 0, 0, 0.08));
color: var(--lex-tag-remove-color-hover, var(--lex-text-primary));
}// Using Lexicon CSS classes with React
export function SkillTags() {
const [skills, setSkills] = useState(['React', 'TypeScript', 'Node.js']);
const removeSkill = (skill: string) => {
setSkills(prev => prev.filter(s => s !== skill));
};
return (
<TagGroup label="Selected skills">
{skills.map(skill => (
<Tag key={skill} onRemove={() => removeSkill(skill)}>
{skill}
</Tag>
))}
</TagGroup>
);
}Design Tokens
| Token | Value (dark) | Value (light) | CSS property |
|---|---|---|---|
| --lex-tag-bg | — | — | bg |
| --lex-tag-text | — | — | text |
| --lex-tag-border | — | — | border |
| --lex-tag-radius | — | — | radius |
| --lex-tag-padding | — | — | padding |
Accessibility
- Remove buttons must have aria-label="Remove [tag name]" for screen readers.
- Tag groups should use role="list" with individual role="listitem" tags.
- Provide a visible group label via aria-label on the container.
- When a tag is removed, move focus to the next tag or the container.