Form Structure

field

#existingsource

A labelled form control with optional helper text or error message in a fixed canonical layout. Always wraps exactly one input control via the default slot.

Readiness
complete
Preview
live
Props
5
Examples
3
Code
implementation mapped

When to use

  • Every labelled form input — pair with `input`, `select`, or `textarea`
  • Inline validation feedback (helper or error)
  • Required-field indicator (`*` next to label)
  • Form fields that need consistent label-above-input layout

When not to use

  • Unlabelled controls (e.g. a search input with placeholder only — use SearchInput)
  • Multi-input fields like address blocks — use Fieldset (when it lands)
  • Toggle switches with adjacent label — use LabeledSwitch

Accessibility

Role: group

  • Tab — Moves focus to the wrapped input

Screen reader: `label` is wired to the wrapped input via `for`/`id`. When `error` is set, the message gets `role=alert` so screen readers announce it immediately. Helper text is hidden when error is set.

Notes: Caller MUST pass the same `field_id` to the wrapped input via its `id` prop — the audit fails if these are mismatched.

Props

NameTypeDefaultDescription
label*stringVisible label text. Always rendered — placeholder text alone is not a label and fails accessibility.
field_id*stringStable id used to bind label `for=` to the wrapped input's `id=`. Caller must pass the same id to the wrapped input via its `id` prop. v1: id strings; later may become opaque tokens.
helperstringOptional helper text below the input. Hidden when error is set.
errorstringError message below the input. When set, helper is hidden, the wrapped input shows its error visual, and the message gets `role=alert` so screen readers announce it.
requiredbooleanfalseRenders a visual `*` next to the label.

Examples

Username with helper

Username field with helper text.

Or your email address.

YAML
type: field
props:
  label: Username
  field_id: login-username
  helper: Or your email address.
slots:
  default:
  - type: input
    props:
      value: ${state.username}
      on_input: ${actions.set_username}
      auto_focus: true
Password with error

Password field with error display (replaces ad-hoc error markup in PasswordLoginForm).

YAML
type: field
props:
  label: Password
  field_id: login-password
  error: ${state.error_message}
slots:
  default:
  - type: input
    props:
      value: ${state.password}
      on_input: ${actions.set_password}
      input_type: password
      error: ${state.has_error}
Required indicator

Required field marker.

We'll never share it.

YAML
type: field
props:
  label: Email
  field_id: register-email
  required: true
  helper: We'll never share it.
slots:
  default:
  - type: input
    props:
      value: ${state.email}
      on_input: ${actions.set_email}
      input_type: email
Edit YAML

fieldset

#existingsource

A semantic grouping of related form controls with an optional legend and supporting description. Fieldset exists so a long form reads as a set of scannable sections, and so the group has a real accessible name (the legend) that assistive tech announces when focus enters the group. For the submit/cancel row use FormActions; for a multi-step flow use Wizard.

Readiness
complete
Preview
live
Props
2
Examples
2
Code
implementation mapped

When to use

  • Chunking a long form into labelled sections ('Contact', 'Billing')
  • A group of radios/checkboxes that share one question (legend = the question)
  • Any set of controls that belong together and need one accessible name
  • Visually separating optional from required sections

When not to use

  • A single field with a label — use Field
  • The submit/cancel button row — use FormActions
  • A multi-step form — use Wizard
  • Non-form content grouping — use Card or Section

Accessibility

Role: group

  • No keyboard shortcuts

Screen reader: Renders a native <fieldset>; the <legend> becomes the group's accessible name and is announced when focus enters any control inside. The description follows the legend in DOM order.

Notes: Keep the legend short — it is repeated by some screen readers for every control in the group.

Props

NameTypeDefaultDescription
legendstringGroup legend — becomes the group's accessible name.
descriptionstringOptional supporting text rendered under the legend.

Examples

Field group

A billing-address section grouping several fields.

Billing address

Where invoices are sent.

YAML
type: fieldset
props:
  legend: Billing address
  description: Where invoices are sent.
slots:
  default:
  - type: field
    props:
      label: Street
    slots:
      default:
      - type: input
        props:
          placeholder: 1 Market St
  - type: field
    props:
      label: City
    slots:
      default:
      - type: input
        props:
          placeholder: San Francisco
Choice group

A radio question where the legend is the question.

