Skip to content

Feature: add Iconography section and icons.* tokens #41

@BenWertoski

Description

@BenWertoski

Summary

Add a formal ## Iconography section and an icons.* token group to the
DESIGN.md spec. The current spec already uses ## Iconography as its
illustrative example of a valid-but-undefined unknown section (docs/spec.md,
"Consumer Behavior for Unknown Content" table); this proposal fills that gap.

Motivation

Every example DESIGN.md in the repo — paws-and-paths, atmospheric-glass,
totality-festival — describes icons in prose but has no token slot for them.
Agents consuming these files today have to infer the icon library, style
variant, and size scale from surrounding context. That defeats the "consistent
visual identity across tools" goal: two agents reading the same DESIGN.md
will pick different icon sets.

Iconography is a visual-language primitive alongside Colors, Typography,
Elevation, and Shapes, and belongs in the token schema.

Proposal

Token group

icons:
  library: "Lucide"              # string — required within this group
  style: "outlined"              # enum (optional): outlined | filled | rounded | sharp | duotone
  strokeWidth: 1.5               # number (optional) — stroke-based libraries (Lucide, Tabler, Feather); font-based libraries map agent-side
  grid: 24px                     # Dimension (optional) — source viewBox unit; e.g. Radix=15, Phosphor=256, most others=24
  size:                          # map<string, Dimension> (optional)
    sm: 16px
    md: 24px
    lg: 32px
  color: "{colors.on-surface}"   # Color | token ref (optional)

Section placement

New ## Iconography section inserted between Shapes and Components in
the canonical section order. Rationale: it sits with the other visual-language
primitives (Colors, Typography, Elevation, Shapes) and immediately precedes
Components, where icon tokens are consumed.

Prose example

## Iconography

Icons use **Lucide** in its outlined style at a 1.5 stroke weight, echoing
the calm, linear rhythm of the typography. Icons render on a 24px grid and
inherit `on-surface` color by default.

- **Small (16px):** Inline with body text or dense tables.
- **Medium (24px):** Default for buttons, navigation, and form fields.
- **Large (32px):** Feature tiles and empty states.

Recommended token names (non-normative)

Add two entries to the existing "Recommended Token Names" list, matching its
existing paragraph format:

Icon Styles: outlined, filled, rounded, sharp, duotone

Icon Sizes: sm, md, lg

Design decisions

  • library is a free-form string — the icon ecosystem is long-tail and
    new libraries appear constantly; an enum would calcify.
  • style enum covers five canonical values drawn from a survey of
    Material Symbols, Heroicons, Phosphor, Font Awesome, Tabler, Lucide,
    Ionicons, Carbon, and Fluent. Unknown values accepted with warning,
    matching the spec's existing behavior.
  • strokeWidth is the cross-library weight concept. Font-based libraries
    (e.g., Material Symbols weight 100–700) map it agent-side.
  • color accepts token refs so icons participate in theming automatically
    as soon as Support for different modes/themes? #13 (themes) lands.
  • size mirrors spacing's map-of-named-steps pattern for consistency
    with existing token group conventions.
  • grid describes the source viewBox, not the render size. This
    disambiguates "what unit is strokeWidth in?" for libraries on non-24
    grids (Radix 15, Phosphor 256).

Deferred to follow-up

Each of these is a real case worth solving, but each is also its own design
debate. Deferring keeps v1 focused on the 80% case:

  • Duotone secondaryColor — only Phosphor Duotone and FA Duotone need
    it; adding a union-typed color field or a sibling secondaryColor is
    worth discussing in isolation.
  • Separate weight axis vs unified strokeWidth — Material Symbols'
    100–700 weight range may not map cleanly to a single stroke number; worth
    empirical validation.
  • Multi-library map — real pattern (Lucide UI + Simple Icons for brand
    logos); prose handles it in v1.
  • Optical-size variant selection — Carbon, Fluent, and Material Symbols
    ship different icon files per render size; v1 treats size.* as CSS
    output only, agent picks the right source file if the library supports
    optical sizing.

Library-specific constraints (not schema concerns)

Some libraries couple fields in ways the schema can't express:

  • Heroicons — "mini" is always solid 20px; "micro" is always solid 16px.
    style: "outlined" + size.sm: 16px is invalid for Heroicons specifically.
  • Material Symbols — the fill/weight/grade/optical-size axes are
    library-specific and resolved agent-side.

These constraints live at the agent/library boundary, not in the linter —
the schema stays library-agnostic.

Backwards compatibility

Purely additive. Existing DESIGN.md files without an icons block or
## Iconography section parse and lint identically. No version bump
required (spec is in alpha; additive schema changes are in-scope).

Consumer-side impact

  • ## Iconography is used in docs/spec.md as the example unknown section.
    When this lands, that example row should be swapped (e.g., to
    ## Illustrations) to avoid self-contradiction.
  • export commands (Tailwind, DTCG): neither format has an icon token
    concept; v1 passes icon tokens through unchanged rather than emitting them.
  • import command (feat(import): add design.md import reverse command #40): Tailwind configs and DTCG files do not carry icon
    metadata; import is a no-op for icons.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions