Tag
The single non-interactive marker: a compact pill carrying a status, a label, or a piece of metadata.
Implementation previewEvery example. In one place.
Explore every named example, including states, compositions, and theme variants.
Example source
packages/design-system/src/components/primitives/Tag/Tag.stories.tsxExport PlaygroundImplementation preview Local Storybook build 0.2.0-preview.1. Source specification status does not approve this runtime.
Stories + source JSON ↗Local specification source status: preview. Implementation preview pending sign-off.
The single non-interactive marker: a compact pill carrying a status, a label, or a piece of metadata.
Implementation API 1 entry point · source-derived preview
Read the actual callable API and preserve its composition constraints. Each union branch is a complete alternative; props marked forbidden cannot be supplied.
import { Tag } from '@cloakedinc/design-system';TagTagProps
packages/design-system/src/components/primitives/Tag/Tag.tsx:39
| Prop | Type | Presence | Notes |
|---|---|---|---|
tone | "neutral" | "info" | "success" | "warning" | "danger" | Required | Semantic status treatment. `neutral` reads as chrome rather than an outcome. |
emphasis | TagEmphasis | Required | Fill weight: `solid` fills with the tone, `subtle` its tint, `outline` a border on transparent. |
contrast | TagContrast | undefined | Optional | Retunes a `neutral` marker for a dark or branded surface. A toned marker keeps its tone.Source default: 'default' |
dot | boolean | "neutral" | "info" | "success" | "warning" | "danger" | undefined | Optional | Leading dot. `true` matches the label color; a tone colors the dot independently. |
leading | React.ReactNode | Optional | Optional leading visual, usually an `Icon` or `SFIcon`. |
fullWidth | boolean | undefined | Optional | Stretches the tag to its parent width, keeping content centered. |
children | React.ReactNode | Required | |
className | string | undefined | Optional | |
style | React.CSSProperties | undefined | Optional | |
testId | string | undefined | Optional | Selector on the outer `<span>`; the dot and the label inside carry none. |
Only explicit destructured parameter initializers are extracted. Other runtime defaults remain in implementation source.
Overview
The single non-interactive marker. A Tag is a compact pill carrying a status, a label, or a piece of
metadata. tone sets the meaning, emphasis sets how much it stands out, and contrast retunes the
chrome for a dark or branded surface.
Tag or Chip
A Tag renders a <span> with no role and no focus stop. A Chip renders a button that takes focus and
responds to a tap. That difference is in the DOM and the accessibility tree, not in the styling, which
is why they are separate components rather than one component with an onPress prop.
So the question is never how the pill looks. It is whether tapping it does anything.
Tone and emphasis
tone carries the Status tone axis. emphasis picks the surface.
neutral is the exception worth understanding: a neutral marker is chrome rather than an outcome, so
it leaves the status ramp and uses the surface roles instead. That is what makes a neutral pill read
as a label rather than as a grey status.
| Tone | `subtle` | `solid` | `outline` |
|---|---|---|---|
neutral | --cds-bg-subtle + primary text | --cds-bg-inverse + inverse text | --cds-divider border |
| any other | tone subtle fill + tone solid text | tone solid fill + inverse text | tone solid border and text |
tone is the Status tone axis and nothing else. A marker carrying product identity rather than an
outcome does not belong here.
The dot
dot takes a boolean or a tone. A bare dot matches the label color. Passing a tone colors the dot
on its own, which is how a marker shows a green indicator beside a neutral label.
Recipes
The design system owns the axes. Product concepts own their prop combinations. When a preset appears
in more than one place, wrap it in the feature that uses it rather than adding a part here, the way
ActivityStatusTag wraps its tone and glyph.
A running or stopped state appears twice, at two prominences. Reach for the ambient row when the marker sits beside a title that already says what it describes, and the announced row when the state is the thing the surface is about.
| Product concept | Props |
|---|---|
| Running, ambient | tone='neutral' emphasis='subtle' dot='success' |
| Stopped, ambient | tone='neutral' emphasis='subtle' dot |
| Running, announced | tone='success' emphasis='solid' dot='neutral' |
| Stopped, announced | tone='neutral' emphasis='solid' dot='neutral' |
| Overdue | tone='danger' emphasis='solid' |
| Complete / done | tone='success' emphasis='subtle' |
| Needs help | tone='warning' emphasis='solid' leading={...} |
| Metadata / category | tone='neutral' emphasis='subtle' |
| Count | tone='neutral' emphasis='subtle' |
| AI-assisted | tone='info' emphasis='subtle' leading={...} |
| Neutral on a dark widget | add contrast='inverse' |
Reach for something else
| Instead of a Tag | Use | Because |
|---|---|---|
| A tappable pill | Chip | It needs a role and a focus stop. |
| A removable value | Chip | The remove affordance is a second button. |
| A bare dot and label | StatusIndicator | No pill behind it; it rides inside a row. |
| An up or down trend | Card.Delta | A delta is a change in a number, not a state. |
| A multi-line callout | Banner | It is a block of feedback, not a marker. |
| A notification count | Avatar or tab slot | An anchored count belongs on the element it counts. |
Sizes
There is no size prop. Figma draws every marker at one height, and the two sizes the old
Tag.Status carried differed only in horizontal inset.
On a dark surface
contrast='inverse' resolves a neutral marker to the inverse roles, so the chrome keeps its
treatment on a surface that is dark in both themes. It has no effect on a toned marker: the status
fills are opaque in both themes and already read on a dark surface, so a success or danger
marker keeps its tone rather than losing it to grey chrome.
Full width
fullWidth stretches the marker to its parent, for a card footer that carries a state across the
whole row.
Do and don’t
| Guidance | Example |
|---|---|
| Do | Use Tag for anything the user only reads: a status, a category, a timestamp, a count. |
| Don’t | Give a Tag an onClick through className or a wrapper. Users try to tap things that look tappable, so a marker
that does something must be a Chip. |
Component specification
$schema
../../../specs/component-spec.schema.jsonParts
- Id
- root
- Label
- Root
- Description
- Inline pill that carries the emphasis surface, tone color, and contrast treatment.
- Required
- true
- Id
- leading
- Label
- Leading
- Description
- Optional leading visual, usually an Icon or SFIcon.
- Id
- dot
- Label
- Dot
- Description
- Optional indicator dot. Matches the label color by default, or takes its own tone.
- Id
- label
- Label
- Label
- Description
- Body-small marker text.
Allowed Design Choices
- Variants
- Solid
- Label
- Solid
- Description
- Saturated fill for the one marker that must stand out.
- Subtle
- Label
- Subtle
- Description
- Tinted fill for inline metadata and statuses.
- Outline
- Label
- Outline
- Description
- Border-only pill for quiet markers on busy surfaces.
- Sizes
- Tones
- Neutral
- Label
- Neutral
- Description
- Chrome rather than an outcome. Leaves the status ramp for the surface roles.
- Info
- Label
- Info
- Success
- Label
- Success
- Warning
- Label
- Warning
- Danger
- Label
- Danger
Variants
- Id
- solid
- Label
- Solid
- Description
- Solid tone fill with inverse text. Neutral resolves to the inverse surface.
- Platforms
- ios
- android
- web
- Id
- subtle
- Label
- Subtle
- Description
- Tinted tone fill with tone-colored text. Neutral resolves to the subtle surface with primary text.
- Platforms
- ios
- android
- web
- Id
- outline
- Label
- Outline
- Description
- Transparent fill with a tone-colored border and text. Neutral borders on the divider token.
- Platforms
- ios
- android
- web
Sizes
None specifiedMeasurements
- Id
- min-height
- Label
- Minimum height
- Kind
- exact
- Token
- --cds-size-24
- Value
- 24
- Unit
- px
- Applies To
- root
- Id
- block-padding
- Label
- Block padding
- Kind
- exact
- Token
- --cds-space-4
- Value
- 4
- Unit
- px
- Applies To
- root
- Id
- inline-padding
- Label
- Inline padding
- Kind
- exact
- Token
- --cds-space-12
- Value
- 12
- Unit
- px
- Applies To
- root
- Id
- content-gap
- Label
- Content gap
- Kind
- exact
- Token
- --cds-space-8
- Value
- 8
- Unit
- px
- Applies To
- root
- leading
- dot
- label
- Id
- dot-size
- Label
- Dot size
- Kind
- exact
- Token
- --cds-size-8
- Value
- 8
- Unit
- px
- Applies To
- dot
Layout
- Alignment
- Leading visual, dot, and label sit on the marker center line, centered on the main axis so fullWidth stays balanced.
- Flow
- One inline pill sized to its content with a fully rounded radius. There is no size axis: Figma draws every marker at one height.
- Notes
- Use Chip when the pill must be tappable or removable.
- Use StatusIndicator for a bare dot-plus-label with no pill behind it.
- Use Card.Delta for a trend delta such as an up or down arrow beside a number.
- Use Banner or an inset Card for a multi-line callout.
Typography And Color
- Typography
- Label
- Marker text
- Description
- Uses the body-small ramp for the label.
- Token
- --cds-type-body-small-size
- Colors
- Label
- Subtle fill
- Description
- The chip fill backs the subtle emphasis: a tint in light, a solid hue in dark.
- Token
- --cds-bg-status-info
- Label
- Subtle text
- Description
- The chip label pairs with the chip fill: the hue in light, white in dark.
- Token
- --cds-text-on-status-info
- Label
- Solid fill
- Description
- Tone solid backs the solid emphasis and the outline border.
- Token
- --cds-status-info-solid
- Label
- Solid text
- Description
- Inverse text sits on a solid tone fill.
- Token
- --cds-text-inverse
- Label
- Neutral subtle fill
- Description
- A neutral marker is chrome, so its tone entry is a surface grey rather than the grey status hue.
- Token
- --cds-bg-status-neutral
- Label
- Neutral subtle text
- Description
- Pairs with the neutral subtle fill.
- Token
- --cds-text-on-status-neutral
- Label
- Neutral solid fill
- Description
- The boldest neutral treatment, matching the selected Chip pairing.
- Token
- --cds-bg-inverse
- Label
- Neutral outline border
- Description
- The divider token borders a neutral outline marker.
- Token
- --cds-divider
- Label
- Inverse contrast fill
- Description
- Backs a neutral marker placed on a dark or branded surface.
- Token
- --cds-bg-subtle-inverse
States
- Id
- solid
- Label
- Solid
- Description
- Tone solid fill with inverse text.
- Id
- subtle
- Label
- Subtle
- Description
- Tone subtle fill with tone solid text.
- Id
- outline
- Label
- Outline
- Description
- Transparent fill with a tone solid border and text.
- Id
- with-dot
- Label
- With dot
- Description
- Shows a leading dot that either matches the label color or carries its own tone.
- Id
- contrast-inverse
- Label
- Inverse contrast
- Description
- Neutral chrome retuned for a dark or branded surface. A toned marker keeps its tone.
- Id
- full-width
- Label
- Full width
- Description
- Stretches to the parent width, keeping content centered.
Behavior
- Label
- Tone
- Description
- Set tone to the semantic status. Neutral means chrome and leaves the status ramp for the surface roles.
- Label
- Independent dot tone
- Description
- Pass a tone to dot when the indicator and the label carry different meanings, such as a green dot beside a neutral label.
- Label
- Non-interactive
- Description
- A Tag is a span with no role and no focus stop. Never attach press or removal behavior; use Chip instead.
- Label
- Presets live in the app
- Description
- Product concepts such as live or paused belong in an app wrapper or in the recipe table, not in a design-system part.
Accessibility
- Label
- Visible meaning
- Description
- Keep textual content so the marker reads without relying on color or the dot alone.
- Label
- Decorative dot
- Description
- The dot is aria-hidden; the visible label carries the meaning.
- Label
- No focus stop
- Description
- The root adds no tab stop and no role, which is what separates a Tag from a Chip.
Content Adaptation
- Label
- Concise content
- Description
- Use short labels that stay on one line without wrapping.
- Label
- Overflow
- Description
- A label wider than the tag truncates with an ellipsis rather than wrapping or spilling past the pill. Treat that as a backstop, not a layout: pick copy that fits the narrowest place the tag appears.
- Label
- Leading visual
- Description
- Pair a glyph with the label rather than replacing the text.
Motion Haptics
- Motion
- Label
- Stable geometry
- Description
- Changing tone or emphasis recolors the pill without animating layout.
- Haptics
- Label
- No feedback
- Description
- Tag is non-interactive and requests no haptics.
Platform Differences
- Platforms
- ios
- android
- Description
- Native platforms have no built-in equivalent to map onto. Apple's HIG has no tag, chip, or pill, and the iOS badge modifier is an anchored count rather than a free-standing marker.
- Rationale
- Internal consistency governs this component instead of platform fidelity, so each platform builds the same pill rather than substituting a native control that means something else.
- Platforms
- web
- Description
- Figma draws a 6px indicator dot. Web renders 8px.
- Rationale
- 6px sits off the 4-step size ramp, and both Badge and StatusIndicator already use 8px, so matching them beats minting an off-ramp token for a 2px difference.