Controls · Toggle
Toggle
Two-state button (pressed / unpressed) — single APG button pattern,
form-integrable via name + value, three
variants (solid / outline / ghost),
doctrinal intent (neutral | affirm | risk | threat),
single commit-toggle sema event with sequence: 'post'.
parts {compiled.parts.order.length}
events {events.length}
variants 3
intents 4
apg
button ↗
trace
{#if trace.length === 0}
click toggle to see commit-toggle event
{:else}
{#each trace.slice(0, 3) as entry}
{entry.event} · {entry.family}{entry.intent ? ' · ' + entry.intent : ''}
{fmtTime(entry.at)}
{/each}
{/if}
state {pressed ? 'on' : 'off'}
{#if lastFormSubmit !== null}
FormData
{JSON.stringify(lastFormSubmit)}
{/if}
(tab = 'live')}>Live
(tab = 'api')}>
API 17
(tab = 'morfo')}>
morfo
{partsList.length}p · {events.length}e
(tab = 'sema')}>
sema
{events.length}
(tab = 'recipe')}>Recipe
(tab = 'a11y')}>A11y
{#if tab === 'live'}
Controls
Props grouped by layer: soma headless behavior, eidos visual treatment. Sema events live in the { e.preventDefault(); tab = 'sema'; }}>Sema tab.
soma props · headless behavior
pressed bindable
{pressed ? 'on' : 'off'}
disabled
{disabled ? 'on' : 'off'}
readonly
{readonly ? 'on' : 'off'}
required
{required ? 'on' : 'off'}
invalid
{invalid ? 'on' : 'off'}
intent
{#each ['neutral', 'affirm', 'risk', 'threat'] as i}
(intent = i as 'neutral' | 'affirm' | 'risk' | 'threat')}>{i}
{/each}
color only when intent=neutral
{#each ['', 'primary', 'secondary'] as c}
(color = c as '' | 'primary' | 'secondary')}>{c || 'none'}
{/each}
name
value
aria-label override
eidos props · visual treatment
variant
{#each ['solid', 'outline', 'ghost'] as v}
(variant = v as ToggleVariant)}>{v}
{/each}
size
{#each ['xs', 'sm', 'md', 'lg', 'xl'] as s}
(size = s as ToggleSize)}>{s}
{/each}
block (full width)
{block ? 'on' : 'off'}
iconOnly
{iconOnly ? 'on' : 'off'}
icon snippet
{showIcon ? 'on (Bold)' : 'off'}
checkMark
{showCheckMark ? 'on' : 'off'}
Demo content · literal label text
label text
soma
headless · ARIA + behavior only
svelte
{somaSnippet}
eidos
visual · adds variant, size, block, iconOnly, icon, checkMark
svelte
{eidosSnippet}
{/if}
{#if tab === 'api'}
API reference
Single-part component — <Toggle> IS the button. All props live on one component.
Prop Type Default Description
pressed bindable boolean false Whether the toggle is pressed.
onPressedChange (pressed: boolean) => void — Press change callback.
disabled / readonly / required / invalid boolean false Field-integration flags.
intent 'neutral' | 'affirm' | 'risk' | 'threat' 'neutral' Doctrinal intent of the consequence. Drives sema sound + color.
color 'primary' | 'secondary' — Hierarchical accent. Only applies when intent='neutral'.
name / value string — / 'on' Form field. Hidden input renders only while pressed.
aria-label string — Override accessible name when children isn't sufficient.
variant eidos 'solid' | 'outline' | 'ghost' 'solid' Visual treatment.
size eidos 'sm' | 'md' | 'lg' 'md' Padding + font preset.
block eidos boolean false Stretch to fill inline-size.
iconOnly eidos boolean false Square aspect, padding-inline reduced.
icon eidos Snippet<{`{pressed}`}> — Icon snippet rendered before children.
checkMark eidos boolean | Snippet false Show check mark when pressed.
{/if}
{#if tab === 'morfo'}
morfo · declarative contract
Source: src/uix/morfo/components/toggle.ts. Single-part — Provider IS the button.
Field Value
name "{toggleMorfo.name}"
kebab "{toggleMorfo.kebab}"
scope [{toggleMorfo.scope.map((s) => `"${s}"`).join(', ')}]
apg {toggleMorfo.apg}
parts.length {toggleMorfo.parts.length}
events.length {toggleMorfo.events?.length ?? 0}
Parts
Part Marker Element Role Archetype States
{#each partsList as part}
{part.kebab}
[{part.marker}]
<{part.defaultElement}>
{part.role ?? '—'}
{part.archetype ?? '—'}
{part.states.length ? part.states.join(' | ') : '—'}
{/each}
{#each toggleMorfo.parts as rawPart}
{@const partAny = rawPart as unknown as { kebab: string; aria?: ReadonlyArray<{ attr: string; value: { kind: string }; condition?: { when: string; prop?: string }; severity?: string }>; keyboard?: ReadonlyArray<{ key: string; action: string }> }}
{@const dataAttrs = compiled.contracts.dataAttrsByPart.get(partAny.kebab) ?? []}
{@const ariaAttrs = partAny.aria ?? []}
{@const keyboard = partAny.keyboard ?? []}
{#if dataAttrs.length || ariaAttrs.length || keyboard.length}
{partAny.kebab}
{#if dataAttrs.length}
data-attr Values Source
{#each dataAttrs as attr}
{attr.attr}
{attr.values ? attr.values.join(' | ') : '—'}
{'value' in attr && attr.value ? (attr as { value: { kind: string } }).value.kind : '—'}
{/each}
{/if}
{#if ariaAttrs.length}
aria-attr Source Condition Severity
{#each ariaAttrs as a}
{a.attr}
{a.value.kind}
{a.condition ? `when ${a.condition.when}${a.condition.prop ? ` (${a.condition.prop})` : ''}` : 'always'}
{a.severity ?? 'required'}
{/each}
{/if}
{#if keyboard.length}
key action
{#each keyboard as kb}
{kb.key === ' ' ? 'Space' : kb.key} {kb.action}
{/each}
{/if}
{/if}
{/each}
Events declaration
name family verb sequence intent target
{#each events as action}
{@const sem = action.semantic}
{@const intentDecl = 'intent' in sem ? sem.intent : undefined}
{@const intentStr = typeof intentDecl === 'string' ? intentDecl : intentDecl ? `fromProp:${(intentDecl as { fromProp?: string }).fromProp ?? '?'}` : '—'}
{action.name}
{sem.family}
{sem.verb ?? '—'}
{sem.sequence ?? 'pre'}
{intentStr}
{action.target}
{/each}
{/if}
{#if tab === 'sema'}
sema · events + perceptual signature
One event — commit-toggle — fires AFTER the state flip (canon sequence: 'post'). The pulse celebrates the resolved state. Intent comes from the intent prop and modulates the perceptual signature via SEMA_MAP.intents.
Name Family Verb Sequence Intent (live) Play
{#each events as action}
{action.name}
{action.semantic.family}
{action.semantic.verb ?? '—'}
{action.semantic.sequence ?? 'pre'}
{intent}
{
const target = stageRef?.querySelector('[data-toggle]') as HTMLElement | null;
if (!target) return;
void uix.events?.emit({
name: action.name,
family: action.semantic.family,
target,
intent
});
}}
>▶ play
{/each}
{/if}
{#if tab === 'recipe'}
Eidos recipe
Selectors at src/uix/eidos/components/toggle/toggle.css. Maps data-state + data-color + data-variant + data-size to design tokens.
Selector Source
[data-toggle] morfo
[data-toggle][data-state='on'/'off'] morfo
[data-toggle][data-color] morfo · resolved from intent + color
[data-toggle][data-disabled / readonly / invalid / required] morfo
[data-toggle][data-variant / data-size / data-block / data-icon-only] eidos
{/if}
{#if tab === 'a11y'}
Accessibility
Follows the APG button pattern . Native button keyboard. aria-pressed exposes the toggle state.
Keyboard
Key Action
Enter / Space Toggle pressed state.
Tab Move focus to / from the toggle.
ARIA contract
Attribute Value
type "button"
aria-pressed "true" / "false"
aria-label {`{aria-label}`} (when set)
aria-disabled / readonly / required / invalid "true" (when set)
{/if}