A small label naming a category, with an optional leading icon or picture and remove control; pressable, it opens something about what it names.
Options
| Choice | Values | Default | What it does |
|---|---|---|---|
tonesmbk-tag--tone-<value> | defaultbrandoutlineinfosuccessdangerwarning | default | A see-through gray that shows on every surface, brand, outlined, or one of the four feedback families on their subtle surfaces. |
pressablesmbk-tag--pressable | On or off | Off | The tag is a button that opens something about what it names, such as a card, with the hover, pressed and focus looks in the tag's own shape. The wrapper sets it when given onClick, as a popover's opener is; plain markup sets it on a button. |
Examples
Usage
A plain tag in the default tone.
Tones
Seven tones: a neutral gray, brand, outline and the four feedback colors.
With icon
An icon before the label.
Removable
The remove control appears when a handler is given; its small cross sits in a box large enough to press.
With a picture
The page's own picture, here an inline SVG, in the icon's place at the icon's size, in the tag's text color.
Opens a card
As a popover's opener the tag is a button that opens a card about what it names, with the pointer, hover, pressed and focus looks in the tag's own shape. Each tag is a Tab stop of its own.
Ada Okafor
Design lead
Leads the design system and reviews every new component.
Sam Kim
Engineer
Builds the components and keeps the tests running.
Lee Park
Writer
Writes the documentation and the release notes.
Guidelines
Purpose
A small label that names a category, a topic or a keyword on the thing it sits on. It reads as metadata, which is what separates it from a badge (a state) and from a chip (a choice). A pressable tag opens something about what it names, such as a small card about a person or a place.
When to use
- Topics on an article or a card.
- Keywords a person has attached to something and may take off again.
- A row of things that each open a small card about themselves when pressed, such as the members of a team or the stops on a route.
When not to use
Usage rules
Do
- Keep the label to one or two words, so the tag stays a glance.
- Make a tag pressable when a press opens something about what it names, such as a card about a person or a place.
Don't
- Make a tag pressable to filter a list or choose an option. That is a chip.
- Make a tag both pressable and removable. Open what it names from the tag, and remove it somewhere else.
Keep a tag to one or two words, so it reads at a glance.
A long tag becomes a sentence squeezed into a label, slow to read.
Anatomy
- The block, a short rounded rectangle of fixed height, on the same scale as the badge and the chip. The default tone is a see-through gray with no edge, so it shows on any surface. A pressable tag is a button drawn the same.
- The icon part, an optional small glyph before the label.
- The leading content part, the page's own small picture in the icon's place, at the icon's size. An inline SVG or an image fills the icon's box, and any other element is held to it. A tag has the icon or the picture, not both.
- The label part, text in sentence case in the small label style.
- The remove part, an optional small cross control, inside a box large enough to press that adds no width.
Behavior
None of its own. The remove control, when present, calls back.
Given a press handler, the tag is a button, and as a popover's opener it gets one from the popover. It keeps its shape, height and type, and takes the pointer, a hover look, a pressed look that sinks in and a focus ring round it. A pressable tag is never removable: given both, it is drawn removable and warns in development, because its remove control would be a button inside a button.
On a touch screen the remove cross keeps its box, and a pressable tag keeps its size, each taking an invisible press area round it, out to the comfortable touch target.
Accessibility
What it does for you
- The label is read as text.
- The remove control is a real button. It is at least 24 by 24 pixels, the least a press needs, though its cross is small.
- The remove control's focus ring is drawn round the cross, and on a brand tag in the inverse focus color, so it shows on the fill.
- A pressable tag is a real button, named by its words, and its focus ring is drawn round the tag. As a popover's opener it says that it opens a dialog and whether that is open.
- The icon is decorative.
- On a touch screen the remove cross and a pressable tag each take an invisible press area round them, out to the comfortable touch target.
What you must do
- Give the remove control an accessible name saying what it removes. Without one the wrapper warns in development and names it "Remove" and the tag's words.
- Hide a picture of your own that only repeats the tag's words (
aria-hidden="true"on an SVG, an emptyalton an image). Give it words of its own when it says something the label does not. - Never put a pressable tag inside a link or another button.
How to test
- Tab to the remove control: the focus ring shows round the cross, on a brand tag too, in both themes and in a forced-color mode. Press Enter, then Space: each calls back.
- Tab to a pressable tag: the focus ring shows round it. Press Enter, then Space: each opens what it names.
- With a screen reader, the label is read as text and the remove control as a button by what it removes; a pressable tag is read as a button by its words.
- On a touch screen, a press just outside the cross still removes the tag, and a press just outside a pressable tag still presses it.
Keyboard
| Key | What it does |
|---|---|
| Tab | Moves focus to a pressable tag, or to the remove control when the tag has one. Each pressable tag in a row is a stop of its own. |
| EnterorSpace | Presses the pressable tag, or the remove control, which calls back. |
Source
The files the tag is made of. Its folder on GitHub (opens in a new tab) holds them with its wrapper and its document.
Stylesheet
/* smbk-tag — Tag. Figma "Tag" 4088:12242.
* 24 tall on the pill scale, Label SM in sentence case, a 12 icon and cross.
* The default tone is a see-through gray with no edge and no shadow, so it
* shows on every surface. Figma draws the edge inside the tag, so the padding
* gives the edge's width back, and every tag draws one, clear where its tone
* has none, so all are the same size. A pressable tag is a button drawn the
* same, with a control's hover, pressed and focus looks (the end of this file). */
.smbk-tag {
/* The default tone; each feedback tone sets these again below (the tone recipe). */
--smbk-tone-surface: var(--smbk-color-surface-neutral-subtle);
--smbk-tone-border: transparent;
--smbk-tone-text: var(--smbk-color-text-subtle);
box-sizing: border-box;
display: inline-flex;
align-items: center;
gap: var(--smbk-space-inline-xs);
height: var(--smbk-size-mark-lg);
padding: 0 calc(var(--smbk-space-inset-md) - var(--smbk-border-width-hairline));
border: var(--smbk-border-width-hairline) solid var(--smbk-tone-border);
border-radius: var(--smbk-radius-control-sm);
background: var(--smbk-tone-surface);
color: var(--smbk-tone-text);
font-family: var(--smbk-typography-label-sm-font-family);
font-size: var(--smbk-typography-label-sm-font-size);
font-weight: var(--smbk-typography-label-sm-font-weight);
line-height: var(--smbk-typography-label-sm-line-height);
letter-spacing: var(--smbk-typography-label-sm-letter-spacing);
text-transform: var(--smbk-typography-label-sm-text-transform);
white-space: nowrap;
}
.smbk-tag__icon {
font-size: var(--smbk-size-icon-xs);
}
/* The page's own picture in the icon's place: a box the icon's size, an svg or an img filling it, and any other element
of the page's own held to it however large it is drawn elsewhere. An svg that fills or strokes with currentColor
takes the tag's text color, as the icon does. */
.smbk-tag__leading-content {
display: inline-flex;
flex-shrink: 0;
align-items: center;
justify-content: center;
width: var(--smbk-size-icon-xs);
height: var(--smbk-size-icon-xs);
}
.smbk-tag__leading-content > * {
max-width: 100%;
max-height: 100%;
}
.smbk-tag__leading-content > :is(svg, img) {
display: block;
width: 100%;
height: 100%;
}
/* The cross sits inside a 24 px box, the least a press needs; the box reaches past the cross into the gap
and the padding, so it adds no width and the cross sits where Figma draws it. The focus ring is drawn
on the cross's own edge.
The box is the small press box, with its press area on a touch screen, shared in press-box/press-box.css. */
.smbk-tag__remove {
margin: calc((var(--smbk-size-icon-xs) - var(--smbk-size-target-min)) / 2);
}
.smbk-tag__remove > .smbk-icon {
font-size: var(--smbk-size-icon-xs);
border-radius: var(--smbk-radius-full);
}
.smbk-tag__remove:focus-visible {
outline: none;
}
.smbk-tag__remove:focus-visible > .smbk-icon {
outline: var(--smbk-focus-ring-width) solid var(--smbk-color-border-focus);
outline-offset: 0;
}
/* ---- tone ---- */
.smbk-tag--tone-brand {
background: var(--smbk-color-surface-brand);
border-color: var(--smbk-color-border-rim-subtle);
color: var(--smbk-color-text-on-brand);
box-shadow: var(--smbk-elevation-raised);
}
/* The focus color would not show on the brand fill, so the ring there takes the inverse focus color. */
.smbk-tag--tone-brand .smbk-tag__remove:focus-visible > .smbk-icon {
outline-color: var(--smbk-color-border-focus-inverse);
}
.smbk-tag--tone-outline {
background: transparent;
border-color: var(--smbk-color-border-strong);
}
/* The feedback tones: the tone recipe, each family's subtle surface inside its pale edge. */
.smbk-tag--tone-info { --smbk-tone-surface: var(--smbk-color-feedback-info-surface-subtle); --smbk-tone-border: var(--smbk-color-feedback-info-border-subtle); --smbk-tone-text: var(--smbk-color-feedback-info-text-on-subtle); }
.smbk-tag--tone-success { --smbk-tone-surface: var(--smbk-color-feedback-success-surface-subtle); --smbk-tone-border: var(--smbk-color-feedback-success-border-subtle); --smbk-tone-text: var(--smbk-color-feedback-success-text-on-subtle); }
.smbk-tag--tone-danger { --smbk-tone-surface: var(--smbk-color-feedback-danger-surface-subtle); --smbk-tone-border: var(--smbk-color-feedback-danger-border-subtle); --smbk-tone-text: var(--smbk-color-feedback-danger-text-on-subtle); }
.smbk-tag--tone-warning { --smbk-tone-surface: var(--smbk-color-feedback-warning-surface-subtle); --smbk-tone-border: var(--smbk-color-feedback-warning-border-subtle); --smbk-tone-text: var(--smbk-color-feedback-warning-text-on-subtle); }
/* ---- pressable: a button that opens something about what it names ----
The tag's own shape, height, corner and type, never the chip's pill, with the chip's pointer, hover, pressed and
focus looks. The button's own look is reset, so a button and a span draw the same tag. The hover and pressed looks
go through the tone recipe: the default tone takes the hover and pressed fills, a feedback tone keeps its surface and
takes its family's full edge for its pale one; brand and outline set their colors directly, as they do at rest.
Pressed, every tone sinks in. On a touch screen the tag takes an invisible press area round it, out to the
comfortable target (press-box/press-box.css). */
.smbk-tag--pressable {
margin: 0;
cursor: pointer;
text-align: start;
text-decoration: none;
-webkit-user-select: none;
user-select: none;
appearance: none;
-webkit-tap-highlight-color: transparent;
touch-action: manipulation;
}
.smbk-tag--pressable:focus-visible {
outline: var(--smbk-focus-ring-width) solid var(--smbk-color-border-focus);
outline-offset: var(--smbk-focus-ring-offset);
}
@media (hover: hover) {
.smbk-tag--pressable:hover { --smbk-tone-surface: var(--smbk-color-surface-hover); }
.smbk-tag--pressable.smbk-tag--tone-info:hover { --smbk-tone-surface: var(--smbk-color-feedback-info-surface-subtle); --smbk-tone-border: var(--smbk-color-feedback-info-border); }
.smbk-tag--pressable.smbk-tag--tone-success:hover { --smbk-tone-surface: var(--smbk-color-feedback-success-surface-subtle); --smbk-tone-border: var(--smbk-color-feedback-success-border); }
.smbk-tag--pressable.smbk-tag--tone-danger:hover { --smbk-tone-surface: var(--smbk-color-feedback-danger-surface-subtle); --smbk-tone-border: var(--smbk-color-feedback-danger-border); }
.smbk-tag--pressable.smbk-tag--tone-warning:hover { --smbk-tone-surface: var(--smbk-color-feedback-warning-surface-subtle); --smbk-tone-border: var(--smbk-color-feedback-warning-border); }
.smbk-tag--pressable.smbk-tag--tone-brand:hover {
background: var(--smbk-color-action-brand-background-hover);
border-color: var(--smbk-color-action-brand-border-hover);
}
.smbk-tag--pressable.smbk-tag--tone-outline:hover {
background: var(--smbk-color-action-outline-background-hover);
border-color: var(--smbk-color-action-outline-border-hover);
}
}
.smbk-tag--pressable:active {
--smbk-tone-surface: var(--smbk-color-action-default-background-pressed);
box-shadow: var(--smbk-elevation-inset-strong);
}
.smbk-tag--pressable.smbk-tag--tone-info:active { --smbk-tone-surface: var(--smbk-color-feedback-info-surface-subtle); --smbk-tone-border: var(--smbk-color-feedback-info-border); }
.smbk-tag--pressable.smbk-tag--tone-success:active { --smbk-tone-surface: var(--smbk-color-feedback-success-surface-subtle); --smbk-tone-border: var(--smbk-color-feedback-success-border); }
.smbk-tag--pressable.smbk-tag--tone-danger:active { --smbk-tone-surface: var(--smbk-color-feedback-danger-surface-subtle); --smbk-tone-border: var(--smbk-color-feedback-danger-border); }
.smbk-tag--pressable.smbk-tag--tone-warning:active { --smbk-tone-surface: var(--smbk-color-feedback-warning-surface-subtle); --smbk-tone-border: var(--smbk-color-feedback-warning-border); }
.smbk-tag--pressable.smbk-tag--tone-brand:active {
background: var(--smbk-color-action-brand-background-pressed);
border-color: var(--smbk-color-action-brand-border-hover);
}
.smbk-tag--pressable.smbk-tag--tone-outline:active {
background: var(--smbk-color-action-outline-background-pressed);
border-color: var(--smbk-color-action-outline-border-hover);
}Tokens it reads
| Token and CSS | Value | Preview | Foundation |
|---|---|---|---|
| size.target.min--smbk-size-target-min | 24px | Size | |
| size.target.comfortable--smbk-size-target-comfortable | 44px | Size | |
| color.surface.neutral-subtle--smbk-color-surface-neutral-subtle | light: #373d431adark: #606a7533changes with theme | Color | |
| color.text.subtle--smbk-color-text-subtle | light: #4e555edark: #9ba5b1changes with theme | Color | |
| space.inline.xs--smbk-space-inline-xs | 4px | Spacing | |
| size.mark.lg--smbk-size-mark-lg | 24px | Size | |
| space.inset.md--smbk-space-inset-md | comfortable: 8pxcompact: 6pxchanges with density | Spacing | |
| border-width.hairline--smbk-border-width-hairline | 1px | Border width | |
| radius.control.sm--smbk-radius-control-sm | 4px | Radius | |
| typography.label-sm--smbk-typography-label-sm-font-family--smbk-typography-label-sm-font-size--smbk-typography-label-sm-font-weight--smbk-typography-label-sm-line-height--smbk-typography-label-sm-letter-spacing--smbk-typography-label-sm-text-transform | fontFamily: Geist, Geist Fallback, system-ui, sans-seriffontSize: 12pxfontWeight: 500lineHeight: 1.4letterSpacing: 0px | The quick brown fox | Typography |
| size.icon.xs--smbk-size-icon-xs | 12px | Size | |
| radius.full--smbk-radius-full | 9999px | Radius | |
| focus.ring.width--smbk-focus-ring-width | 2px | Focus | |
| color.border.focus--smbk-color-border-focus | light: #cc0d0ddark: #f34336changes with theme | Color | |
| color.surface.brand--smbk-color-surface-brand | #cc0d0d | Color | |
| color.border.rim-subtle--smbk-color-border-rim-subtle | light: #ffffff33dark: #ffffff08changes with theme | Color | |
| color.text.on-brand--smbk-color-text-on-brand | #f9fafb | Color | |
| elevation.raised--smbk-elevation-raised | light: 0px 2px 8px 1px #373d431a, 0px 1px 2px 0px #373d431adark: 0px 2px 8px 1px #00000026, 0px 1px 2px 0px #00000026 | Elevation | |
| color.border.focus-inverse--smbk-color-border-focus-inverse | #f9fafb | Color | |
| color.border.strong--smbk-color-border-strong | light: #9ba5b1dark: #373d43changes with theme | Color | |
| color.feedback.info.surface-subtle--smbk-color-feedback-info-surface-subtle | light: #e3ebfedark: #162352changes with theme | Color | |
| color.feedback.info.border-subtle--smbk-color-feedback-info-border-subtle | light: #b8ccffdark: #213583changes with theme | Color | |
| color.feedback.info.text-on-subtle--smbk-color-feedback-info-text-on-subtle | light: #2f4ab8dark: #b8ccffchanges with theme | Color | |
| color.feedback.success.surface-subtle--smbk-color-feedback-success-surface-subtle | light: #dffddfdark: #0a2d0echanges with theme | Color | |
| color.feedback.success.border-subtle--smbk-color-feedback-success-border-subtle | light: #8ddf90dark: #084712changes with theme | Color | |
| color.feedback.success.text-on-subtle--smbk-color-feedback-success-text-on-subtle | light: #016317dark: #8ddf90changes with theme | Color | |
| color.feedback.danger.surface-subtle--smbk-color-feedback-danger-surface-subtle | light: #fee5e1dark: #4b130echanges with theme | Color | |
| color.feedback.danger.border-subtle--smbk-color-feedback-danger-border-subtle | light: #febdb2dark: #761812changes with theme | Color | |
| color.feedback.danger.text-on-subtle--smbk-color-feedback-danger-text-on-subtle | light: #a51d17dark: #febdb2changes with theme | Color | |
| color.feedback.warning.surface-subtle--smbk-color-feedback-warning-surface-subtle | light: #ffe6dbdark: #431b07changes with theme | Color | |
| color.feedback.warning.border-subtle--smbk-color-feedback-warning-border-subtle | light: #febea2dark: #692903changes with theme | Color | |
| color.feedback.warning.text-on-subtle--smbk-color-feedback-warning-text-on-subtle | light: #913900dark: #febea2changes with theme | Color | |
| focus.ring.offset--smbk-focus-ring-offset | 2px | Focus | |
| color.surface.hover--smbk-color-surface-hover | light: #373d4326dark: #606a754dchanges with theme | Color | |
| color.feedback.info.border--smbk-color-feedback-info-border | #557bff | Color | |
| color.feedback.success.border--smbk-color-feedback-success-border | #269936 | Color | |
| color.feedback.danger.border--smbk-color-feedback-danger-border | #f34336 | Color | |
| color.feedback.warning.border--smbk-color-feedback-warning-border | #da601a | Color | |
| color.action.brand.background-hover--smbk-color-action-brand-background-hover | #a51d17 | Color | |
| color.action.brand.border-hover--smbk-color-action-brand-border-hover | #0000000d | Color | |
| color.action.outline.background-hover--smbk-color-action-outline-background-hover | light: #373d431adark: #606a751achanges with theme | Color | |
| color.action.outline.border-hover--smbk-color-action-outline-border-hover | light: #9ba5b1dark: #4e555echanges with theme | Color | |
| color.action.default.background-pressed--smbk-color-action-default-background-pressed | light: #c4cdd8dark: #4e555echanges with theme | Color | |
| elevation.inset-strong--smbk-elevation-inset-strong | light: inset -1px 2px 2px 0px #373d4333dark: inset -1px 2px 2px 0px #0000004d | Elevation | |
| color.action.brand.background-pressed--smbk-color-action-brand-background-pressed | #761812 | Color | |
| color.action.outline.background-pressed--smbk-color-action-outline-background-pressed | light: #c4cdd8dark: #2d3237changes with theme | Color |
Manifest
{
"name": "tag",
"block": "smbk-tag",
"summary": "A small label naming a category, with an optional leading icon or picture and remove control; pressable, it opens something about what it names.",
"adapt": "css",
"axes": {
"tone": {
"values": [
"default",
"brand",
"outline",
"info",
"success",
"danger",
"warning"
],
"default": "default",
"description": "A see-through gray that shows on every surface, brand, outlined, or one of the four feedback families on their subtle surfaces."
}
},
"flags": {
"pressable": {
"description": "The tag is a button that opens something about what it names, such as a card, with the hover, pressed and focus looks in the tag's own shape. The wrapper sets it when given onClick, as a popover's opener is; plain markup sets it on a button."
}
},
"parts": [
"icon",
"leading-content",
"label",
"remove"
],
"figmaNodeId": "4088:12242"
}