jixoai-ui
the terminal design language
loading the style sheet…
Skip to content
docs · print medium: screen

registry:ui · Navigation

steps — explicit ordinals, compared not registered

The wizard progress as a composed family: a nine-word state vocabulary (auto trio + middle pending, success/error/hint/emphasis/disabled) overrides the derived done/current/todo comparison when stated explicitly. The done Indicator becomes the button (a link back) when onclick is given; the current step is aria-current=step; future steps are inert spans. CSS connector; check glyph on done; the Separator self-hides on the last item.

bind:current · 0-based required step ordinals done marker = the button 9-word state vocabulary connector on its own lane

steps

Walk the wizard: click a completed step's check-marker to go back, or drive current from the playground — every Indicator, Title, Description and Separator below is authored, never auto-inserted. The playground rides the floating dock over the stage's top-right corner: the wizard row keeps the full stage width, and one click collapses the dock to its chrome chip when you want the corner back.

  1. completed connect link the git origin
  2. current step audit typecheck + tests green
  3. not started ship promote to production
steps-usage.svelte svelte
<script lang="ts">
  import {
    Steps,
    StepsItem,
    StepsIndicator,
    StepsTitle,
    StepsDescription,
    StepsSeparator,
  } from '@ui/steps/index';
</script>

<!-- bind:current (0-based) is the one shared state; each Item carries a
     REQUIRED explicit ordinal — state is pure step-vs-current comparison.
     onclick fires only from the done state and makes the Indicator the
     button (no handler ⇒ inert span, no dead affordance). -->
let current = $state(1);

<Steps bind:current>
  <StepsItem step={0} label="connect" onclick={() => (current = 0)}>
    <StepsIndicator />
    <StepsTitle>connect</StepsTitle>
    <StepsDescription>link the git origin</StepsDescription>
    <StepsSeparator />
  </StepsItem>
  <StepsItem step={1}>
    <StepsIndicator />
    <StepsTitle>build</StepsTitle>
    <StepsDescription>install + typecheck</StepsDescription>
    <StepsSeparator />
  </StepsItem>
  <StepsItem step={2}>
    <StepsIndicator />
    <StepsTitle>ship</StepsTitle>
    <StepsDescription>promote to production</StepsDescription>
    <StepsSeparator />
  </StepsItem>
</Steps>

law

the state vocabulary — nine words for where a step stands

The derived trio (done / current / todo) is pure ordinal comparison — it cannot say submitted-but-waiting, it cannot say won or lost, it cannot say look here or closed. The state prop overrides the trio with the missing words. Read it as a wizard form AND as the markers over an NPC's head: ⋯ is the quest in flight, ! is the quest-giver, ✓ is turn-in day, ✕ is the failure state.

steps · state vocabulary

  1. completed donestep < current · solid fill + ✓ · connector painted primary
  2. current step currentstep = current · aria-current=step · solid fill + its number
  3. in progress pendingthe middle state · hollow + the breathing ⋯ · submitted, in flight
  1. succeeded successthe terminal win · ✓ on the success pair
  2. failed errorthe terminal failure · ✕ on the error pair
  3. information hintinformational · i on the info pair
  1. current step current · the first 1duplicates paint EVERY match current — ordinal truth, not identity
  2. current step current · the second 1the duplicate — also current; nothing corrupts
  3. information 3 (the gap)ordinal 2 simply does not exist — gaps paint none, no phantom row
  1. attention emphasisthe quest-giver ! · hollow + halo ring · look here
  2. unavailable disableddeclared out-of-reach · dashed ring, reduced contrast, spoken "unavailable" — unlike todo (the merely unreached)
  3. not started todostep > current · hollow ring at full contrast · inert
steps-states-demo.svelte svelte
<script lang="ts">
  import Steps, {
    StepsItem,
    StepsIndicator,
    StepsTitle,
    StepsDescription,
    StepsSeparator,
  } from '@ui/steps/index';
</script>