Notification frequency
YAML
type: fieldset
props:
  legend: Notification frequency
slots:
  default:
  - type: radio-group
    props:
      name: freq
      options:
      - Real-time
      - Daily digest
      - Weekly
Edit YAML

form-actions

#existingsource

The action row at the foot of a form: primary submit plus secondary cancel/back. FormActions exists so the alignment, gap, and separator are consistent across every form rather than re-derived per form. The row is a labelled group so assistive tech announces it as the form's action area. For a multi-step flow's Back/Next use Wizard (it has its own footer); for grouping fields use Fieldset.

Readiness
complete
Preview
live
Props
1
Examples
3
Code
implementation mapped

When to use

  • The submit + cancel row at the bottom of any form
  • A dialog footer's confirm/dismiss pair
  • A settings panel's Save / Discard row
  • Back-left / Next-right navigation (align=between)

When not to use

  • A multi-step wizard's step navigation — use Wizard
  • A general-purpose button cluster outside a form — use Stack or ButtonGroup
  • A single primary action — just render the Button
  • Grouping form fields — use Fieldset

Accessibility

Role: group

  • No keyboard shortcuts

Screen reader: Rendered as role=group with aria-label 'Form actions' so assistive tech announces the action area. Order the buttons so the primary action is last in DOM for logical tab order.

Notes: Keep the primary action visually and structurally distinct (variant) — alignment alone is not an accessible signal of which button submits.

Props

NameTypeDefaultDescription
alignenum: start | center | end | betweenend

Examples

Save / Cancel

A standard cancel + save row, primary action last.

YAML
type: form-actions
props:
  align: end
slots:
  default:
  - type: button
    props:
      variant: ghost
    slots:
      default: Cancel
  - type: button
    props:
      variant: primary
    slots:
      default: Save changes
Between

Back-left / Next-right navigation.

YAML
type: form-actions
props:
  align: between
slots:
  default:
  - type: button
    props:
      variant: ghost
    slots:
      default: Back
  - type: button
    props:
      variant: primary
    slots:
      default: Continue
Alignments

All alignments for visual comparison.

YAML
type: stack
props:
  gap: md
  direction: column
children:
- type: form-actions
  props:
    align: start
  slots:
    default:
    - type: button
      props:
        variant: ghost
      slots:
        default: Cancel
    - type: button
      props:
        variant: primary
      slots:
        default: Save
- type: form-actions
  props:
    align: center
  slots:
    default:
    - type: button
      props:
        variant: ghost
      slots:
        default: Cancel
    - type: button
      props:
        variant: primary
      slots:
        default: Save
- type: form-actions
  props:
    align: end
  slots:
    default:
    - type: button
      props:
        variant: ghost
      slots:
        default: Cancel
    - type: button
      props:
        variant: primary
      slots:
        default: Save
Edit YAML

schema-form

#existingsource

SchemaForm renders editable fields from a JSON Schema. It is the bridge between element definitions and consistent platform forms, keeping labels, required markers, field order, and submit chrome aligned across element types.

Readiness
complete
Preview
live
Props
6
Examples
1
Code
implementation mapped

When to use

  • Element property editors where the field model comes from chemistry
  • Internal tools that already have a JSON Schema contract
  • Forms whose shape changes by selected element type

When not to use

  • Small fixed forms where custom layout or copy is essential
  • Wizard flows with cross-step validation or progressive disclosure
  • Highly interactive editors such as code, graph, or rich text surfaces

Accessibility

Role: form

  • Tab — Moves through generated fields and actions
  • Enter — Submits when focus is in a compatible field

Screen reader: Each generated field receives a visible label and required marker.

Notes: Schema authors must provide meaningful titles and descriptions.

Props

NameTypeDefaultDescription
schema*objectJSON Schema object with properties, required fields, and optional propertyOrder.
initial_valuesobjectInitial form values keyed by schema property name.
submit_labelstringSavePrimary submit button label.
cancel_labelstringCancelCancel button label.
show_cancelbooleantrueWhether the cancel action is rendered.
submittingbooleanfalseShows the submit button in a pending state.

Examples

Element properties

An element property form generated from schema metadata.

Human-readable element name

Retry attempts before surfacing failure

