Side-anchored dialog surface with canonical open state, dismissal policy, focus management, and reduced-motion behavior.
Install @wyrd-company/react or the Flutter package and use it directly —
your DESIGN.md does the styling.
catalog/contracts/drawer.ymlsource of truth · verbatim
$schema: https://thewyrdingway.dev/schemas/component-contract.schema.ymlcontractVersion: 0.1.0identity:name: Drawertag: wyrd-drawerpackage: wyrd.component.drawertitle: Drawersummary: Side-anchored dialog surface with canonical open state, dismissal policy, focus management, and reduced-motion behavior.relationships:related-to: - quality-parity-and-gatesclassification:category: overlaycomposition: overlayinteractive: truetarget-strategy:react: requiredflutter: requiredsurface:properties: - name: is-opentype:kind: booleanrequired: falsedefault: falsecontrolled: truereflects: trueserializable: truesummary: Controlled open state. - name: default-opentype:kind: booleanrequired: falsedefault: falseserializable: truesummary: Initial uncontrolled open state. - name: is-modaltype:kind: booleanrequired: falsedefault: truereflects: trueserializable: truesummary: Makes background content inert while the drawer is open. - name: dismissibletype:kind: booleanrequired: falsedefault: truereflects: trueserializable: truesummary: Allows Escape, backdrop, and platform back navigation to request dismissal. - name: sidetype:kind: enumvalues: - start - end - bottomrequired: falsedefault: endreflects: trueserializable: truesummary: Anchored edge; start and end are logical, RTL-aware sides. - name: labeltype:kind: stringrequired: falseserializable: truesummary: Accessible-name fallback used when the title slot is absent.slots: - name: titlerequired: falsecardinality: zero-or-oneaccepts: - text - nodesummary: Optional drawer title and preferred accessible-name source. - name: contentcontent: truerequired: truecardinality: one-or-manyaccepts: - content - nodesummary: Drawer content. - name: actionsrequired: falsecardinality: zero-or-manyaccepts: - action - componentsummary: Drawer action area.events: - name: open-changepayload:is-open:kind: booleanreason:kind: enumvalues: - trigger - escape - backdrop - platform-back - action - programmaticbubbles: truecomposed: truecancelable: falsesummary: Canonical open-state change event. - name: dismisspayload:reason:kind: enumvalues: - escape - backdrop - platform-back - actionbubbles: truecomposed: truecancelable: truesummary: Dismissal request emitted before a dismissible drawer closes.states: - name: closedsource: behavior-runtimesummary: Drawer is absent from the active overlay surface. - name: openingsource: behavior-runtimesummary: Drawer is entering and focus is moving into the surface. - name: opensource: behavior-runtimesummary: Drawer is visible and owns modal focus semantics. - name: dismissingsource: behavior-runtimesummary: Drawer is exiting and focus is restoring.parts: - name: backdropsummary: Modal backdrop. - name: surfacesummary: Drawer surface container.slots: - title - content - actions - name: titlesummary: Title region.slots: - title - name: contentsummary: Content region.slots: - content - name: actionssummary: Action region.slots: - actionstokens:panel:background: color.surface-containerforeground: color.on-surfaceborder-color: color.outlinescrim:color: color.on-backgroundopacity: opacity.mutedborder-width: 1pxradius: rounded.lgshadow: shadow.lgpadding-x: spacing.lgpadding-y: spacing.lggap: spacing.mdinline-size: 24remblock-size: 20remmessages: []obligations:accessibility:role: dialogname: Title slot provides the accessible name when present; otherwise label property provides the accessible name.description: Content may provide the accessible description when declared by the target projection.keyboard: - Escape requests dismissal when dismissible is true. - Tab and Shift+Tab cycle inside a modal drawer.semantics: - Modal drawer makes background content inert on web targets. - Focus moves into the drawer on open and restores to trigger or return target on close. - Each drawer instance must provide either a title slot or label property.behavior:model: behavior-runtimeruntimeBlueprint: behavior/dialog-open-closeinteractions: - Escape, backdrop, platform back, and action dismissal request close when dismissible is true. - Reduced motion collapses transform tracks while preserving state transitions and completion events.hostEffects: - Apply inert background. - Trap focus while modal. - Restore focus after close.conditions: - rtl - reduced-motion - cvd-deuteranopia - text-expansion - safe-areasdui:status: partialserializableProperties: - is-open - default-open - is-modal - dismissible - side - labelserializableSlots: - title - content - actionseventBindings: - open-change - dismissnotes: Open-state data is serializable; overlay host coordination, focus trap, inert background, accessible-name enforcement, and platform back behavior require host effects.examples: - name: endstate: openproperties:default-open: trueside: endslots:title: Navigationcontent: Primary links and account tools. - name: startstate: openproperties:default-open: trueside: startlabel: Filtersslots:content: Filter controls for the current result set. - name: bottomstate: openproperties:default-open: trueside: bottomslots:title: Detailscontent: Secondary details anchored to the bottom edge.actions: Closeoverrides:react:slots:content: childrenflutter:slots:content: child
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.
Makes background content inert while the drawer is open.
dismissible
boolean
true
Allows Escape, backdrop, and platform back navigation to request dismissal.
side
start | end | bottom
end
Anchored edge; start and end are logical, RTL-aware sides.
label
string
undefined
Accessible-name fallback used when the title slot is absent.
03
Slots & events
Slot
Cardinality
Accepts
Summary
title
zero-or-one
text, node
Optional drawer title and preferred accessible-name source.
content
one-or-many
content, node
Drawer content.
actions
zero-or-many
action, component
Drawer action area.
Event
Payload
Summary
open-change
is-open, reason
Canonical open-state change event.
dismiss
reason
Dismissal request emitted before a dismissible drawer closes.
04
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
panel.background
color.surface-container
panel.foreground
color.on-surface
panel.border-color
color.outline
scrim.color
color.on-background
scrim.opacity
opacity.muted
border-width
1px
radius
rounded.lg
shadow
shadow.lg
padding-x
spacing.lg
padding-y
spacing.lg
gap
spacing.md
inline-size
24rem
block-size
20rem
05
States
State
Source
Summary
closed
behavior-runtime
Drawer is absent from the active overlay surface.
opening
behavior-runtime
Drawer is entering and focus is moving into the surface.
open
behavior-runtime
Drawer is visible and owns modal focus semantics.
dismissing
behavior-runtime
Drawer is exiting and focus is restoring.
06
Accessibility
From the contract's accessibility obligations. Role dialog; Title slot provides the accessible name when present; otherwise label property provides the accessible name.
Escape requests dismissal when dismissible is true.
Tab and Shift+Tab cycle inside a modal drawer.
Modal drawer makes background content inert on web targets.
Focus moves into the drawer on open and restores to trigger or return target on close.
Each drawer instance must provide either a title slot or label property.