<!-- the derived trio plus the override words, three rows by state group -->
<div class={cx(rt.col24)}>
  <div class={cx(rt.wFull, rt.maxW2xl)}>
    <Steps current={1}>
      <StepsItem step={0} label="done"><StepsIndicator /><StepsTitle>done</StepsTitle><StepsDescription>step &lt; current · solid fill + ✓ · connector painted primary</StepsDescription><StepsSeparator /></StepsItem>
      <StepsItem step={1}><StepsIndicator /><StepsTitle>current</StepsTitle><StepsDescription>step = current · aria-current=step · solid fill + its number</StepsDescription><StepsSeparator /></StepsItem>
      <StepsItem step={2} state="pending"><StepsIndicator /><StepsTitle>pending</StepsTitle><StepsDescription>the middle state · hollow + the breathing ⋯ · submitted, in flight</StepsDescription><StepsSeparator /></StepsItem>
    </Steps>
  </div>
  <div class={cx(rt.wFull, rt.maxW2xl)}>
    <Steps current={1}>
      <StepsItem step={0} state="success"><StepsIndicator /><StepsTitle>success</StepsTitle><StepsDescription>the terminal win · ✓ on the success pair</StepsDescription><StepsSeparator /></StepsItem>
      <StepsItem step={1} state="error"><StepsIndicator /><StepsTitle>error</StepsTitle><StepsDescription>the terminal failure · ✕ on the error pair</StepsDescription><StepsSeparator /></StepsItem>
      <StepsItem step={2} state="hint"><StepsIndicator /><StepsTitle>hint</StepsTitle><StepsDescription>informational · i on the info pair</StepsDescription><StepsSeparator /></StepsItem>
    </Steps>
  </div>
  <div class={cx(rt.wFull, rt.maxW2xl)}>
    <Steps current={1}>
      <StepsItem step={0} state="emphasis"><StepsIndicator /><StepsTitle>emphasis</StepsTitle><StepsDescription>the quest-giver ! · hollow + halo ring · look here</StepsDescription><StepsSeparator /></StepsItem>
      <StepsItem step={1} state="disabled"><StepsIndicator /><StepsTitle>disabled</StepsTitle><StepsDescription>declared out-of-reach · dashed ring, reduced contrast, spoken "unavailable" — unlike todo (the merely unreached)</StepsDescription><StepsSeparator /></StepsItem>
      <StepsItem step={2}><StepsIndicator /><StepsTitle>todo</StepsTitle><StepsDescription>step &gt; current · hollow ring at full contrast · inert</StepsDescription></StepsItem>
    </Steps>
  </div>
</div>

types

Step states

Each item compares its explicit ordinal with current: completed, current and future are projections of one number. The explicit state prop overrides the comparison when the trio cannot say it.

steps · derived trio

  1. completed done
  2. current step current
  3. not started future
steps-types-demo.svelte svelte
<script lang="ts">
  import Steps, {
    StepsItem,
    StepsIndicator,
    StepsTitle,
    StepsSeparator,
  } from '@ui/steps/index';
</script>

<div class={cx(rt.wFull, rt.maxW2xl)}>
  <Steps current={1}>
    <StepsItem step={0}><StepsIndicator /><StepsTitle>done</StepsTitle><StepsSeparator /></StepsItem>
    <StepsItem step={1}><StepsIndicator /><StepsTitle>current</StepsTitle><StepsSeparator /></StepsItem>
    <StepsItem step={2}><StepsIndicator /><StepsTitle>future</StepsTitle></StepsItem>
  </Steps>
</div>

usage

Usage

The composition contract in one sample: import the family from the registry barrel (@ui/steps/index — per-part targets exist per file), give every StepsItem its explicit step ordinal, author the parts you want. The Separator self-hides on the last item through the family css — chrome, not authoring.

usage
<script lang="ts">
  import {
    Steps,
    StepsItem,
    StepsIndicator,
    StepsTitle,
    StepsDescription,
    StepsSeparator,
  } from '@ui/steps/index';
</script>

<!-- bind:current (0-based) is the one shared state; each Item carries a
     REQUIRED explicit ordinal — state is pure step-vs-current comparison.
     onclick fires only from the done state and makes the Indicator the
     button (no handler ⇒ inert span, no dead affordance). -->
let current = $state(1);

