Skip to content

role presentation

Icon draft v0.1.0

A glyph of the system's icon set, decorative or named.

An icon draws one glyph of the icon set (Material Symbols, the Iconography foundation) at a size and in a color of the system. Next to text it is decoration and says nothing to assistive technology; alone, it must be named by what it means, and is then exposed as an image. Icons inside the other components (buttons, alerts, selects) are those components' parts, styled by their tokens; this component is for icons placed by a product in its own content.

Web implementation

Root .ds-icon on a <span>. Properties map to attributes: size → data-sizecolor → data-colorlabel → aria-label

packages/components/src/components/icon/icon.css
/*
 * Icon — vanilla CSS reference implementation.
 * Spec:   packages/components/specs/components/icon.spec.json
 * Tokens: packages/tokens/dist/css/components/icon.css (generated from packages/tokens/src/components/icon.tokens.json)
 *
 * Rules:
 *  - Only --icon-* custom properties may appear here. No raw values, no semantic tokens.
 *  - A glyph of the icon font. Size and color are data attributes; the default color, current,
 *    inherits the surrounding text color (currentColor: a token cannot say inherit).
 */

.ds-icon {
  --_size: var(--icon-container-size-medium);
  --_color: currentColor;

  display: inline-block;
  flex: none;
  inline-size: var(--_size);
  block-size: var(--_size);
  overflow: hidden;
  color: var(--_color);
  font-family: var(--icon-container-font-family);
  font-size: var(--_size);
  font-weight: var(--icon-container-font-weight);
  font-style: normal;
  font-variation-settings:
    "FILL" var(--icon-container-fill),
    "GRAD" var(--icon-container-grade),
    "opsz" var(--icon-container-optical-size);
  font-feature-settings: "liga";
  line-height: var(--_size);
  letter-spacing: normal;
  text-transform: none;
  white-space: nowrap;
  direction: ltr;
  vertical-align: middle;
  -webkit-font-smoothing: antialiased;
}

.ds-icon[data-size="small"] { --_size: var(--icon-container-size-small); }
.ds-icon[data-size="large"] { --_size: var(--icon-container-size-large); }

.ds-icon[data-color="neutral"] { --_color: var(--icon-container-color-neutral); }
.ds-icon[data-color="brand"] { --_color: var(--icon-container-color-brand); }
.ds-icon[data-color="success"] { --_color: var(--icon-container-color-success); }
.ds-icon[data-color="warning"] { --_color: var(--icon-container-color-warning); }
.ds-icon[data-color="error"] { --_color: var(--icon-container-color-error); }
.ds-icon[data-color="info"] { --_color: var(--icon-container-color-info); }
packages/components/src/components/icon/icon.template.mjs
/**
 * Icon — HTML template for the web implementation.
 * Pure function of the spec properties (packages/components/specs/components/icon.spec.json) -> HTML string.
 * A glyph of the icon font written as its ligature name. Without a label it is decorative and
 * hidden; with one it is an image named by the label.
 */
import { escapeAttr, renderIcon, ICONS } from '../../lib/template-utils.mjs';

export const meta = { id: 'icon', selector: '.ds-icon', icons: ICONS };

export function render(props = {}) {
  const { name = 'add', label = null, size = 'medium', color = 'current', state = null } = props;
  const attrs = ['class="ds-icon"', `data-size="${escapeAttr(size)}"`, `data-color="${escapeAttr(color)}"`];
  if (label) attrs.push('role="img"', `aria-label="${escapeAttr(label)}"`);
  else attrs.push('aria-hidden="true"');
  if (state && state !== 'default') attrs.push(`data-state="${escapeAttr(state)}"`);
  return `<span ${attrs.join(' ')}>${renderIcon(name || 'add')}</span>`;
}

No other platform implementation recorded yet. Platform token outputs live under Platforms.