Data Display

admin-timeseries-chart

#existingsource

The full time-series chart the Admin pillars drill into: multiple labelled series over a shared time axis, with gridlines, y/x axis labels, an optional filled area (band) or stacked mode, and a hover crosshair that reads the exact value at a point. The at-a-glance counterparts stay specialised — `<Sparkline>` for an inline trend, `<Gauge>` for a single ratio, `<DonutChart>` for a categorical split — this is what they expand into. Pure SVG computed in Rust so it renders identically under SSR and after hydration.

Readiness
complete
Preview
live
Props
7
Examples
2
Code
implementation mapped

When to use

  • An operator dashboard progression view (intake/terminal net-flow, runs over time, vitals).
  • Comparing two or more series on a shared time axis (e.g. shown vs clicked).
  • A stacked composition over time (intake split by source) — set `stacked`.
  • A metric that is partly instrumented — flag the series `gapped` to draw it honestly.

When not to use

  • A tiny inline trend beside a number — use `<Sparkline>`.
  • A single ratio/percentage — use `<Gauge>`.
  • A parts-of-a-whole split at one instant — use `<DonutChart>`.

Accessibility

Role: group

  • No keyboard shortcuts

Screen reader: The chart carries a visible legend (series are labelled, not colour-only) plus an offscreen text summary of each series' latest value, so a screen-reader user gets the data without the SVG geometry. The hover readout is `aria-live="off"` (pointer-only, not announced).

Notes: Series tone reinforces — it is never the only signal (legend label + last-value text carry meaning). Honours `prefers-reduced-motion` at the CSS-rail level: the live-append slide tween collapses to an instant redraw.

Props

NameTypeDefaultDescription
seriesarrayThe series to plot. Each: `{ label, tone, gapped?, points: [{t, v}] }` (points may also be bare numbers, in which case `t` is the index). Reactive. Required.
widthinteger640SVG viewBox width in px (scales to container, keeps ratio).
heightinteger240SVG viewBox height in px.
y_formatenum: count | ms | percent | tokenscountHow y-axis labels + the hover readout format values.
stackedbooleanfalseStack series cumulatively (implies filled areas).
bandbooleanfalseFill the area under each line (ignored when stacked, which always fills).
aria_labelstringChart-level description; an offscreen latest-value summary is always added.

Examples

Net-flow: intake vs terminal

Pipeline net-flow — intake (caution) vs terminal (good) over a window.

2216.5115.50t0t3t5
Intake22Terminal21

Intake: latest 22. Terminal: latest 21

YAML
type: admin-timeseries-chart
props:
  y_format: count
  band: true
  series:
  - label: Intake
    tone: caution
    points:
    - t: 0
      v: 12
    - t: 1
      v: 18
    - t: 2
      v: 14
    - t: 3
      v: 20
    - t: 4
      v: 16
    - t: 5
      v: 22
  - label: Terminal
    tone: good
    points:
    - t: 0
      v: 8
    - t: 1
      v: 11
    - t: 2
      v: 15
    - t: 3
      v: 13
    - t: 4
      v: 19
    - t: 5
      v: 21
Gap-aware series

A gapped series — a metric signoz has only partly instrumented renders dashed + noted.

6145.830.515.20t0t2t3
Visits (instrumented)61Component shown7history pending

Visits (instrumented): latest 61. Component shown: latest 7

YAML
type: admin-timeseries-chart
props:
  y_format: count
  series:
  - label: Visits (instrumented)
    tone: accent
    points:
    - t: 0
      v: 40
    - t: 1
      v: 52
    - t: 2
      v: 48
    - t: 3
      v: 61
  - label: Component shown
    tone: neutral
    gapped: true
    points:
    - t: 0
      v: 5
    - t: 1
      v: 7
Edit YAML

avatar

#existingsource

A circular identity chip. When `src` is set it shows the image; otherwise it derives up-to-two-letter initials from `name` on a token-tinted background. Three sizes keep identity consistent across dense rows, default lists, and profile headers.

Readiness
complete
Preview
live
Props
3
Examples
3
Code
implementation mapped

When to use

  • A user or agent identity in a list row or header
  • Comment / activity authorship
  • Anywhere a person/agent needs a compact recognisable mark

When not to use

  • A stack of several identities — use AvatarGroup
  • A general framed image — use Image
  • A status indicator — use Badge / status-dot

Accessibility

Role: img

  • No keyboard shortcuts

Screen reader: The image variant uses `name` as alt; the initials variant exposes `name` via role=img + aria-label so the identity is announced rather than read as loose letters.

Notes: Initials are a visual shorthand only — the accessible name is always the full `name`, never the two-letter abbreviation.

Props

NameTypeDefaultDescription
namestring?Display name — drives initials and the accessible name.
srcstringOptional image URL. Empty → initials.
sizeenum: small | medium | largemedium

Examples

Initials

An initials avatar (no image).

GH
YAML
type: avatar
props:
  name: Grace Hopper
  size: medium
Sizes

The three sizes side by side.

ABCDEF
YAML
type: stack
props:
  gap: sm
  direction: row
  align: center
children:
- type: avatar
  props:
    name: A B
    size: small
- type: avatar
  props:
    name: C D
    size: medium
- type: avatar
  props:
    name: E F
    size: large
Single name

A single-word name (one initial).

T
YAML
type: avatar
props:
  name: Triform
  size: large
Edit YAML

avatar-group

#existingsource

Show several identities in a compact overlapping stack — collaborators on a board, agents on a run. `overflow` renders a trailing "+N" chip for identities not shown so the count stays honest without widening the row.

Readiness
complete
Preview
live
Props
2
Examples
3
Code
implementation mapped

When to use

  • Collaborators / members on a card or board header
  • Agents participating in a run
  • Any compact 'these N people' affordance

When not to use

  • A single identity — use Avatar
  • A full member list with names — use a list / Table
  • Selectable participants — compose with interactive rows

Accessibility

Role: group

  • No keyboard shortcuts

Screen reader: The container is role=group; each child Avatar carries its own accessible name, and the overflow chip exposes "+N more" via aria-label so the hidden count is announced, not just shown.

Notes: The overlap is purely visual; assistive tech still reads each avatar in DOM order followed by the overflow count.

Props

NameTypeDefaultDescription
sizeenum: small | medium | largemedium
overflowinteger0Count rendered as a trailing +N chip (0 = none).

Examples

Collaborators

Three collaborators with two more hidden.

ALGHAT+2
YAML
type: avatar-group
props:
  overflow: 2
slots:
  default:
  - type: avatar
    props:
      name: Ada L
  - type: avatar
    props:
      name: Grace H
  - type: avatar
    props:
      name: Alan T
No overflow

A small stack, no overflow.

QARB
YAML
type: avatar-group
slots:
  default:
  - type: avatar
    props:
      name: Q A
  - type: avatar
    props:
      name: R B
Large + overflow

Large stack with a big overflow count.

OT+12
YAML
type: avatar-group
props:
  size: large
  overflow: 12
slots:
  default:
  - type: avatar
    props:
      name: One
      size: large
  - type: avatar
    props:
      name: Two
      size: large
Edit YAML

badge

#existingsource

A read-only rectangular label displaying a count or status. Use Badge when the value is non-interactive — clicking it does nothing. For interactive filter chips, use FilterChip; for free-form labels, use Tag (when it lands). The tone (variant) is structural: muted for inherited / inactive values; primary for emphasis; success / warning / danger / info for ladder-consistent semantic states.

Readiness
complete
Preview
live
Props
1
Examples
3
Code
implementation mapped

When to use

  • Status indicator on a list row (e.g. 'Active', 'Failed', 'Pending')
  • Numeric counter ('12 unread', '3 errors')
  • Inherited / inferred value markers (`muted` variant — '[parent]')
  • Inline labels next to text headings

When not to use

  • Interactive toggles — use FilterChip
  • Read-only free-form text label — use Tag (when it lands)
  • Element identity (icon + colour + name) — use ElementBadge
  • Numeric counter on rail items — use CounterPill (sibling, panel-bound)

Accessibility

Role: status

  • No keyboard shortcuts

Screen reader: Reads the badge's text content. Variant colour is decorative only — semantic state should be conveyed in the text (e.g. 'Status: Active' not just 'Active' next to a green badge).

Notes: Don't rely on colour alone to convey status. Pair badges with text or icons so colourblind users can still parse them.

Props

NameTypeDefaultDescription
variantenum: default | primary | success | warning | danger | info | muteddefault

Examples

Status row

Status badges on a row of entities.

ActivePendingFailed
YAML
type: stack
props:
  gap: sm
  direction: row
children:
- type: badge
  props:
    variant: success
  slots:
    default: Active
- type: badge
  props:
    variant: warning
  slots:
    default: Pending
- type: badge
  props:
    variant: danger
  slots:
    default: Failed
Counter

Numeric counter.

12
YAML
type: badge
props:
  variant: primary
slots:
  default: '12'
Variants

All variants for visual comparison.

defaultprimarysuccesswarningdangerinfomuted
YAML
type: stack
props:
  gap: sm
  direction: row
  align: center
children:
- type: badge
  props:
    variant: default
  slots:
    default: default
- type: badge
  props:
    variant: primary
  slots:
    default: primary
- type: badge
  props:
    variant: success
  slots:
    default: success
- type: badge
  props:
    variant: warning
  slots:
    default: warning
- type: badge
  props:
    variant: danger
  slots:
    default: danger
- type: badge
  props:
    variant: info
  slots:
    default: info
- type: badge
  props:
    variant: muted
  slots:
    default: muted
Edit YAML

bar-chart

#existingsource

Compare a small set of categorical values. Each bar's length is its value relative to the dataset maximum, and the numeric value is printed alongside so the chart is readable without colour or precise length perception. For trends over time use Sparkline; for parts-of-a-whole use DonutChart.

Readiness
complete
Preview
live
Props
1
Examples
3
Code
implementation mapped

When to use

  • Top-N comparisons (counts per category, per element)
  • Small operational breakdowns on a dashboard
  • Any 'compare these few values' summary

When not to use

  • Time series — use Sparkline
  • Parts of a whole / percentages — use DonutChart
  • Large datasets needing axes / zoom — out of scope

Accessibility

Role: img

  • No keyboard shortcuts

Screen reader: The chart container is role=img with an aria-label. Each row prints its label and exact numeric value as text, so the data is fully available without interpreting bar length or colour.

Notes: Value is conveyed as text in addition to bar width — never by bar length alone.

Props

NameTypeDefaultDescription
barsarrayBars in display order. Each: { label, value }.

Examples

Runs by element

Runs per element type.

YAML
type: bar-chart
props:
  bars:
  - label: python
    value: 142
  - label: sql
    value: 86
  - label: http
    value: 53
  - label: vector
    value: 21
Pass / fail

A two-bar comparison.

YAML
type: bar-chart
props:
  bars:
  - label: pass
    value: 318
  - label: fail
    value: 12
Uniform

Uniform values (all bars equal).

YAML
type: bar-chart
props:
  bars:
  - label: a
    value: 10
  - label: b
    value: 10
  - label: c
    value: 10
Edit YAML

code-block

#existingsource

A read-only code sample surface with monospace type, horizontal overflow, and an optional language label. Use it for API examples, shell commands, JSON payloads and generated snippets so every code sample on the platform reads the same way.

