Action primitive that emits one canonical press event from pointer, keyboard, and assistive activation.
Install @wyrd-company/react or the Flutter package and use it directly —
your DESIGN.md does the styling.
catalog/contracts/button.ymlsource of truth · verbatim
$schema: https://thewyrdingway.dev/schemas/component-contract.schema.ymlcontractVersion: 0.1.0identity:name: Buttontag: wyrd-buttonpackage: wyrd.component.buttontitle: Buttonsummary: Action primitive that emits one canonical press event from pointer, keyboard, and assistive activation.relationships:related-to: - quality-parity-and-gatesclassification:category: actioncomposition: multi-slotinteractive: truetarget-strategy:react: requiredflutter: requiredsurface:properties: - name: varianttype:kind: enumvalues: - primary - secondary - ghost - dangerrequired: falsedefault: primaryreflects: trueserializable: truesummary: Visual and semantic action emphasis. - name: is-disabledtype:kind: booleanrequired: falsedefault: falsereflects: trueserializable: truesummary: Prevents activation and exposes disabled platform semantics. - name: is-loadingtype:kind: booleanrequired: falsedefault: falsereflects: trueserializable: truesummary: Shows pending action state while preserving dimensions and suppressing duplicate activation.slots: - name: labelcontent: truerequired: truecardinality: exactly-oneaccepts: - text - nodesummary: Primary visible label and accessible-name source. - name: leading-iconrequired: falsecardinality: zero-or-oneaccepts: - iconsummary: Optional icon before the label in inline flow. - name: trailing-iconrequired: falsecardinality: zero-or-oneaccepts: - iconsummary: Optional icon after the label in inline flow.events: - name: presspayload:source:kind: enumvalues: - pointer - keyboard - assistiveaction:kind: action-refbubbles: truecomposed: truecancelable: truesummary: Canonical activation event emitted once per accepted activation.states: - name: defaultsource: platformsummary: Idle enabled state. - name: hoversource: interactionsummary: Pointer hover state on hover-capable devices. - name: focus-visiblesource: platformsummary: Keyboard-visible focus state. - name: pressedsource: interactionsummary: Active press state. - name: disabledsource: propertysummary: Disabled state derived from is-disabled. - name: loadingsource: propertysummary: Pending state with a visible activity indicator derived from is-loading.parts: - name: rootsummary: Interactive platform control root.slots: - label - leading-icon - trailing-icon - name: labelsummary: Label content container.slots: - label - name: iconsummary: Icon slot containers.slots: - leading-icon - trailing-icon - name: loading-indicatorsummary: Non-color-only indeterminate activity indicator shown before the stable label while loading.tokens:primary:background: color.primarybackground-hover: color.primary-hoverbackground-pressed: color.primary-pressedforeground: color.on-primarysecondary:background: color.secondaryforeground: color.on-secondaryghost:background: transparentforeground: color.primarydanger:background: color.errorforeground: color.on-errordisabled:background: color.disabledforeground: color.on-disabledradius: rounded.mdpadding-x: spacing.lgpadding-y: spacing.smgap: spacing.smlabel: typography.label-mdloading-indicator-size: spacing.mdloading-indicator-stroke-width: 2pxmessages: []obligations:accessibility:role: buttonname: Label slot or aria-label provides the accessible name.keyboard: - Enter activates the button. - Space activates the button.semantics: - Disabled state is exposed through native disabled semantics where the target has them. - Loading state keeps the accessible name stable and prevents duplicate activation. - The loading indicator is decorative because aria-busy exposes the pending state while the visible label remains the accessible name.behavior:model: statelessinteractions: - Activation emits press when the button is enabled and not loading. - Touch activation does not create hover state. - Loading renders an indeterminate activity indicator before the unchanged label without changing the button's dimensions. - Reduced-motion preferences replace continuous rotation with a static partial-ring indicator.hostEffects: - Dispatch activation event. - Invoke action binding for SDUI when present.conditions: - rtl - reduced-motion - cvd-deuteranopia - density-compactsdui:status: serializableserializableProperties: - variant - is-disabled - is-loadingserializableSlots: - label - leading-icon - trailing-iconeventBindings: - pressnotes: Press serializes as an action reference; executable callbacks stay target-local.examples: - name: primarystate: defaultproperties:variant: primaryslots:label: Save changes - name: loadingstate: loadingproperties:variant: primaryis-loading: trueslots:label: Save changes - name: dangerstate: defaultproperties:variant: dangerslots:label: Delete
01
Examples
Generated from the contract's examples block.
Previews are the published @wyrd-company/react component, themed by the
brand's role tokens — flip the site's light/dark toggle and they follow.
The specimen is the same published React component and contract example used above.
Indexed markers identify only regions the contract can ground; the typed ledger keeps
parts, slots, states, and semantic token bindings distinct.
ANATOMY · LIVE SPECIMENButton primary example · contract-derived
1
PartrootInteractive platform control root.
The rendered button boundary.
2
PartlabelLabel content container.
The visible label region.
3
SlotlabelPrimary visible label and accessible-name source.
Where the example supplies Save changes.
4
Tokenprimary.backgroundcolor.primary
The semantic primary background token applied to the root surface.
Parts
rootInteractive platform control root.
labelLabel content container.
iconIcon slot containers.
loading-indicatorNon-color-only indeterminate activity indicator shown before the stable label while loading.
Slots
labelRequired · exactly-one
leading-iconOptional · zero-or-one
trailing-iconOptional · zero-or-one
States
defaultIdle enabled state.
hoverPointer hover state on hover-capable devices.
focus-visibleKeyboard-visible focus state.
pressedActive press state.
disabledDisabled state derived from is-disabled.
loadingPending state with a visible activity indicator derived from is-loading.
Prevents activation and exposes disabled platform semantics.
is-loading
boolean
false
Shows pending action state while preserving dimensions and suppressing duplicate activation.
04
Slots & events
Slot
Cardinality
Accepts
Summary
label
exactly-one
text, node
Primary visible label and accessible-name source.
leading-icon
zero-or-one
icon
Optional icon before the label in inline flow.
trailing-icon
zero-or-one
icon
Optional icon after the label in inline flow.
Event
Payload
Summary
press
source, action
Canonical activation event emitted once per accepted activation.
05
Tokens
The contract's token bindings. Open the shared contextual sidebar from any example;
primary swatches reflect the color you pick there. Error swatches show the active
preset's values; editing any knob switches to custom and resets error to TWW · Ink.
Binding
Token
primary.background
color.primary
primary.background-hover
color.primary-hover
primary.background-pressed
color.primary-pressed
primary.foreground
color.on-primary
secondary.background
color.secondary
secondary.foreground
color.on-secondary
ghost.background
transparent
ghost.foreground
color.primary
danger.background
color.error
danger.foreground
color.on-error
disabled.background
color.disabled
disabled.foreground
color.on-disabled
radius
rounded.md
padding-x
spacing.lg
padding-y
spacing.sm
gap
spacing.sm
label
typography.label-md
loading-indicator-size
spacing.md
loading-indicator-stroke-width
2px
06
States
State
Source
Summary
default
platform
Idle enabled state.
hover
interaction
Pointer hover state on hover-capable devices.
focus-visible
platform
Keyboard-visible focus state.
pressed
interaction
Active press state.
disabled
property
Disabled state derived from is-disabled.
loading
property
Pending state with a visible activity indicator derived from is-loading.
07
Accessibility
From the contract's accessibility obligations. Role button; Label slot or aria-label provides the accessible name.
Enter activates the button.
Space activates the button.
Disabled state is exposed through native disabled semantics where the target has them.
Loading state keeps the accessible name stable and prevents duplicate activation.
The loading indicator is decorative because aria-busy exposes the pending state while the visible label remains the accessible name.