YAML
type: schema-form
props:
  submit_label: Save element
  schema:
    type: object
    required:
    - name
    propertyOrder:
    - name
    - retries
    - enabled
    properties:
      name:
        type: string
        title: Name
        description: Human-readable element name
      retries:
        type: integer
        title: Retries
        description: Retry attempts before surfacing failure
        default: 3
      enabled:
        type: boolean
        title: Enabled
        default: true
  initial_values:
    name: Sync contacts
    retries: 3
    enabled: true
Edit YAML

voice-recorder-card

#existingsource

Makes voice setup simple: prepare the mouth, record or upload a short sample, save it as a named voice, then show a usable saved state for speech.

Readiness
complete
Preview
live
Props
6
Examples
1
Code
implementation mapped

When to use

  • Circle Personality section when the user configures how the circle speaks.
  • Any mouth-backed voice cloning setup flow.

When not to use

  • Speech-to-text or listening configuration; this card is only for mouth/voice.

Accessibility

Role: form

  • Tab — Moves through recorder controls, name field, upload, and save.

Screen reader: N/A

Props

NameTypeDefaultDescription
titlestringVoiceCard heading for the voice setup surface.
stateenum: empty | ready | recording | savedreadyCurrent recorder lifecycle state.
mouthstringResolved mouth element or speech provider backing the voice.
saved_voicestringSaved voice label shown after a successful recording.
helper_textstringRecord a short sample so the circle can speak consistently.Short explanatory line below the heading.
can_recordbooleantrueEnables the record affordance in the rendered preview.

Examples

Voice setup

Mouth-backed voice recorder flow.

Mouth voice

Voice

Ready

Record a short sample so the circle can speak consistently.

Mouth
Primary Mouth
Saved voice
Narrator
YAML
type: voice-recorder-card
props:
  title: Voice
  state: ready
  mouth: Primary Mouth
  saved_voice: Narrator
Edit YAML

wizard

#existingsource

A bounded, ordered multi-step form: onboarding, setup, a long form split across stages. Wizard owns the active-step signal, renders the step indicator and Back/Next controls, and shows only the active step's panel. Use it when the user benefits from seeing how many steps remain and moving back and forth. For free navigation between unrelated sections use Tabs; for a single grouped section use Fieldset.

Readiness
complete
Preview
live
Props
2
Examples
2
Code
implementation mapped

When to use

  • An onboarding or account-setup flow
  • A long form split into digestible ordered stages
  • A checkout / submission flow with discrete steps
  • Any bounded sequence where progress and back-navigation matter

When not to use

  • Free navigation between unrelated sections — use Tabs
  • A single grouped section — use Fieldset
  • A pure progress indicator with no form content — use ProgressSteps
  • An unbounded / open-ended flow — a wizard implies a known end

Accessibility

Role: form

  • No keyboard shortcuts

Screen reader: The indicator is a <nav aria-label="Progress"> ordered list; the active step carries aria-current="step" and each step has an aria-label of the form 'Label, current/completed/upcoming' so its state is conveyed without relying on the marker colour. Inactive panels are hidden from the accessibility tree. The step counter is aria-hidden decoration (the per-step aria-current/label is authoritative).

Notes: Each step should make its position obvious in the panel heading too (e.g. 'Step 2 of 4: Account details') for users who land mid-flow.

Props

NameTypeDefaultDescription
stepsarrayOrdered step labels.
currentinteger0Zero-based index of the active step. Earlier steps render complete; later steps upcoming.

Examples

Onboarding

A three-step onboarding wizard on the middle step.

Step 2 — tell us about yourself.
YAML
type: wizard
props:
  steps:
  - Account
  - Profile
  - Confirm
  current: 1
slots:
  default:
  - type: text
    slots:
      default: Step 1 — create your account credentials.
  - type: text
    slots:
      default: Step 2 — tell us about yourself.
  - type: text
    slots:
      default: Step 3 — review and confirm.
Checkout

A four-step checkout flow starting at step one.

Review the items in your cart.
YAML
type: wizard
props:
  steps:
  - Cart
  - Shipping
  - Payment
  - Review
  current: 0
slots:
  default:
  - type: text
    slots:
      default: Review the items in your cart.
  - type: text
    slots:
      default: Enter your shipping address.
  - type: text
    slots:
      default: Add a payment method.
  - type: text
    slots:
      default: Confirm and place your order.
Edit YAML