Readiness
complete
Preview
live
Props
2
Examples
3
Code
implementation mapped

When to use

  • API examples, shell commands, JSON payloads, generated snippets
  • Read-only code samples inside a docs / markdown surface
  • Short configuration examples

When not to use

  • Editable code fields — use code-input
  • One-line inline values — use inline code, or kbd for a shortcut
  • Large file viewers needing search / minimap — out of scope

Accessibility

Role: region

  • No keyboard shortcuts

Screen reader: Wrapped in role=region with an aria-label naming the language so screen-reader users can navigate to and skip the sample.

Notes: The language label is decorative chrome; the code itself is the content and is exposed verbatim in the <pre><code>.

Props

NameTypeDefaultDescription
languagestringtextLanguage label shown in the header (also drives the aria-label).
codestringThe code text. Falls back to the default slot's text.

Examples

Shell

A shell command sample.

bash
cargo run -p triform-server --features ssr-frontend
YAML
type: code-block
props:
  language: bash
  code: cargo run -p triform-server --features ssr-frontend
JSON

A small JSON payload.

json
{
  "circle": "acme",
  "element": "my-fn"
}
YAML
type: code-block
props:
  language: json
  code: |-
    {
      "circle": "acme",
      "element": "my-fn"
    }
Rust

A Rust snippet.

rust
fn main() {
    println!("hello triform");
}
YAML
type: code-block
props:
  language: rust
  code: |-
    fn main() {
        println!("hello triform");
    }
Edit YAML

data-row

#existingsource

One horizontal label→value row for detail panels and sidebars. Label left, value right, with an optional `badge` ("[parent]", "[here]") and an optional `muted` style for inherited/default values. It is the row atom — stack several inside a list or `<DefinitionList>` for a detail block. Use `<KeyValue>` instead when the shape is `name = value` config with masking/actions.

Readiness
complete
Preview
live
Props
4
Examples
2
Code
implementation mapped

When to use

  • A property/detail panel line — Name → my-element, Type → python.
  • Sidebar metadata rows where label/value alignment should be consistent.
  • Rows that need a small status badge ([parent], [here], [overridden]).

When not to use

  • Env/secret config with masking + edit/delete actions — use `<KeyValue>`.
  • A clickable row that expands detail — use `<ExpandableRow>`.
  • Free-form two-column layout — use a layout primitive, not a semantic row.

Accessibility

Role: presentation

  • No keyboard shortcuts

Screen reader: Presentational by default — label and value read in order. When a row conveys a semantic pair that matters to AT, prefer wrapping a set of them in `<DefinitionList>` (proper `<dl><dt><dd>`) rather than relying on visual adjacency.

Notes: `muted` is visual only — don't let it be the sole signal that a value is inherited; pair with a `badge` ("[inherited]") so the meaning survives for low-vision users.

Props

NameTypeDefaultDescription
labelstringRow label (left). Required.
valuestringRow value (right). Required.
badgestringOptional small status badge ([parent], [here], [overridden]).
mutedbooleanfalseMuted/inherited styling. Visual only — pair with a badge so the inherited meaning is not colour-alone.

Examples

Detail rows

Element detail rows — the canonical sidebar shape.

Name my-element Type python Status active
YAML
type: stack
props:
  direction: column
  gap: sm
children:
- type: text
  slots:
    default: Name        my-element
- type: text
  slots:
    default: Type        python
- type: text
  slots:
    default: Status      active
Inherited row

Inherited value with badge — muted + [parent].

Timeout 30s
YAML
type: stack
props:
  direction: row
  gap: md
children:
- type: text
  slots:
    default: Timeout     30s
- type: badge
  props:
    label: parent
Edit YAML

definition-list

#existingsource

The semantic multi-row wrapper for label→value pairs. `<KeyValue>` and `<DataRow>` are the single-row atoms; DefinitionList wraps a set of them in proper `<dl><dt><dd>` markup with consistent rhythm and column alignment so a detail block is one accessible unit, not visually-adjacent rows. Use it when a group of read-only attributes should scan like data and announce as term/definition pairs.

Readiness
complete
Preview
live
Props
2
Examples
2
Code
implementation mapped

When to use

  • A detail block of label→value pairs that should be ONE semantic unit (element properties, request metadata).
  • Where `<dl>` semantics matter for assistive tech (grouped term/definition associations).
  • Replacing a visually-aligned stack of rows that AT currently reads as unrelated lines.

When not to use

  • A single pair — use `<KeyValue>` or `<DataRow>` directly.
  • Editable config — use `<Field>`/`<Input>`; this is a display wrapper.

Accessibility

Role: list

  • No keyboard shortcuts

Screen reader: Target semantics: `<dl>` with each pair as `<dt>` (term) + `<dd>` (definition) so AT announces grouped term/definition associations rather than loose lines. This is the primary reason the component exists over a plain row stack.

Notes: Render as `<dl><dt><dd>…` for proper semantic association.

Props

NameTypeDefaultDescription
pairsarrayThe term→definition pairs rendered as `<dt>`/`<dd>`. Each entry is a label + value (+ optional badge), mirroring `<DataRow>`.
alignedbooleantrueWhether `<dt>` columns align to a shared width (true, default — scannable) or `<dd>` flows directly after each `<dt>`.

Examples

Properties definition list

Element-properties definition block.

Name
my-element
Type
python
Created
2026-05-16
Owner
iggyactive
YAML
type: definition-list
props:
  pairs:
  - label: Name
    value: my-element
  - label: Type
    value: python
  - label: Created
    value: 2026-05-16
  - label: Owner
    value: iggy
    badge: active
Request metadata

Request-metadata block with a status badge on one pair.

Method
POST
Status
200cached
Trace
req_2G4Y...
YAML
type: definition-list
props:
  pairs:
  - label: Method
    value: POST
  - label: Status
    value: '200'
    badge: cached
  - label: Trace
    value: req_2G4Y...
Edit YAML

diff-view

#existingsource

Render a unified diff: a monospace block of lines, each marked added (+), removed (-), or context (space) with both a gutter glyph and a token-tinted background. Use it for review snippets, generated-change previews, and "what changed" summaries.

Readiness
complete
Preview
live
Props
1
Examples
3
Code
implementation mapped

When to use

  • Review / change-preview snippets
  • Showing a generated edit before applying it
  • Config or code 'before vs after' summaries

When not to use

  • Plain (non-diff) code — use code-block
  • Full side-by-side file review with navigation — out of scope
  • Prose change tracking — not a diff surface

Accessibility

Role: region

  • No keyboard shortcuts

Screen reader: Wrapped in role=region + aria-label "Diff". Each line begins with a literal +/-/space gutter glyph in the text, so add/remove status is conveyed in content — not by background colour alone.

Notes: The tinted backgrounds are reinforcement only; the gutter glyph is the primary, colour-independent signal.

Props

NameTypeDefaultDescription
linesarrayDiff lines in order. Each: { kind: add|del|context, text }.

Examples

Config diff

A small config change.

replicas: 2
memory: 512Mi
memory: 1Gi
image: triform:latest
YAML
type: diff-view
props:
  lines:
  - kind: context
    text: 'replicas: 2'
  - kind: del
    text: 'memory: 512Mi'
  - kind: add
    text: 'memory: 1Gi'
  - kind: context
    text: 'image: triform:latest'
Addition

An added block.