<Steps bind:current>
  <StepsItem step={0} label="connect" onclick={() => (current = 0)}>
    <StepsIndicator />
    <StepsTitle>connect</StepsTitle>
    <StepsDescription>link the git origin</StepsDescription>
    <StepsSeparator />
  </StepsItem>
  <StepsItem step={1}>
    <StepsIndicator />
    <StepsTitle>build</StepsTitle>
    <StepsDescription>install + typecheck</StepsDescription>
    <StepsSeparator />
  </StepsItem>
  <StepsItem step={2}>
    <StepsIndicator />
    <StepsTitle>ship</StepsTitle>
    <StepsDescription>promote to production</StepsDescription>
    <StepsSeparator />
  </StepsItem>
</Steps>

a11y

Accessibility

ARIA

AttributeValueDescription
aria-currentstepMarks the current step — the derived trio and an explicit state="current" both carry it.
sr-only statusper-item state textThe marker glyphs are aria-hidden chrome, so every item speaks its effective state as text (completed · current step · in progress · unavailable · …) — the vocabulary reaches AT as words.
buttoncompleted indicatorMakes completed steps keyboard actionable only when onclick is supplied; after a go-back click, focus rests on the item (tabindex=-1), never on body.

theming

Density and tokens

xs
  1. current step step
default
  1. current step step
lg
  1. current step step
TokenDefaultSource
--jx-icondensity scaledensity
--jx-gapdensity scaledensity
--jx-insetdensity scaledensity
--jx-textdensity scaledensity
--jx-text-secondarydensity scaledensity
--jx-linedensity scaledensity

axes

Universal props

The eight-axis surface (explicit-props): size · shape · radius · density · color · theme · elevation · motion — each axis takes named steps, auto (inherit the ambient context; stamps nothing), an exact number (px · coefficient · dp · hue per axis), or query() for responsive/container-conditional values. The root carries the surface (the parts ride the ambient chain — 吃也供); density rides the root's bridged provider lane, and the size axis scales the ordered list.

Steps · universal props

  1. completed connect
  2. current step build
  3. not started ship
  1. completed connect
  2. current step build
  3. not started ship
steps-universal.svelte svelte
<Steps size={18} density="small">…</Steps>

api

API

Steps owns current (bindable); StepsItem owns the ordinal and the state vocabulary; the parts stay authored.

Properties

PropertyTypeDefaultDescription
Steps.current bindnumber00-based current ordinal.
StepsItem.step * number—REQUIRED explicit ordinal — compared against current.
StepsItem.state 'auto' | 'done' | 'current' | 'todo' | 'pending' | 'success' | 'error' | 'hint' | 'emphasis' | 'disabled''auto'The state vocabulary: auto = the derived trio (pure comparison); the semantic overrides paint the middle state (pending ⋯), the terminals (success ✓ / error ✕), hint (i), emphasis (the quest-giver !) and disabled (dashed ring, spoken "unavailable").
StepsItem.label string—Accessible name for the done-marker button.
StepsItem.onclick (e) => void—Fires only from the done state — makes the Indicator the button.
class string—Adds consumer classes.

Universal props

PropertyTypeDefaultDescription
size'small' | 'medium' | 'large' | 'auto' | number'auto' · ambient scopethe base scale — root font-size; parts size in em
shape'round' | 'scoop' | 'bevel' | 'notch' | 'square' | 'squircle' | 'auto''auto' · ambient scopecorner geometry (CSS corner-shape; §14 degrade table)
radius'small' | 'medium' | 'large' | 'auto' | number'auto' · ambient scopecorner size; auto = the concentric broadcast (§3)
density'small' | 'medium' | 'large' | 'auto' | number'auto' · ambient scopespacing/leading scale over the kernel channels (§4)
color'primary' | 'secondary' | 'error' | 'warn' | 'success' | 'info' | 'auto' | number | string'auto' · ambient scopethe hue axis of the fixed oklch primary system (§5)
theme'light' | 'dark' | 'system' | 'auto''auto' · ambient scopelight/dark profile; system = the JS-mutable global (§6)
elevation'level-1' | 'level0' | 'level1' | 'level2' | 'level3' | 'level4' | 'level5' | 'auto' | number'auto' · ambient scopeofficial M3 levels over the surface ladder (§7)
motion'reduced' | 'subtle' | 'normal' | 'expressive' | 'auto' | number'auto' · ambient scopeintensity across the motion kernels (§8)
jixoai-ui ui.jixoai.com the jixoai design language

Theme

Brand hue

0°

Auto cycle · 24h