Brik Design System
Build Standards

Prop Axes

The four shared prop names — size, status, variant, appearance — that any BDS component with overlapping visual concerns must use.

A prop is an axis when more than one component exposes it. Axis names belong to the system, not any single component. When adding a new pill, chip, or indicator, reuse the axis names below — never invent kind, style, or flavor.

The four axes

AxisValuesMeaningComponents
sizexs · sm · md · lg (indicators); tiny · sm · md · lg · xl (buttons)Physical dimensions on a shared scaleBadge, Tag, Chip, Button, IconButton, ServiceTag, Field, Sheet, most form controls
statuspositive · warning · error · info · progress · brandSemantic value judgment — which system color tier appliesBadge, Dot
variantcomponent-specific (see matrix)Shared prop name; meaning varies by componentChip, Button, IconButton, LinkButton, Card, ServiceTag
appearancesolid · subtle · outlineHow the shape is filled vs borderedBadge (solid / subtle), Tag (solid / subtle)

variant vs appearance

appearance describes fill. variant is the shared prop name — its meaning varies by component.

  • Interactive components (Chip, Button) use variant only. They have hierarchy to express.
  • Read-only indicators (Badge, Tag) use appearance only. Fill form is the only lever.

Never cross this boundary.

Why solid, subtle, outline

dark | light was ambiguous with dark-mode theming. solid | subtle | outline names the fill form explicitly:

  • solid — filled background, typically saturated or neutral
  • subtle — tinted background, lower emphasis
  • outline — transparent background, visible border

Coverage matrix

Source of truth: manifest/component-axes.json — auto-generated via npm run typegen:axes (ADR-009). When the table and the manifest disagree, the manifest wins.

Componentvariantappearancesizestatus
Buttonprimary · outline · secondary · ghost · inverse · on-color · destructive · positive · danger · danger-outline · danger-ghost—tiny · sm · md · lg · xl—
LinkButtonshares ButtonVariant—shares ButtonSize—
IconButtonshares ButtonVariant—shares ButtonSize—
Chipprimary · secondary—sm · md · lg—
Cardoutlined · brand · elevated · borderless———
ServiceTagtext · icon-text · icon—sm · md · lg—
Tag—solid · subtlexs · sm · md · lg—
Badge—solid · subtlexs · sm · md · lgpositive · warning · error · info · progress · brand

Notes:

  • selected is not a variant — it is a boolean state prop on Button / IconButton (selected={true}), applied as a modifier on top of any variant. Never list it in the variant union.
  • Chip appearance removed in v0.66 — Chip is interactive; emphasis lives on variant only.
  • Card variant encodes border/elevation style — not a hierarchy or fill axis. CardPreset (control · summary · display · display-row) is orthogonal to variant.
  • Badge outline appearance excluded — low contrast for status indicators.
  • Banner is not on the status axis — it expresses the same semantics through its own tone axis (announcement · warning · error · information). Dot uses status with its own union (default · positive · warning · error · info · neutral); the value sets are per-component (TypeScript is the gate).

TypeScript is the authoritative gate. Pass only values the component's declared union includes — never invent values. The manifest shows which types are exported.

Expression modes

The five expression-mode axes are the Style half of ADR-039. They are not component props — no component declares them. They are attributes set once on :root (the <html> element), and every component inherits the retuned tokens.

AxisAttribute on :rootValuesDefault (no attribute)
Spacingdata-mode-spacingcompact · comfortable · spaciousdefault
Typographydata-mode-typographycompact · comfortable · spacious · expressivedefault
Radiusdata-mode-radiussharp · round · pillsoft
Elevationdata-mode-elevationflat · lifted · dramaticsubtle
Border widthdata-mode-borderwidththin · boldstandard

Each default is the attribute-ABSENT state — there is no [data-mode-radius="soft"] selector, and setting one does nothing. Omit the attribute to get the default. For the same reason the defaults are not members of the closed vocabularies below.

Closed value lists live in content-system/vocabularies/{spacing,typography,radius,elevation,borderwidth}-mode.ts, published as @brikdesigns/bds/content-system. They are surfaced to the portal's enum gate under the reserved @modes key in manifest/component-axes.json, alongside the component axes.

The authority is the CSS, not the TypeScript: tokens/modes-*.css is what ships, and content-system/vocabularies/expression-modes.test.ts parses it to hold each list equal to the selectors it declares. A Figma mode rename fails that test rather than drifting into a portal pick-list.

Motion has no mode axis. There is no data-mode-motion selector; motion is expressed through the AnimationTier vocabulary (subtle · moderate · expressive) and the reveal / contentMotion prop axes, with none meaning no motion classes are emitted.

Blueprint shortlist weights

resolveBlueprintShortlist ranks the blueprint library against a company profile. The weights are exported as SHORTLIST_WEIGHTS from content-system/blueprints/resolver.ts so the portal runs the same math on the same numbers — this table documents them, the export is the gate.

TermWeightCounts
perPersonalityHit2once per overlapping personality
perVisualStyleHit1once per overlapping visual style
industrySlugMatch3once
universalBonus5once, for a universal blueprint
atmosphereMatch3once
animationTierMatch2once
spacingModeMatch1once

The three design-decision terms descend by how much of a section's rendering the axis governs: the atmosphere sets the whole visual register and is a peer of the industry match, the animation tier governs motion only, the spacing mode governs density alone. Combined they cap at 6, just above universalBonus — deliberately, so a blueprint matching every decision the client made outranks an evergreen one matching none.

Each is matched against an optional affinity array on the blueprint (atmospheres, animation_tiers, spacing_modes). Every term is additive and none filters, so a blueprint that declares no affinity scores exactly what it scored before these existed, and an affinity miss can re-rank a shortlist but never shrink it.

  • Components — each component implements the axes documented here
  • Slot Vocabulary — slot names that pair with these axis props
  • Client Themes — the four Theming Dimensions the expression modes sit inside

On this page

💬