fn main() {
init_tracing();
}
YAML
type: diff-view
props:
  lines:
  - kind: context
    text: fn main() {
  - kind: add
    text: '    init_tracing();'
  - kind: context
    text: '}'
Kinds

All three line kinds.

unchanged line
added line
removed line
YAML
type: diff-view
props:
  lines:
  - kind: context
    text: unchanged line
  - kind: add
    text: added line
  - kind: del
    text: removed line
Edit YAML

donut-chart

#existingsource

A donut/pie for categorical breakdowns — "where are runs happening" (mail/phone/boards/agents), "where are errors concentrated". Self- contained SVG arc math (no chart library, no canvas, SSR-safe). The hollow centre (`inner_ratio`, default 0.6 ring) carries a total-count label; slices ≤2% of the total fold into one "Other" wedge so the ring stays legible (`collapse_small: false` to opt out).

Readiness
complete
Preview
live
Props
5
Examples
2
Code
implementation mapped

When to use

  • A categorical share — runs by surface, errors by service, cost by element type.
  • A breakdown where the total (centre label) matters alongside the split.
  • Dashboard composition tiles needing SSR with no chart JS.

When not to use

  • A single ratio/percentage — use `<Gauge>`.
  • A trend over time — use `<Sparkline>`.
  • Many categories with precise values — a labelled bar/table reads better than a forest of wedges.

Accessibility

Role: img

  • No keyboard shortcuts

Screen reader: The SVG is decorative; `aria_label` should summarise the split and a non-visual label/value list should sit nearby so SR users get the per-slice numbers. Slice colour alone is meaningless to them.

Notes: The ≤2% "Other" fold is a legibility default — when exact small slices matter, pass `collapse_small: false` and surface the values in an adjacent list.

Props

NameTypeDefaultDescription
slicesarrayThe categorical entries. Each is a label + value + CSS colour. Reactive. Required.
inner_rationumber0.6Inner radius as a fraction of outer (0.0 = full pie, ~0.6 = ring).
collapse_smallbooleantrueFold slices ≤2% of total into one 'Other' wedge for legibility.
center_labelstringOptional hollow-centre label (usually the total count).
aria_labelstringSR summary of the breakdown.

Examples

Runs by surface

Runs-by-surface breakdown with a total in the centre.

◍ 1,420 total agents 612 · mail 388 · boards 250 · phone 170
YAML
type: stack
props:
  direction: column
  gap: sm
children:
- type: text
  slots:
    default: ◍ 1,420 total
- type: text
  slots:
    default: agents 612 · mail 388 · boards 250 · phone 170
Errors by service

Errors-by-service donut with a small-slice 'Other' fold.

◍ 88 errors payment 51 · auth 22 · search 9 · Other 6
YAML
type: stack
props:
  direction: column
  gap: sm
children:
- type: text
  slots:
    default: ◍ 88 errors
- type: text
  slots:
    default: payment 51 · auth 22 · search 9 · Other 6
Edit YAML

element-badge

#existingsource

A compact identity badge for element types and element instances. Badge sizes that show a label reserve the label line even when custom data is incomplete, so icon grids do not change rhythm as metadata loads. The reusable showcase preview mirrors the portal class contract, so changes made here are visible immediately on `/components` and in portal badge surfaces.

Readiness
complete
Preview
live
Props
13
Examples
2
Code
implementation mapped

When to use

  • Element type selectors where a compact icon-led option is enough
  • Breadcrumbs, trees, and inline mentions that need element identity
  • Instance badges with custom icon, color, image, or glow overrides

When not to use

  • Library browse results that need intention context — use library-element-card
  • Full element-type catalog entries — use element-card
  • Generic status labels unrelated to elements — use badge

Accessibility

Role: button

  • Enter — Activates the badge when clickable
  • Space — Activates the badge when clickable

Screen reader: The button exposes an aria-label derived from the display name. Decorative icons and images are hidden from assistive tech.

Notes: XS badges hide the name visually. Larger badge sizes reserve a stable name line so a grid does not compress when a custom label is absent.

Props

NameTypeDefaultDescription
element_type*stringElement type identifier.
display_namestringOptional preview label for component-showcase rendering.
symbolstringOptional symbol fallback for component-showcase rendering.
icon_namestringOptional Material Symbols icon for component-showcase rendering.
icon_colorstringOptional identity color for component-showcase rendering.
sizeenum: xs | sm | md | lg | xlmdBadge size. XS is icon-only; larger sizes show a stable label slot.
show_namebooleanOverrides size-based name visibility.
custom_namestringOptional label override.
selectedbooleanfalseSelected visual state.
highlightedbooleanfalseKeyboard-highlight visual state.
disabledbooleanfalseDisabled interaction state.
glowbooleanfalseLive/active glow treatment.
titlestringTooltip and optional accessibility label detail.

Examples

Badge row

Compact element badge row for selectors and toolbars.

YAML
type: stack
props:
  gap: sm
  direction: row
  align: center
children:
- type: element-badge
  props:
    element_type: circle
    display_name: Circle
    symbol: Ci
    icon_name: radio_button_unchecked
    icon_color: '#8B5CF6'
    size: md
- type: element-badge
  props:
    element_type: app
    display_name: App
    symbol: Ap
    icon_name: deployed_code
    icon_color: '#8B5CF6'
    size: md
- type: element-badge
  props:
    element_type: validation
    display_name: Validation
    symbol: Va
    icon_name: fact_check
    icon_color: '#FF7A1A'
    size: md
Badge states

Live and selected badge states.

YAML
type: stack
props:
  gap: sm
  direction: row
  align: center
children:
- type: element-badge
  props:
    element_type: queue
    display_name: Queue
    symbol: Qu
    icon_name: dns
    icon_color: '#FF7A1A'
    size: lg
    glow: true
- type: element-badge
  props:
    element_type: contacts
    display_name: Contacts
    symbol: Cn
    icon_name: person
    icon_color: '#2F80FF'
    size: lg
    selected: true
- type: element-badge
  props:
    element_type: board
    display_name: Board
    symbol: Bd
    icon_name: view_kanban
    icon_color: '#6B7280'
    size: lg
    disabled: true
Edit YAML

element-card

#existingsource

A reusable full element identity card for browse, showcase, chooser, and live-runtime surfaces. The intention row always reserves two lines, even when empty, so card grids keep a stable rhythm while data is incomplete. Type cards emphasize elemental metadata; instance and live cards can add compact metrics without changing card geometry.

Readiness
complete
Preview
live
Props
15
Examples
4
Code
implementation mapped

When to use

  • Element catalog and component showcase entries
  • Chooser surfaces where users compare multiple element types
  • Element cards that need name, symbol/icon, intention, and metadata tags
  • Instance and live-runtime summaries with a few high-value statistics

When not to use

  • Dense library browse grids — use library-element-card
  • Inline text references — use element-badge-inline
  • Pure layout grouping — use card

Accessibility

Role: article

  • No keyboard shortcuts

Screen reader: The card exposes the element name and kind as its accessible label. Icons and accent strips are decorative because the name and text carry identity.

Notes: If the card is interactive, render it as a button/link through the component API rather than adding click handlers to a passive wrapper.

Props

NameTypeDefaultDescription
kind*stringKebab-case element type.
symbol*stringShort periodic-table symbol.
name*stringHuman-readable display name.
intentionstringOne- or two-line element intention. Empty still reserves space.
category*stringElement category id.
icon_namestringMaterial Symbols icon name.
icon_color*stringCategory or element identity color.
formstringElement form label.
variantenum: type | instance | livetypeCard mode: elemental definition, instantiated element, or live runtime.
state_labelstringShort status label shown in the top-right pill.
state_toneenum: active | pulse | attention | error | inactive | neutralSemantic tone for the status pill.
updated_labelstringOptional freshness or secondary live-data caption.
tagsarrayOptional metadata chips under the intention row.
metricsarrayUp to three compact metric cells for instance/live cards.
selectedbooleanfalseSelected/focused visual state.

Examples

Type card

Element type card with definition metadata.

Sq
type

SQL Database

Persistent SQL storage with schemas, indexes, and migrations.

datapersistentschema
YAML
type: element-card
props:
  kind: sql
  symbol: Sq
  name: SQL Database
  intention: Persistent SQL storage with schemas, indexes, and migrations.
  category: data
  icon_name: database
  icon_color: '#2F80FF'
  form: data
  variant: type
  tags:
  - data
  - persistent
  - schema
Instance card

Instantiated element card with stable metric slots.

Ap
Draft

Month End Review

Finance close workspace with linked app and modifier context.

Files
7
Owners
2
Drafts
1

3 linked elements

YAML
type: element-card
props:
  kind: app
  symbol: Ap
  name: Month End Review
  intention: Finance close workspace with linked app and modifier context.
  category: apps
  icon_name: deployed_code
  icon_color: '#8B5CF6'
  form: manifest
  variant: instance
  state_label: Draft
  state_tone: attention
  updated_label: 3 linked elements
  metrics:
  - label: Files
    value: '7'
    tone: neutral
  - label: Owners
    value: '2'
    tone: active
  - label: Drafts
    value: '1'
    tone: attention
Live card

Live element card with runtime statistics.

Qu
Running

Revenue Intake

Running intake flow with browser, queue, and validation telemetry.

Runs
248
Success
99.1%
p95
182ms

Updated 18s ago

YAML
type: element-card
props:
  kind: queue
  symbol: Qu
  name: Revenue Intake
  intention: Running intake flow with browser, queue, and validation telemetry.
  category: io
  icon_name: dns
  icon_color: '#FF7A1A'
  form: connector
  variant: live
  state_label: Running
  state_tone: pulse
  updated_label: Updated 18s ago
  metrics:
  - label: Runs
    value: '248'
    tone: info
  - label: Success
    value: 99.1%
    tone: active
  - label: p95
    value: 182ms
    tone: neutral
Empty intention spacing

Same spacing with missing intention.

Pr
type

Prompt

modifier
YAML
type: element-card
props:
  kind: prompt
  symbol: Pr
  name: Prompt
  intention: ''
  category: modifiers
  icon_name: edit_note
  icon_color: '#FF7A1A'
  form: modifier
  tags:
  - modifier
Edit YAML

element-composition

#existingsource

The structural neighbourhood of an element in two stacked blocks. First, the composition categories a compound element is built from — each a labelled, icon-led bucket of member element badges. Then the topology relations (Contains, Uses, Attaches) plus the reverse-topology "Referenced by" — each a labelled row of member badges. Member badges link to the element's page, with an href_base prop that lets /components repoint links to its own routes. Driven through the shared ViewEngine `element-composition` arm so /docs and /components stay pixel-identical. A leaf atom with no composition or topology renders nothing.

Readiness
complete
Preview
live
Props
3
Examples
2
Code
implementation mapped

When to use

  • Compound element pages showing what the element is built from
  • Any element with topology — what it contains, uses, attaches, or is used by
  • Linking an element to its structural neighbours with navigable badges

When not to use

  • A leaf atom with no composition or topology — the component renders nothing
  • A flat list of unrelated elements — use an element badge row directly
  • Live instance graphs — this is a type-level structural view

Accessibility

Role: group

  • No keyboard shortcuts

Screen reader: Each composition category and each relation is a section with its heading as the accessible name, and the member badges form labelled lists. Category and relation icons / glyphs are hidden from assistive technology; the member badges keep their own button semantics inside navigable links.

Notes: Empty categories and relations are dropped so assistive tech never meets an empty heading.

Props

NameTypeDefaultDescription
categoriesarrayComposition category buckets (empty for non-compound atoms). Each is a labelled, icon-led group of member element badges.
relationsarrayTopology relation rows — Contains, Uses, Attaches, Referenced by. Each is a labelled row of member element badges.
href_basestring/docs/elements/Link base for member badges. /components repoints this to /components/elements/ so the same component serves both surfaces.

Examples

Composition and relations

A compound element's composition categories and topology.

Conscious Brain

YAML
type: element-composition
props:
  categories:
  - id: conscious
    label: Conscious Brain
    icon: genetics
    members:
    - element_type: brain
      display_name: Brain
      symbol: Br
      icon_name: genetics
      icon_color: '#06B6D4'
      category: intelligence
  relations:
  - label: Contains
    kind: contains
    members:
    - element_type: ears
      display_name: Ears
      symbol: Ea
      icon_name: hearing
      icon_color: '#06B6D4'
      category: intelligence
    - element_type: mouth
      display_name: Mouth
      symbol: Mo
      icon_name: record_voice_over
      icon_color: '#06B6D4'
      category: intelligence
  - label: Referenced by
    kind: referenced_by
    members:
    - element_type: app
      display_name: App
      symbol: Ap
      icon_name: deployed_code
      icon_color: '#8B5CF6'
      category: apps
Relations only

Topology-only relations for a non-compound element.

YAML
type: element-composition
props:
  relations:
  - label: Uses
    kind: uses
    members:
    - element_type: sql
      display_name: SQL
      symbol: Sq
      icon_name: database
      icon_color: '#3B82F6'
      category: data
    - element_type: vector
      display_name: Vector
      symbol: Ve
      icon_name: scatter_plot
      icon_color: '#3B82F6'
      category: data
Edit YAML

element-hexagon

#existingsource

A pointy-top hex tile matching the canvas element footprint. It carries generated element identity metadata plus a reusable state vocabulary for active, pulse, attention, error, and inactive states. Animated states are subtle and respect reduced-motion preferences.

Readiness
complete
Preview
live
Props
11
Examples
2
Code
implementation mapped

When to use

  • Canvas-adjacent element previews
  • Element topology and periodic-table layouts
  • Compact state visualization where shape identity matters

When not to use

  • Text-heavy browse results — use element-card or library-element-card
  • Dense lists — use element-miniature
  • Inline text mentions — use element-badge-inline

Accessibility

Role: img

  • No keyboard shortcuts

Screen reader: The rendered element exposes the display name and state in its accessible label. SVG icon and decoration are hidden from assistive technology.

Notes: State is not conveyed by color alone: each state value is also present in data-state and the accessible label.

Props

NameTypeDefaultDescription
kind*stringKebab-case element type.
symbol*stringShort periodic-table symbol.
name*stringHuman-readable display name.
intentionstringElement intention copy.
category*stringElement category id.
icon_namestringMaterial Symbols icon name.
icon_color*stringCategory or element identity color.
formstringElement form label.
stateenum: none | active | pulse | attention | error | inactivenoneReusable visual lifecycle state.
show_connection_handlebooleanfalseShows the compound/manifest connection handle on the right edge.
selectedbooleanfalseSelected/focused visual state.

Examples

State signals

State vocabulary shown with the same element identity.

YAML
type: stack
props:
  gap: md
  direction: row
  align: center
children:
- type: element-hexagon
  props:
    kind: app
    symbol: Ap
    name: App
    category: apps
    icon_name: deployed_code
    icon_color: '#8B5CF6'
    form: manifest
    state: active
- type: element-hexagon
  props:
    kind: app
    symbol: Ap
    name: App
    category: apps
    icon_name: deployed_code
    icon_color: '#8B5CF6'
    form: manifest
    state: pulse
- type: element-hexagon
  props:
    kind: app
    symbol: Ap
    name: App
    category: apps
    icon_name: deployed_code
    icon_color: '#8B5CF6'
    form: manifest
    state: attention
- type: element-hexagon
  props:
    kind: app
    symbol: Ap
    name: App
    category: apps
    icon_name: deployed_code
    icon_color: '#8B5CF6'
    form: manifest
    state: error
- type: element-hexagon
  props:
    kind: app
    symbol: Ap
    name: App
    category: apps
    icon_name: deployed_code
    icon_color: '#8B5CF6'
    form: manifest
    state: inactive
Selected manifest

Compound/manifest tile with selected and handle states.

YAML
type: element-hexagon
props:
  kind: app
  symbol: Ap
  name: App
  category: apps
  icon_name: deployed_code
  icon_color: '#8B5CF6'
  form: manifest
  state: pulse
  show_connection_handle: true
  selected: true
Edit YAML

element-relationship-map

#existingsource

The cross-cutting view of how element categories wire together. Given nodes (every element ref with its category) and edges (category→category relationship weights), it renders two legible halves: a grid of category cluster cards each holding its element badges, and a list of from→to relationship strands each carrying an edge-count chip. This is deliberately NOT a force-directed graph — a layout of ~78 nodes is unreadable in generated/SSR markup — but the same information expressed as category clusters plus relationship counts. Driven through the shared ViewEngine `element-relationship-map` arm.

Readiness
complete
Preview
live
Props
3
Examples
1
Code
implementation mapped

When to use

  • An overview of how element categories relate across the whole platform
  • A landing visual that orients a reader to the element category map
  • Anywhere a category-level relationship summary beats a node-edge tangle

When not to use

  • A single element's neighbourhood — use element-composition
  • A precise force-directed graph — intentionally rejected as unreadable here
  • Per-instance live relationships — this is a type/category-level view

Accessibility

Role: group

  • No keyboard shortcuts

Screen reader: The cluster grid is a list of category sections, each headed by the category name and element count. The strands are a list whose items spell out "{from} to {to}: {weight} {kind} relationship(s)" so the count and direction are announced without relying on the arrow or chip glyph, both hidden from assistive technology.

Notes: Categories appearing only as a strand endpoint still get a (member-less) cluster card so every strand resolves; relationship counts are conveyed in the accessible name, not by the chip alone.

Props

NameTypeDefaultDescription
nodesarrayEvery element node, each tagged with its category. Nodes are grouped into category cluster cards.
edgesarrayCategory→category relationship strands rendered as from→to rows with an edge-count chip.
href_basestring/docs/elements/Link base for member badges.

Examples

Category constellation

A small category constellation with three clusters and strands.

actions

2

apps

1

data

2

How categories connect

  • actionsdatauses
  • appsactionscontains
  • appsdatacontains
YAML
type: element-relationship-map
props:
  nodes:
  - element_type: python
    symbol: Py
    category: actions
    icon_color: '#84CC16'
  - element_type: rust-fn
    symbol: Rs
    category: actions
    icon_color: '#84CC16'
  - element_type: sql
    symbol: Sq
    category: data
    icon_color: '#3B82F6'
  - element_type: vector
    symbol: Ve
    category: data
    icon_color: '#3B82F6'
  - element_type: app
    symbol: Ap
    category: apps
    icon_color: '#8B5CF6'
  edges:
  - from_category: actions
    to_category: data
    weight: 6
    kind: uses
  - from_category: apps
    to_category: actions
    weight: 3
    kind: contains
  - from_category: apps
    to_category: data
    weight: 2
    kind: contains
Edit YAML

expandable-row

#existingsource

A list/table row that reveals an inline detail panel on click and collapses on click again — the core drill pattern for the dashboard error panel (click an error, see affected runs) and cockpit per-element detail. The `detail` body is lazy (only built when expanded) so heavy drill queries don't run until the user opens the row. Expansion state is local to the row.

Readiness
complete
Preview
live
Props
3
Examples
2
Code
implementation mapped

When to use

  • Drill-in rows where detail is expensive and should load only on open (error → affected runs).
  • Per-item inline detail in a list/table without navigating away.
  • Rows whose expansion is independent of siblings (multiple can be open).

When not to use

  • Accordion behaviour (only one row open at a time) — wrap in a coordinator or use `<Disclosure>`.
  • A static label→value row — use `<DataRow>`.
  • Navigation to a full detail view — use a link/drill, not inline reveal.

Accessibility

Role: button

  • Enter — Toggle expansion (summary is the activation target).
  • Space — Toggle expansion.
  • Tab — Focuses the summary row, then expanded detail content.

Screen reader: The summary is `role=button` with `aria-expanded` reflecting state, so SR users know the row is togglable and its current state. Because detail is lazily built, ensure the expanded content is announced (focus management / live region) when it appears.

Notes: Local state by design. For one-open-at-a-time semantics the caller coordinates externally — don't bolt accordion logic onto the row.

Props

NameTypeDefaultDescription
summaryarrayAlways-visible row header content. Required (slot).
detailarrayReveal body — lazily built only when expanded, so heavy drill queries are deferred. Required (slot).
initially_expandedbooleanfalseWhether the row starts expanded.

Examples

Collapsed drill row

Collapsed error row — summary only, detail deferred until click.

▸ TimeoutError · payment-svc
YAML
type: stack
props:
  direction: row
  gap: md
children:
- type: text
  slots:
    default: ▸ TimeoutError · payment-svc
- type: badge
  props:
    label: 12 runs
Expanded drill row

Expanded state — summary + revealed affected-runs detail.

▾ TimeoutError · payment-svc run_8a1 · 2026-05-16 14:02 · failed run_8a3 · 2026-05-16 14:09 · failed
YAML
type: stack
props:
  direction: column
  gap: sm
children:
- type: text
  slots:
    default: ▾ TimeoutError · payment-svc
- type: text
  slots:
    default: '  run_8a1 · 2026-05-16 14:02 · failed'
- type: text
  slots:
    default: '  run_8a3 · 2026-05-16 14:09 · failed'
Edit YAML

file-preview

#existingsource

Present a file reference compactly: a generic document glyph, the file name, and an optional human-readable meta line ("PDF · 1.2 MB"). It is intentionally content-agnostic — it does not download or render the file (that's the consumer's job) — so every attachment / upload row looks and reads the same.

Readiness
complete
Preview
live
Props
2
Examples
3
Code
implementation mapped

When to use

  • An attachment row on a message or record
  • An uploaded-file confirmation chip
  • A reference to a file the user can act on elsewhere

When not to use

  • Rendering image content — use Image
  • Playing audio/video — use MediaPlayer
  • A full file browser / tree — use Tree

Accessibility

Role: group

  • No keyboard shortcuts

Screen reader: The chip is role=group with an aria-label of the file name; the glyph is aria-hidden decoration and the name + meta are real text.

Notes: The icon is decorative — the file name is the accessible content, so a missing/instructive name is never masked by the glyph.

Props

NameTypeDefaultDescription
namestringfileFile name (with extension).
metastringOptional size / kind line (e.g. 'PDF · 1.2 MB').

Examples

Document

A document with size.

q3-report.pdfPDF · 1.2 MB
YAML
type: file-preview
props:
  name: q3-report.pdf
  meta: PDF · 1.2 MB
Name only

A file with no meta line.

notes.txt
YAML
type: file-preview
props:
  name: notes.txt
Archive

A code archive.

build.tar.gzArchive · 48 MB
YAML
type: file-preview
props:
  name: build.tar.gz
  meta: Archive · 48 MB
Edit YAML

gauge

#existingsource

A circular progress ring for a single ratio/percentage tile — success-rate, resource utilisation, eval pass-rate. Pure SVG (ghost backing ring + stroked arc), SSR-safe, no chart library. `value/max` sets the fill (default `max: 1.0` so `value` can be a direct fraction); `tone` selects the stroke palette. Use `<DonutChart>` instead when you have a categorical breakdown rather than one ratio.

Readiness
complete
Preview
live
Props
6
Examples
2
Code
implementation mapped

When to use

  • A single headline ratio tile — "61% worked", storage used/limit, eval pass-rate.
  • Dashboard KPI rings where the centre carries the number + a label line.
  • A SSR-rendered progress dial (no runtime chart JS).

When not to use

  • A categorical breakdown (mail/phone/agents share) — use `<DonutChart>`.
  • A trend over time — use `<Sparkline>`.
  • A linear progress bar — use a progress primitive, not a circular gauge.

Accessibility

Role: img

  • No keyboard shortcuts

Screen reader: The SVG is decorative; `aria_label` MUST carry the value in words (e.g. "CPU usage 73%"). The arc geometry alone gives a screen-reader user nothing.

Notes: Tone is reinforcement, not the sole signal — the numeric label / aria_label carries meaning so colour-blind and SR users are covered.

Props

NameTypeDefaultDescription
valuenumberCurrent value (clamped to [0, max]). Reactive. Required.
maxnumber1.0Upper bound. Default 1.0 so `value` can be a direct fraction.
toneenum: primary | success | warning | error | mutedprimaryStroke palette. Reinforces — not the sole signal.
sizeinteger72Diameter in px.
labelstringOptional centre label; omitted → renders the percentage.
aria_labelstringSR text carrying the value in words (e.g. "CPU usage 73%").

Examples

Success-rate gauge

Success-rate KPI ring with centre percentage.

◯ 61% Run success rate
YAML
type: stack
props:
  direction: column
  gap: sm
children:
- type: text
  slots:
    default: ◯ 61%
- type: text
  slots:
    default: Run success rate
Storage utilisation (warning)

Warning-tone utilisation gauge near its limit.

◯ 88% Storage used (88 / 100 GB)
YAML
type: stack
props:
  direction: column
  gap: sm
children:
- type: text
  slots:
    default: ◯ 88%
- type: text
  slots:
    default: Storage used (88 / 100 GB)
Edit YAML

icon

#existingsource

A single inline glyph resolved from a stable key via the shared icon set. Decorative by default; pass `title` to give it an accessible label.

Readiness
complete
Preview
live
Props
4
Examples
3
Code
implementation mapped

When to use

  • A small decorative or labelled glyph inside a row of text or a button
  • Status / category affordances rendered from a known icon key
  • Any engine spec that needs a vector glyph without raw <svg>

When not to use

  • A clickable icon-only control — use a button with an icon variant
  • A large illustrative graphic — that is not an icon
  • An arbitrary uploaded image — use the image primitive

Accessibility

Role: img

  • No keyboard shortcuts

Screen reader: With no `title`, the glyph is decorative and hidden from assistive tech. With `title`, it exposes an accessible name. Never rely on an icon alone to convey state to screen-reader users — pair with text.

Notes: `title` is the only accessibility input; absent it, the icon must be purely decorative (its meaning carried by adjacent text).

Props

NameTypeDefaultDescription
namestringsettingsStable icon key resolved against the shared icon set (e.g. settings, terminal, check).
sizestring20Square edge length in px, as a string (e.g. "16", "20", "24").
classstringExtra CSS class(es) appended to the glyph.
titlestringAccessible label. When set, the glyph is exposed to assistive tech; when empty, it is decorative.

Examples

Settings icon

A labelled settings glyph at the default size.

YAML
type: icon
props:
  name: settings
  size: '20'
  title: Settings
Icon + label

A decorative status glyph next to a label.

Ready
YAML
type: stack
props:
  direction: row
  gap: sm
  align: center
children:
- type: icon
  props:
    name: check
    size: '16'
- type: text
  props:
    kind: muted
    value: Ready
Sizes gallery

Sizes side-by-side.

YAML
type: stack
props:
  direction: row
  gap: md
  align: center
children:
- type: icon
  props:
    name: terminal
    size: '16'
    title: small
- type: icon
  props:
    name: terminal
    size: '24'
    title: medium
- type: icon
  props:
    name: terminal
    size: '32'
    title: large
Edit YAML

identity-chip

#existingsource

A presentation-only chip that renders an identity — a Contact, an Organization, or a pursuit's primary contact — with one shared vocabulary: avatar initials, name, role, and organization. The caller supplies the fields; the chip never fetches, so it is side-effect-free and safe to drop into any surface. The `density` prop selects one of four shapes: `compact` (inline person line), `row` (avatar beside a two-line name/role + organization block), `header` (large avatar disc with name, role, organization, phone, and email for a modal header), and `line` (plain-text one-line fallback for dense lists).

Readiness
complete
Preview
live
Props
6
Examples
2
Code
implementation mapped

When to use

  • The contact line inside a kanban card body or a pursuit row.
  • A leads / address-book list row (`density: row`).
  • The header of an entity-detail modal (`density: header`).
  • A one-line identity in a dense table or activity row (`density: compact` or `line`).

When not to use

  • An interactive identity that opens a profile on click — wrap the chip in a button or link; the chip itself is not interactive.
  • A standalone profile picture with no name — use `<Avatar>`.
  • Element identity (icon + colour + type name) — use `<ElementBadge>`.
  • A free-form label or tag — use `<Tag>`.

Accessibility

Role: group

  • No keyboard shortcuts

Screen reader: The chip is plain text — name, role, and organization are read in document order. In `density: header` the name renders as an `<h2>`, which is the heading an enclosing entity-detail modal points its `aria-labelledby` at. Keep the supplied `name` meaningful; a chip built from only an email or phone reads that value verbatim.

Notes: The chip emits no explicit ARIA role today — it is presentational. The avatar initials disc and the Material Symbols glyphs (person / domain / phone / mail) are decorative and should carry `aria-hidden` so they are not read as stray characters; pair the chip with meaningful text rather than relying on the glyph alone.

Props

NameTypeDefaultDescription
densityenum: compact | row | header | linecompact
namestringPrimary identity label. Falls back to email, then phone, when absent.
rolestringOptional role or title shown after the name (e.g. "VP Engineering").
organizationstringOptional organization, shown on the secondary line in row and header densities.
phonestringOptional phone number — shown only in header density; also feeds initials and name fallback.
emailstringOptional email — shown only in header density; also feeds initials and name fallback.

Examples

Compact identity

Compact density — the inline person line used in activity rows and kanban card bodies.

Sarah Chen · VP Engineering
YAML
type: stack
props:
  direction: row
  gap: sm
  align: center
children:
- type: icon
  props:
    name: person
- type: text
  slots:
    default: Sarah Chen
- type: text
  slots:
    default: ·
- type: text
  slots:
    default: VP Engineering
Row identity

Row density — avatar initials beside a two-line name/role and organization block.

SC
Sarah Chen · VP Engineering Northwind Traders
YAML
type: stack
props:
  direction: row
  gap: sm
  align: center
children:
- type: badge
  props:
    variant: primary
  slots:
    default: SC
- type: stack
  props:
    direction: column
    gap: sm
  children:
  - type: text
    slots:
      default: Sarah Chen · VP Engineering
  - type: text
    slots:
      default: Northwind Traders
Edit YAML

image

#existingsource

Display an image inside a frame whose aspect ratio is pinned so the page does not reflow while the image loads. `fit` chooses cover (crop to fill — thumbnails) or contain (letterbox — logos). When `src` is empty a token-styled placeholder is shown instead.

Readiness
complete
Preview
live
Props
4
Examples
3
Code
implementation mapped

When to use

  • Thumbnails and avatars-as-images in a grid or list
  • Hero / preview imagery where layout stability matters
  • Any image that should not cause layout shift while loading

When not to use

  • Decorative background textures — use CSS
  • Identity chips with initials fallback — use Avatar
  • Inline SVG icons — use Icon

Accessibility

Role: img

  • No keyboard shortcuts

Screen reader: Pass real `alt` for meaningful images; pass an empty string for decorative ones. The placeholder state exposes the same alt via role=img + aria-label so the slot is still announced meaningfully.

Notes: Never omit `alt`. Empty alt is a deliberate "decorative" signal, not a missing-text bug.

Props

NameTypeDefaultDescription
srcstringImage URL. Empty renders the placeholder frame.
altstringAlt text. Empty string = decorative.
ratiostring16 / 9CSS aspect-ratio value (e.g. '16 / 9', '1').
fitenum: cover | containcover

Examples

Placeholder

An empty 16:9 frame showing the placeholder state.

YAML
type: image
props:
  ratio: 16 / 9
  alt: Preview unavailable
Square / contain

A square contain frame.

YAML
type: image
props:
  ratio: '1'
  fit: contain
  alt: Logo
Banner ratio

A wide banner ratio placeholder.

YAML
type: image
props:
  ratio: 21 / 9
  alt: Banner
Edit YAML

item-list

#existingsource

A thin vertical list container that owns the empty-state branch so callers stop reinventing `if items.is_empty() { empty } else { list }`. When `empty`, it renders `empty_message`; otherwise it renders its children. It is the container, not the rows — compose `<KeyValue>`, `<DataRow>`, or custom rows inside it.

Readiness
complete
Preview
live
Props
3
Examples
2
Code
implementation mapped

When to use

  • Any vertical list that should show a calm message when there are zero items.
  • Wrapping a set of KeyValue/DataRow rows with consistent list styling.
  • List surfaces where the empty case is common (env vars, connections, members).

When not to use

  • A rich empty state with icon + action — wrap `<EmptyState>` / `<PanelEmptyState>` directly.
  • A data table with columns/sorting — use a table component.
  • A single row — just render the row; the list wrapper adds nothing.

Accessibility

Role: list

  • No keyboard shortcuts

Screen reader: `role=list`; children should be list items. The empty branch replaces the list with a short message — make `empty_message` a meaningful sentence ("No connections yet"), not a bare "Empty", so SR users get the same information sighted users do.

Notes: For a pre-data empty state that needs an icon + call-to-action, the caller should render `<PanelEmptyState>` in the empty branch rather than relying on the plain `empty_message` string.

Props

NameTypeDefaultDescription
emptybooleanfalseWhether the list is empty (renders `empty_message` instead of children).
empty_messagestringNo itemsMessage shown when `empty`. Make it a meaningful sentence, not a bare "Empty".
childrenarrayList rows (KeyValue / DataRow / custom). Rendered when not empty.

Examples

Populated list

Populated list wrapping config rows.

API_BASE = https://triform.dev TIMEOUT = 30 RETRIES = 3
YAML
type: stack
props:
  direction: column
  gap: sm
children:
- type: text
  slots:
    default: API_BASE = https://triform.dev
- type: text
  slots:
    default: TIMEOUT  = 30
- type: text
  slots:
    default: RETRIES  = 3
Empty list

Empty branch — calm meaningful message, not a bare 'Empty'.

No environment variables set
YAML
type: text
slots:
  default: No environment variables set
Edit YAML

json-viewer

#existingsource

Display a JSON value for inspection: pretty-printed (2-space indent), monospace, scrollable, in a labelled region. It replaces ad-hoc `<pre>{stringify}</pre>` debug dumps with one consistent surface. Collapsible nodes / syntax colouring are deliberately out of scope — bundling a JSON tokeniser into the showcase bundle is the wrong trade, and the value is fully readable without it.

Readiness
complete
Preview
live
Props
1
Examples
3
Code
implementation mapped

When to use

  • Inspecting an API response / payload
  • Showing element config or run output for debugging
  • Any 'here is the raw JSON' read-only surface

When not to use

  • Editable JSON — use code-input
  • An interactive collapsible object explorer — out of scope
  • Non-JSON code — use code-block

Accessibility

Role: region

  • No keyboard shortcuts

Screen reader: Wrapped in role=region + aria-label "JSON" so it can be reached and skipped; the content is a real <pre><code> exposing the value verbatim.

Notes: Indentation conveys structure visually; the verbatim text in the <pre> is the source of truth for assistive tech.

Props

NameTypeDefaultDescription
jsonanyThe value to display. Objects are pretty-printed; a string is shown as-is.

Examples

Payload

An element invocation payload.

{
  "circle": "acme",
  "element": "summarize",
  "input": {
    "text": "hello world"
  }
}
YAML
type: json-viewer
props:
  json:
    circle: acme
    element: summarize
    input:
      text: hello world
Run result

A short run-result object.

{
  "duration_ms": 1240,
  "status": "ok",
  "tokens": 318
}
YAML
type: json-viewer
props:
  json:
    status: ok
    duration_ms: 1240
    tokens: 318
Array

An array value.

[
  "alpha",
  "beta",
  "gamma"
]
YAML
type: json-viewer
props:
  json:
  - alpha
  - beta
  - gamma
Edit YAML

kbd

#existingsource

A compact visual treatment for a single key or a key combination. Use it so shortcut notation reads identically everywhere — a documentation page, a command-palette hint, a menu accelerator. The content is the key label(s); the component supplies the consistent chrome.

Readiness
complete
Preview
live
Props
1
Examples
3
Code
implementation mapped

When to use

  • Keyboard shortcuts in documentation
  • Command-palette accelerator hints
  • Menu / toolbar rows that show an accelerator

When not to use

  • Inline code or tokens that are not keyboard input — use code-block
  • Long prose instructions
  • Button labels — use Button or IconButton

Accessibility

Role: presentation

  • No keyboard shortcuts

Screen reader: Renders a semantic <kbd> element so assistive tech announces the content as keyboard input rather than plain text.

Notes: Keep the label to the actual key name(s). For a combination, render separate kbd chips joined by a visible "+" so each key is clear.

Props

NameTypeDefaultDescription
classstringExtra classes appended after the base kbd class.

Examples

Single combo

A command-palette open shortcut.

+K
YAML
type: stack
props:
  gap: xs
  direction: row
  align: center
children:
- type: kbd
  slots:
    default: ⌘
- type: text
  slots:
    default: +
- type: kbd
  slots:
    default: K
Inline hint

An inline 'press Esc to close' hint.

PressEsc to close
YAML
type: stack
props:
  gap: xs
  direction: row
  align: center
children:
- type: text
  slots:
    default: Press
- type: kbd
  slots:
    default: Esc
- type: text
  slots:
    default: to close
Keys

A small set of single keys.

Enter
YAML
type: stack
props:
  gap: sm
  direction: row
  align: center
children:
- type: kbd
  slots:
    default: ↑
- type: kbd
  slots:
    default: ↓
- type: kbd
  slots:
    default: Enter
Edit YAML

key-value

#existingsource

The `name = value` row for environment variables, configs, and secrets. Shows an `=` separator, an optional `source` badge ("[parent]", "[circle]"), masks the value as `••••••••` when `masked` (secrets), applies inherited styling when `inherited`, and exposes an `actions` slot for edit/delete. Use `<DataRow>` for plain label→value detail lines; reach for KeyValue when the row is config that can be inherited, masked, or acted on.

Readiness
complete
Preview
live
Props
5
Examples
2
Code
implementation mapped

When to use

  • Environment-variable / config rows with an inheritance source.
  • Secret values that must mask by default (`masked: true`).
  • Config rows that need inline edit/delete actions.

When not to use

  • Plain detail label→value lines — use `<DataRow>`.
  • A multi-row semantic block — wrap rows in `<DefinitionList>` for `<dl>` semantics.
  • Editable form fields — use `<Field>` / `<Input>`; KeyValue is a display row with optional actions, not a form control.

Accessibility

Role: presentation

  • Tab — Moves into the actions slot (edit/delete) when present.

Screen reader: name / value / source read in order. Masked values announce as the mask glyphs — ensure a reveal control exists in the actions slot if SR users legitimately need the secret; never make the value SR-unreachable when it is required for the task.

Notes: `masked` is a display default, not security — the real value is still in the DOM unless the consumer withholds it. Treat masking as shoulder-surfing defence only.

Props

NameTypeDefaultDescription
namestringVariable/key name (left of `=`). Required.
valuestringValue (right of `=`). Required; rendered masked when `masked`.
sourcestringOptional inheritance/source badge ([parent], [circle], [override]).
inheritedbooleanfalseMuted styling for inherited values. Pair with a `source` badge.
maskedbooleanfalseRender the value as `••••••••` (shoulder-surfing defence only — not security; value is still in the DOM unless withheld upstream).

Examples

Env config rows

Env vars with inheritance source — the common config shape.

API_BASE = https://triform.dev [circle] TIMEOUT = 30 [parent]
YAML
type: stack
props:
  direction: column
  gap: sm
children:
- type: text
  slots:
    default: API_BASE = https://triform.dev  [circle]
- type: text
  slots:
    default: TIMEOUT  = 30  [parent]
Masked secret

Masked secret with an actions slot (reveal/edit).

API_KEY = ••••••••
YAML
type: stack
props:
  direction: row
  gap: md
children:
- type: text
  slots:
    default: API_KEY = ••••••••
- type: icon-button
  props:
    icon: visibility
    aria_label: Reveal
- type: icon-button
  props:
    icon: edit
    aria_label: Edit
Edit YAML

library-element-card

#existingsource

A compact reusable glass element card for the Library panel and dense pickers. It presents the element icon, name, type label, and intention while preserving the same height when intention is missing. This keeps browse/search lists aligned while authors progressively fill metadata.

Readiness
complete
Preview
live
Props
11
Examples
3
Code
implementation mapped

When to use

  • Library browse and semantic search results
  • Dense element pickers where cards still need enough context to compare
  • Cards for element instances that may have custom avatars

When not to use

  • Full element-type catalog pages — use element-card
  • Tiny inline references — use element-badge-inline
  • Generic dashboard cards unrelated to elements — use card

Accessibility

Role: group

  • No keyboard shortcuts

Screen reader: The parent button or link supplies the actionable label. The card's icon is decorative; the visible name and intention remain real text.

Notes: Keep the card inside a single interactive parent. Do not put buttons inside the card body.

Props

NameTypeDefaultDescription
name*stringHuman-readable element instance name.
intentionstringElement intention. Empty still reserves the same vertical space.
meta_labelstringShort element type or category label shown on the trailing edge.
icon_namestringMaterial Symbols icon fallback.
icon_svg_htmlstringRaw SVG markup from generated element metadata.
colorstringElement/category identity color.
state_colorstringStatus dot color.
avatar_urlstringOptional avatar image URL. Falls back to icon if it fails.
folderbooleanfalseShows a quiet chevron for drillable compound/folder items.
activebooleanfalseFocused/selected visual state.
loadingbooleanfalseReduced-opacity busy state.

Examples

Library card

Library item with intention copy.

Month EndReconcile invoices and close the reporting period.App
YAML
type: library-element-card
props:
  name: Month End
  intention: Reconcile invoices and close the reporting period.
  meta_label: App
  icon_name: deployed_code
  color: '#8B5CF6'
  state_color: '#F5D96E'
Missing intention

Library item with no intention still holds the same rhythm.

ReviewApp
YAML
type: library-element-card
props:
  name: Review
  intention: ''
  meta_label: App
  icon_name: deployed_code
  color: '#8B5CF6'
  state_color: '#F5D96E'
  folder: true
Typed instance

Library item showing a different element identity in the same reusable shape.

Daniel CFO CommentaryDraft the month-end commentary and route it for approval.Modifier
YAML
type: library-element-card
props:
  name: Daniel CFO Commentary
  intention: Draft the month-end commentary and route it for approval.
  meta_label: Modifier
  icon_name: chat_bubble
  color: '#F97316'
  state_color: '#F5D96E'
Edit YAML

markdown-view

#existingsource

Apply the platform's typographic rhythm (headings, lists, code, links via tokens) to long-form content so generated docs feel like part of the app shell. It accepts EITHER caller-sanitised pre-rendered HTML (the caller owns parsing + sanitisation) OR a plain-text fallback. It deliberately does not embed a markdown parser — keeping the contract truthful: styling is real; the parse step is the caller's. Heading decoration is configurable so the Triform identity accent can stay coherent while the visual language keeps evolving.

Readiness
complete
Preview
live
Props
4
Examples
4
Code
implementation mapped

When to use

  • Rendering already-parsed, sanitised documentation HTML
  • Element READMEs whose HTML is produced server-side
  • Any long-form prose that should match the app's type scale

When not to use

  • Short labels or inline helper text
  • Editable rich text — needs an editor, not a viewer
  • Untrusted HTML — sanitise before passing `html`

Accessibility

Role: article

  • No keyboard shortcuts

Screen reader: Rendered inside a prose container. When `html` is supplied the caller's semantic structure (headings, lists, links) is preserved verbatim; the plain-text fallback is a single readable block.

Notes: Heading order and semantics are the responsibility of the caller-supplied HTML — this surface only styles it, it does not rewrite structure.

Props

NameTypeDefaultDescription
htmlstringCaller-sanitised pre-rendered HTML. Takes precedence over `text`.
textstringPlain-text fallback when no rendered HTML is supplied.
densityenum: document | panel | chatdocumentTypographic density. `document` uses full prose rhythm; `panel` and `chat` compact the scale.
heading_accentenum: subtle | brand | nonesubtleHeading rule treatment for section headings. `subtle` keeps the rule quiet; `brand` opts into the CTA accent.

Examples

Rendered HTML

Pre-rendered HTML styled by the prose surface.

Overview

This element summarizes text using a small model.

  • Fast
  • Cheap
YAML
type: markdown-view
props:
  html: <h2>Overview</h2><p>This element summarizes text using a small model.</p><ul><li>Fast</li><li>Cheap</li></ul>
  density: document
  heading_accent: subtle
Plain text

Plain-text fallback.

No rendered HTML supplied — this is the plain-text fallback block.

YAML
type: markdown-view
props:
  text: No rendered HTML supplied — this is the plain-text fallback block.
With code

An HTML snippet with a code sample.

Command

Run:

cargo run
YAML
type: markdown-view
props:
  html: <h3>Command</h3><p>Run:</p><pre><code>cargo run</code></pre>
  density: panel
Chat density

Compact prose for streaming or chat surfaces.

Done. I updated the schema and kept the generated output in sync.

  • No restart required
  • Ready for review
YAML
type: markdown-view
props:
  html: <p><strong>Done.</strong> I updated the schema and kept the generated output in sync.</p><ul><li>No restart required</li><li>Ready for review</li></ul>
  density: chat
  heading_accent: none
Edit YAML

media-player

#existingsource

Play an audio or video source inside a token-styled frame using the browser's native controls. Native controls are a deliberate choice — they are keyboard-complete, screen-reader-friendly, and support captions for free; a hand-rolled control bar would regress all of that for no benefit at this layer.

Readiness
complete
Preview
live
Props
4
Examples
3
Code
implementation mapped

When to use

  • Playing a recording, screencast, or audio note
  • Embedding a short video preview
  • Any inline media that needs standard playback controls

When not to use

  • Static images — use Image
  • A file the user only references (not plays) — use FilePreview
  • Bespoke synchronized media UX — out of scope

Accessibility

Role: group

  • Space — Toggle play / pause (native control behaviour)
  • ArrowLeft — Seek backward (native control behaviour)
  • ArrowRight — Seek forward (native control behaviour)

Screen reader: The element renders native `controls`, so all playback affordances come with the browser's built-in accessible names, focus order, and keyboard model. The frame is role=group with an aria-label.

Notes: Keyboard behaviour is the browser's, not re-implemented — which is exactly why native controls are used. Provide captions on the source for video where applicable.

Props

NameTypeDefaultDescription
srcstringMedia source URL.
kindenum: video | audiovideo
posterstringOptional poster image (video only).
labelstringMedia playerAccessible label for the player frame.

Examples

Video

A video player frame.

YAML
type: media-player
props:
  kind: video
  label: Screencast
  src: ''
Audio

An audio player frame.

YAML
type: media-player
props:
  kind: audio
  label: Voice note
  src: ''
Poster

Video with a poster.

YAML
type: media-player
props:
  kind: video
  label: Demo
  src: ''
  poster: ''
Edit YAML

ops-intent-strip

#existingsource

The "what can this element DO" surface. One chip per operation an element exposes, each carrying an intent-coloured status dot (read=grey, create=green, change=amber, delete=red, run=blue), the operation name in mono, and a small method tag. Driven through the shared ViewEngine `ops-intent-strip` arm so the /docs element page and the /components atlas render it identically. Intent is never colour-only: every chip spells out its intent in the accessible name.

Readiness
complete
Preview
live
Props
1
Examples
2
Code
implementation mapped

When to use

  • Element documentation pages summarising the element's operations
  • Compact operation overviews where a verb + method is enough
  • Anywhere the read/create/change/delete/run intent should scan at a glance

When not to use

  • Full operation reference with parameters — use a definition list or table
  • A single operation call-to-action — use a button
  • Operation execution UI — this is a read-only summary, not a runner

Accessibility

Role: list

  • No keyboard shortcuts

Screen reader: The strip is a list and each chip a list item with an accessible name of "{name} ({intent}): {description}", so intent and purpose are announced without relying on the dot colour. The status dot and method glyphs are hidden from assistive technology.

Notes: Intent is conveyed redundantly — by dot colour, by the data-intent attribute, and in the accessible name — so it is never colour-only.

Props

NameTypeDefaultDescription
ops*arrayThe operations to render, one chip each. Order is preserved (the generator pre-sorts universal, category, then element). An empty list renders nothing.

Examples

Operation intents

Full intent vocabulary across the five verbs.

  • readGET
  • createPOST
  • updatePATCH
  • deleteDELETE
  • invokePOST
YAML
type: ops-intent-strip
props:
  ops:
  - name: read
    intent: read
    method: GET
    description: Fetch the current value.
  - name: create
    intent: create
    method: POST
    description: Create a new instance.
  - name: update
    intent: change
    method: PATCH
    description: Change an existing instance.
  - name: delete
    intent: delete
    method: DELETE
    description: Remove the instance.
  - name: invoke
    intent: run
    method: POST
    description: Run the element with input.
Action operations

A typical action element's operation summary.

  • invokePOST
  • readGET
YAML
type: ops-intent-strip
props:
  ops:
  - name: invoke
    intent: run
    method: POST
    description: Run the function and return its result.
  - name: read
    intent: read
    method: GET
    description: Read the function definition.
Edit YAML

port-diagram

#existingsource

An element's declared ports rendered as two legible columns — Inputs on the left, Outputs on the right — separated by a small central element glyph. Each port is a pill with a direction caret, the port name in mono, the port type as a small tag, and a required marker. Deliberately a flex 2-column layout, not an SVG wiring diagram: SVG edge-routing is fragile to emit from generated code and unreadable in SSR, while the two columns carry the same information robustly. Driven through the shared ViewEngine `port-diagram` arm for /docs ↔ /components parity.

Readiness
complete
Preview
live
Props
1
Examples
2
Code
implementation mapped

When to use

  • Element documentation showing what an element consumes and produces
  • Compact port overviews where direction + type + required is enough
  • Any element with a meaningful input/output port contract

When not to use

  • Full port schemas with nested fields — use a schema view or table
  • Live wiring between concrete instances — this is a static type-level view
  • Elements with no ports — the component renders nothing

Accessibility

Role: list

  • No keyboard shortcuts

Screen reader: Each column is a labelled list headed by "Inputs" or "Outputs" (shown only for the non-empty side). Each port's accessible name spells out "{direction} {name} ({port_type}), required: {description}" so direction and requiredness are announced without relying on the caret or the asterisk glyph, both of which are hidden from assistive technology.

Notes: Direction is conveyed redundantly by column, by the data-direction attribute, and in the accessible name — never by the caret glyph alone.

Props

NameTypeDefaultDescription
ports*arrayThe ports to render, split into the Inputs / Outputs columns by direction. An empty list renders nothing.

Examples

Request and response ports

A request/response element with required and optional ports.

Inputs

  • coderequest
  • inputjson

Outputs

  • resultresponse
  • errorerror
YAML
type: port-diagram
props:
  ports:
  - name: code
    direction: input
    port_type: request
    required: true
    description: Source code to execute.
  - name: input
    direction: input
    port_type: json
    required: false
    description: Optional structured input payload.
  - name: result
    direction: output
    port_type: response
    required: false
    description: Execution result and stdout.
  - name: error
    direction: output
    port_type: error
    required: false
    description: Error detail when the run fails.
Inputs only

An input-only trigger element (outputs column stays header-less).

Inputs

  • payloadevent
YAML
type: port-diagram
props:
  ports:
  - name: payload
    direction: input
    port_type: event
    required: true
    description: The triggering event payload.
Edit YAML

qr-code

#existingsource

A QR code rendered as inline SVG computed in Rust — SSR-safe, no runtime QR library. Encodes `data` at `size` px with token-driven `colors`, a `style` (rounded/square modules), and an optional centre Triform logo. On an encoding failure it renders a calm `role=alert` error block, not a broken image.

Readiness
complete
Preview
live
Props
5
Examples
2
Code
implementation mapped

When to use

  • Pairing / sign-in / wallet-auth flows that hand off to a phone (scan to continue).
  • Any URL or token a user should scan rather than type.
  • SSR pages needing a QR without shipping a client QR library.

When not to use

  • Encoding large payloads — QR density makes big data unscannable; link to it instead.
  • A decorative graphic — QR is functional; don't use it as ornament.
  • Dynamic data that changes faster than a user can scan.

Accessibility

Role: img

  • No keyboard shortcuts

Screen reader: `aria_label` MUST describe what the QR encodes and the non-scan path ("QR code for sign-in URL — or open triform.dev/auth on this device"). A QR is unusable by a screen-reader user on the same device; always provide the underlying link/code in text too.

Notes: Never make a QR the ONLY path through a flow — pair with the raw URL/code so non-scanning and SR users can proceed.

Props

NameTypeDefaultDescription
datastringThe string to encode (URL, token). Required. Keep it short to stay scannable.
sizeinteger256Width = height in px.
styleenum: rounded | squareroundedModule shape.
with_logobooleantrueShow the Triform logo in the centre (uses error-correction headroom).
aria_labelstringSR text describing what the QR encodes + the non-scan path.

Examples

Sign-in QR

Sign-in QR paired with the raw URL (never QR-only).

▣ [QR] Scan to sign in, or open triform.dev/auth?s=abc123
YAML
type: stack
props:
  direction: column
  gap: sm
children:
- type: text
  slots:
    default: ▣ [QR]
- type: text
  slots:
    default: Scan to sign in, or open triform.dev/auth?s=abc123
QR error fallback

Encoding-failure fallback — calm error block, not a broken image.

QR Error: payload too large
YAML
type: stack
props:
  direction: row
  gap: sm
children:
- type: icon
  props:
    name: error_outline
- type: text
  slots:
    default: 'QR Error: payload too large'
Edit YAML

sparkline

#existingsource

A tiny inline trend line for dashboard headline tiles and category cards — ~30 points in ~160×32, no axes, no labels, no legend. It answers "is this going up or down right now?" at a glance; detail belongs in the drill view. Pure SVG `<polyline>` computed in Rust (SSR-safe, zero runtime JS). `trend` (Up/Down/Neutral) sets the stroke colour; empty/constant data draws a flat midline so the tile never visually collapses.

Readiness
complete
Preview
live
Props
5
Examples
2
Code
implementation mapped

When to use

  • An at-a-glance trend beside a KPI number (emails sent last 24h, error rate).
  • Category cards where direction matters more than exact values.
  • Any SSR tile that needs a trend without a chart library.

When not to use

  • A readable chart with axes/values — use a full chart component in the drill view.
  • A single ratio — use `<Gauge>`.
  • A categorical split — use `<DonutChart>`.

Accessibility

Role: img

  • No keyboard shortcuts

Screen reader: The SVG is decorative; pair with an `aria_label` describing the trend in words ("Emails sent, last 24 hours, trending up"). The line shape alone is meaningless to a screen-reader user.

Notes: `trend` colour reinforces direction for sighted users; the aria_label is what carries it for everyone else. Leave `trend: neutral` to auto-infer from first-vs-last.

Props

NameTypeDefaultDescription
valuesarrayData points, left-to-right chronologically. ≤60 render cleanly; more are valid but visually dense. Reactive. Required.
trendenum: neutral | up | downneutralStroke-colour direction hint. `neutral` (default) auto-infers from first-vs-last value.
widthinteger160Render box width in px.
heightinteger32Render box height in px.
aria_labelstringSR description of the trend ("CPU last 24h, trending up").

Examples

KPI with up-trend

Up-trend sparkline beside a KPI number — the canonical tile shape.

1,204 ╱╱╱ ↑
YAML
type: stack
props:
  direction: row
  gap: md
children:
- type: text
  slots:
    default: 1,204
- type: text
  slots:
    default: ╱╱╱ ↑
Down-trend

Down-trend sparkline (error-rate going the wrong way).

0.82% ╲╲╲ ↓
YAML
type: stack
props:
  direction: row
  gap: md
children:
- type: text
  slots:
    default: 0.82%
- type: text
  slots:
    default: ╲╲╲ ↓
Edit YAML

table

#existingsource

A tokenised tabular surface for dense comparison or reference data where columns and rows carry meaning. It keeps native <table> / <th scope> semantics so assistive tech and the platform stay in agreement. Interactive product tables (sort, select, paginate) layer those behaviours on top — this primitive is the read-only base.

Readiness
complete
Preview
live
Props
3
Examples
3
Code
implementation mapped

When to use

  • Reference matrices and generated property tables
  • Dense operational data with clear columns
  • Read-only markdown tables that need horizontal overflow

When not to use

  • Small key/value summaries — use DefinitionList or DataRow
  • Card collections where cross-column comparison isn't needed
  • Virtualised datasets — out of scope here

Accessibility

Role: table

  • No keyboard shortcuts

Screen reader: Native <table> with <thead>, <th scope=col> and an optional <caption> — assistive tech announces it as a real data table with column headers. No bespoke grid keyboard model is layered on (a static table doesn't need one and faking it would mislead).

Notes: `aria-sort` is intentionally absent because this primitive does not sort — adding it without real sorting would be a false signal.

Props

NameTypeDefaultDescription
columnsarrayColumn header labels.
rowsarrayRows; each row is a list of stringified cells.
captionstringOptional accessible table caption.

Examples

Reference

An element reference table.

Element categories
CategoryElements
actionspython, rust-fn, go-fn
datasql, vector, graph
iohttp, slack, email
YAML
type: table
props:
  caption: Element categories
  columns:
  - Category
  - Elements
  rows:
  - - actions
    - python, rust-fn, go-fn
  - - data
    - sql, vector, graph
  - - io
    - http, slack, email
Metrics

A small metrics table.

RunStatusDuration
#1024ok1.2s
#1025failed0.4s
YAML
type: table
props:
  columns:
  - Run
  - Status
  - Duration
  rows:
  - - '#1024'
    - ok
    - 1.2s
  - - '#1025'
    - failed
    - 0.4s
Plain

A two-column table, no caption.

KeyValue
regionfsn1
replicas3
YAML
type: table
props:
  columns:
  - Key
  - Value
  rows:
  - - region
    - fsn1
  - - replicas
    - '3'
Edit YAML

tag

#existingsource

A small read-only rectangular label for an arbitrary label with no semantic meaning — a language ("rust"), a version ("v1.2"), a topic keyword. Tag deliberately has no tone ladder: that is Badge's job (status). Clicking a Tag does nothing; for an interactive filter use FilterChip.

Readiness
complete
Preview
live
Props
1
Examples
3
Code
implementation mapped

When to use

  • Free-form keyword / topic labels on a card or row
  • Version or language markers
  • Any non-semantic, non-interactive label

When not to use

  • Semantic status (Active/Failed/…) — use Badge
  • An interactive filter toggle — use FilterChip
  • A numeric counter on a rail item — use CounterPill

Accessibility

Role: presentation

  • No keyboard shortcuts

Screen reader: Reads its text content. Tag is decorative chrome around a label; keep the label itself meaningful (don't rely on adjacency).

Notes: Tag carries no colour-coded meaning, so there is no colour-only information to mitigate — it is intentionally tone-neutral.

Props

NameTypeDefaultDescription
classstringExtra classes appended after the base tag class.

Examples

Keywords

Keyword tags on a project card.

rustleptoswasm
YAML
type: stack
props:
  gap: xs
  direction: row
  align: center
children:
- type: tag
  slots:
    default: rust
- type: tag
  slots:
    default: leptos
- type: tag
  slots:
    default: wasm
Version

A single version marker.

v1.2.0
YAML
type: tag
slots:
  default: v1.2.0
Topics

A row of topic tags.

dataioagents
YAML
type: stack
props:
  gap: xs
  direction: row
  align: center
children:
- type: tag
  slots:
    default: data
- type: tag
  slots:
    default: io
- type: tag
  slots:
    default: agents
Edit YAML

timeline

#existingsource

Shows a sequence of versions, commits, activities, or audit events in a narrow panel without turning each event into a tall card. Rows keep the version/date, message, and action in predictable columns so long histories stay scannable.

Readiness
complete
Preview
live
Props
2
Examples
1
Code
implementation mapped

When to use

  • Version history inside the props panel.
  • Short audit trails where each row has one primary action.
  • Activity streams that need dense scanning more than editorial layout.

When not to use

  • Narrative feeds with rich media or long comments.
  • Tables with many sortable columns.

Accessibility

Role: list

  • Tab — Moves through row actions in document order.
  • Enter — Activates the focused row action.

Screen reader: N/A

Notes: Rows render as an ordered list. Keep row actions short and focused so keyboard users can move through the history without card-level noise.

Props

NameTypeDefaultDescription
itemsarrayThe timestamped events, newest-first. Each row keeps version/title, timestamp, body, and one primary action in predictable columns. Required.
densityenum: compact | comfortablecompactRow spacing. `compact` (default) for narrow props panels; `comfortable` when the timeline has room.

Examples

Version restore list

Version history for a narrow props panel.

  1. v47

    Added child: Narrate Review Cases

  2. v46

    Added child: measure-multivariate-isolation-forest

  3. v45

    Added child: measure-dag-slip-bayesian

YAML
type: timeline
props:
  density: compact
  items:
  - id: v47
    title: v47
    timestamp: 2026-05-11 08:16
    body: 'Added child: Narrate Review Cases'
    action: Restore
  - id: v46
    title: v46
    timestamp: 2026-05-10 21:26
    body: 'Added child: measure-multivariate-isolation-forest'
    action: Restore
  - id: v45
    title: v45
    timestamp: 2026-05-10 21:26
    body: 'Added child: measure-dag-slip-bayesian'
    action: Restore
Edit YAML

tree

#existingsource

Render a nested hierarchy as an indented, semantically-structured list. This is the read-only *display* shape — a file tree snapshot, element nesting, an org chart. An interactive expand/collapse tree is intentionally out of scope (compose with Disclosure); claiming interactivity without implementing roving focus would be a false accessibility promise.

Readiness
complete
Preview
live
Props
1
Examples
3
Code
implementation mapped

When to use

  • A static file / directory tree snapshot
  • Element or component nesting visualisation
  • Any read-only parent → child hierarchy

When not to use

  • An interactive expand/collapse navigator — compose with Disclosure
  • A flat list — use a list / Table
  • Breadcrumb-style single-path navigation — use Breadcrumb

Accessibility

Role: tree

  • No keyboard shortcuts

Screen reader: Emits role=tree on the root, role=treeitem per node, and role=group on each nested level so assistive tech announces depth and parent / child relationships. It is non-interactive by contract, so there is no focus management to get wrong.

Notes: Indentation is paired with the group/treeitem roles, so depth is conveyed structurally — not by visual indentation alone.

Props

NameTypeDefaultDescription
nodesarrayRoot nodes. Each node: { label, children: [ ...nodes ] }.

Examples

Source tree

A small source tree.

  • src
    • lib.rs
    • primitives
      • badge.rs
      • button.rs
  • Cargo.toml
YAML
type: tree
props:
  nodes:
  - label: src
    children:
    - label: lib.rs
    - label: primitives
      children:
      - label: badge.rs
      - label: button.rs
  - label: Cargo.toml
Element nesting

Element nesting.

  • circle
    • automation
      • condition
      • loop
YAML
type: tree
props:
  nodes:
  - label: circle
    children:
    - label: automation
      children:
      - label: condition
      - label: loop
Flat

A flat (single-level) tree.

  • alpha
  • beta
  • gamma
YAML
type: tree
props:
  nodes:
  - label: alpha
  - label: beta
  - label: gamma
Edit YAML

workflow-port-affordance

#newsource

Documents the reusable visual contract for automation workflow building. Every element's input/output ports come from generated element YAML; the portal renders the primary input at the north vertex, primary output at the south vertex, fans multiple ports across the adjacent vertices, filters compatible targets with the generated port compatibility matrix, and exposes a Playwright-readable topology mirror for end-to-end workflow construction.

Readiness
complete
Preview
live
Props
1
Examples
2
Code
implementation mapped

When to use

  • Explaining or testing automation workflow port placement.
  • Designing a canvas interaction that must reuse generated port metadata.
  • Writing Playwright tests that drive workflow wiring through the visual canvas.

When not to use

  • Element-library search cards; use library-element-card.
  • Generic graph diagrams without generated Triform element ports.
  • Persisted workflow data models; use the automation build-flow op and _flow response.

Accessibility

Role: img

  • No keyboard shortcuts

Screen reader: The live canvas exposes ports through the workflow-port selector and a workflow-topology-json mirror. The visible wire/port marks are decorative; the generated metadata attributes carry the port name, direction, type, schema hash, and compatibility state for tests and assistive surfaces.

Notes: Boundary flow-in and flow-out nodes are derived visuals only. They are never serialized as edge endpoints.

Props

NameTypeDefaultDescription
modeenum: rest | expanded | focused | connectedrestDocumentation-only state marker for the specimen.

Examples

North input / south output

Rest-state contract: a step's main input is north and its main output is south.

Workflow port contract

Generated per element type; reused by canvas, library, tests

flow inflow out
text
primary input  -> N
primary output -> S
extra inputs   -> NE, NW
extra outputs  -> SE, SW
YAML
type: card
props:
  title: Workflow port contract
  subtitle: Generated per element type; reused by canvas, library, tests
  style: flat
  padding: relaxed
slots:
  default:
  - type: stack
    props:
      direction: row
      gap: md
      align: center
    children:
    - type: badge
      props:
        variant: muted
      slots:
        default: flow in
    - type: element-hexagon
      props:
        kind: automation
        symbol: Au
        name: Trigger
        category: apps
        icon_name: play_arrow
        icon_color: '#7C3AED'
        form: compound
        state: active
    - type: element-hexagon
      props:
        kind: python
        symbol: Py
        name: Transform
        category: actions
        icon_name: code
        icon_color: '#2563EB'
        form: atom
        state: pulse
    - type: badge
      props:
        variant: muted
      slots:
        default: flow out
  - type: well
    props:
      padding: cozy
    slots:
      default:
      - type: code-block
        props:
          language: text
          code: |
            primary input  -> N
            primary output -> S
            extra inputs   -> NE, NW
            extra outputs  -> SE, SW
Test surface

Playwright-facing assertions for a visually built workflow.

Automation builder selectors

Canvas2D stays canonical; DOM mirrors expose coordinates and graph state

workflow-portworkflow-topology-jsonbuild-flow
json
{
  "steps": [{"id": "...", "slug": "transform", "ports": [...]}],
  "edges": [{"edge": "trigger:result -> transform:input"}]
}
YAML
type: card
props:
  title: Automation builder selectors
  subtitle: Canvas2D stays canonical; DOM mirrors expose coordinates and graph state
  style: flat
  padding: relaxed
slots:
  default:
  - type: stack
    props:
      direction: row
      gap: sm
      align: center
    children:
    - type: badge
      props:
        variant: info
      slots:
        default: workflow-port
    - type: badge
      props:
        variant: info
      slots:
        default: workflow-topology-json
    - type: badge
      props:
        variant: success
      slots:
        default: build-flow
  - type: code-block
    props:
      language: json
      code: |
        {
          "steps": [{"id": "...", "slug": "transform", "ports": [...]}],
          "edges": [{"edge": "trigger:result -> transform:input"}]
        }
Edit YAML

terminal-miniature

#existingsource

A small read-only card summarising one agent-terminal session: which agent (claude-code / open-code / codex / generic), its title, status, session id, and last-active time. Per-agent accent colour and command label are derived from `element_type`; an explicit `accent` / `icon_name` overrides.

Readiness
incomplete
Preview
live
Props
7
Examples
3
Code
implementation unmapped

When to use

  • A grid or rail of recent agent-terminal sessions
  • A compact session affordance the user can click to open the full terminal
  • A dashboard summary of active agent runs

When not to use

  • The live, interactive terminal itself — that is the terminal panel
  • A generic status chip with no terminal/session context — use a badge

Accessibility

Role:

  • No keyboard shortcuts

Screen reader: Renders a static <article> with the title, agent label, and last-active line in document order. It is presentational; when used as a click target, wrap it in a real button/link so it is keyboard-operable.

Notes: The card itself carries no interactive semantics — the parent is responsible for making it actionable and labelled if it opens a session.

Props

NameTypeDefaultDescription
element_typeenum: claude-code | open-code | codex | external-agent | triformerclaude-codeDrives the default icon, accent colour, command, and agent label.
titlestringMy Terminal
statusenum: ready | running | error | idleready
session_idstringa1b2c3d4Short session identifier shown on the card.
last_activestringjust nowHuman last-active label (e.g. "just now", "3m ago").
icon_namestringOverride the per-agent default icon key.
accentstringOverride the per-agent default accent colour (CSS colour).

Examples

Claude Code · ready

A ready Claude Code session, just active.

Refactor auth flowClaude Code
readya1b2c3d4
$ claudeagent: claude-codelast: just now
YAML
type: terminal-miniature
props:
  element_type: claude-code
  title: Refactor auth flow
  status: ready
  last_active: just now
OpenCode · running

An OpenCode session mid-run.

Expand test suiteOpenCode
runninga1b2c3d4
$ opencodeagent: open-codelast: 2m ago
YAML
type: terminal-miniature
props:
  element_type: open-code
  title: Expand test suite
  status: running
  last_active: 2m ago
Session rail

A rail of recent sessions.

Bug BUGS-3820Claude Code
errora1b2c3d4
$ claudeagent: claude-codelast: 5m ago
Draft migrationCodex
idlea1b2c3d4
$ codexagent: codexlast: 1h ago
YAML
type: stack
props:
  direction: row
  gap: md
children:
- type: terminal-miniature
  props:
    element_type: claude-code
    title: Bug BUGS-3820
    status: error
    last_active: 5m ago
- type: terminal-miniature
  props:
    element_type: codex
    title: Draft migration
    status: idle
    last_active: 1h ago
Edit YAML

text

#existingsource

The base inline text node the ViewEngine renders. `kind` selects a semantic tone class (heading, muted, error) and otherwise renders plain body text. Content comes from either the `value` prop (reactive) or the default slot.

Readiness
incomplete
Preview
live
Props
2
Examples
3
Code
implementation unmapped

When to use

  • Any inline label, caption, or run of text inside an engine-rendered spec
  • A muted secondary line (`kind: muted`)
  • An inline error message (`kind: error`)
  • A lightweight heading inside a composed component (`kind: heading`)

When not to use

  • Rich/long-form prose with markdown — use markdown-view
  • A standalone page heading with semantic level — use page-header
  • Interactive text that triggers an action — use link-button

Accessibility

Role:

  • No keyboard shortcuts

Screen reader: Renders a plain inline <span>; the text content is read in document order. `kind` is purely presentational (a tone class) and adds no ARIA semantics, so use a heading or page-header component when structural heading semantics are required.

Notes: `kind: error` is a visual tone only — pair it with the field's aria-describedby wiring when announcing a validation error.

Props

NameTypeDefaultDescription
kindenum: body | heading | muted | errorbody
valuestringReactive inline text. Rendered before the default slot. Use this for a single bound string; use the default slot for composed children.

Examples

Muted caption

A muted secondary caption line.

Run success rate
YAML
type: text
props:
  kind: muted
  value: Run success rate
Error text

An inline error message.

Circle name is already taken
YAML
type: text
props:
  kind: error
  value: Circle name is already taken
Heading + body

Heading and body composed in a column.

Storage88 / 100 GB used
YAML
type: stack
props:
  direction: column
  gap: sm
children:
- type: text
  props:
    kind: heading
    value: Storage
- type: text
  props:
    kind: muted
    value: 88 / 100 GB used
Edit YAML