Behaviours

Interaction in Milda is modelled, not coded. A small set of atoms, each a formal state machine, is composed by every archetype, and the states those machines emit are what paint keys on. This page lists the vocabulary, read off the prelude, and says what the file can say about it and what the React target does with it.

#Three layers

The spec definesA .milda file can sayThe React target does
19 atoms as state machines, 7 composites built from them, and a composition algebra: , , , broadcast with aggregates, and arena for gestures racing for one input.Which archetype a component starts from, and so which composition it has. On a part: which event an interaction raises, which prop drives a state, and the free behaviours (behavior focus-trap…). On a component: , and , carried in the file.Realizes every archetype's composition as idiomatic React: state hooks, ARIA, keyboard handling, portals. Reads a component's event emissions, state bindings and free behaviours. Does not yet read an authored // block.
Partly built

A component can declare uses, wire and gate, and the file carries them. No target realizes an authored composition yet: a component’s behaviour is still its archetype’s.proposal 0024

#The atom model

An atom is not a widget. It is an abstract interaction state machine: a few named states, the events that move between them, and the outputs it emits along the way. A toggle is two states, one event that flips them, and a change output, with nothing about checkboxes or tap targets. Three properties make atoms platform-neutral invariants:

  • They emit states, not pseudo-classes. Paint keys on checked, open, selected, never on :hover.
  • They gate on capabilities, not platforms. An atom that needs a keyboard declares input.keyboard; a target without it drops or substitutes the atom. No atom mentions a platform by name.
  • They compose through a small algebra. Wire one machine's output to another's input, listen only under a condition, fan out to a set, arbitrate a race. A select is activation opening a presentation, browse moving the highlight, selection committing the value, dismiss closing the surface: five stock machines and a few wires. The iOS wheel changes one wire.

#The atoms

19 indivisible machines. For each: what it does, the states it exposes for paint, what it requires, and the archetypes that compose it.

Invoke an action + emit event/payload on a trigger.

Exposes
no states: a transducer
Composed by
Button, Link, FileUpload

transducer (single state); foundational atom under almost every interactive archetype

schedulertimeout · debounce · interval

Timed transition: auto-dismiss, auto-advance, debounce, delay.

Exposes
no states: a transducer

load-bearing: all time-based interactions compose from it

Flip a boolean (BooleanInput core; tristate → +mixed).

Exposes
checked
Composed by
ToggleButton, BooleanInput
selectionsingle · multiple · range · none

Choose member(s) of a collection.

Exposes
selected
Composed by
ChoiceGroup, SingleSelect, MultiSelect, Combobox, DatePicker, TimePicker, TagsInput, Rating, Accordion, Tree, List, Table, Grid

multiple=set; range=anchor+extent (date range, shift-click, cell range)

browseroving · spatial · tree · scroll-detent

Move a cursor over a collection.

Exposes
active
Requires
input.keyboard or input.remote (mode∈{roving,tree})
Composed by
MenuButton, ChoiceGroup, SingleSelect, MultiSelect, Combobox, DatePicker, TimePicker, Tabs, ContextMenu, Menu, Tree, List, Table, Carousel, Grid

neighbor(): roving=linear · spatial=2D · tree=in/out/sib · scroll-detent=nearest

presentationinline · popover · menu · sheet · dialog · push · wheel

Manage a surface.

Exposes
open
Composed by
MenuButton, SingleSelect, MultiSelect, Combobox, DatePicker, TimePicker, ColorPicker, Dialog, Drawer, Popover, Tooltip, ContextMenu, Menu, Toast

surface is realization-only

Close on a configured trigger.

Exposes
no states: a transducer
Composed by
MenuButton, SingleSelect, MultiSelect, Combobox, DatePicker, TimePicker, ColorPicker, Dialog, Drawer, Popover, ContextMenu, Menu

trigger ∈ configured [outside, escape, commit, swipe-down, timeout]

Trap / contain / restore focus within a region (modal a11y).

Exposes
no states: a transducer
Requires
input.keyboard or input.remote
Composed by
Dialog, Drawer

no visual states (exposes none) - a behaviour guarantee, not a paint surface; realized as a focus trap on web, OS-owned on native sheets

Free text/value entry; commit on change|blur|enter.

Exposes
focused, empty, dirty
Composed by
TextField, TextArea, SearchField, Combobox, Stepper, ColorPicker, TagsInput

Value(s) along a min/max track (single/dual thumb).

Exposes
active
Composed by
Slider, ColorPicker

live (change) vs committed (commit)

Increment/decrement a value.

Exposes
atMin, atMax
Composed by
Stepper, Pagination

Valid/invalid against rules (PURE - does not listen to input).

Exposes
invalid, valid, pristine
Composed by
Field, TextField, TextArea

the when:change|blur|submit policy = a wire from value-entry/submission into check

Form-level orchestration: collective validation, submit, focus-first-error.

Exposes
loading, dirty
Composed by
Form

fields: DYNAMIC set of validation machines; FAN-OUT broadcast + FAN-IN aggregate/select

gestureswipe · long-press · pinch · pan · drag · drop

Swipe | long-press | pinch | pan | drag | drop.

Exposes
dragging
Requires
input.touch (per gesture)
Composed by
Slider, FileUpload, Drawer, Carousel

load-bearing: all drag-based interactions compose from it

Idle | loading | success | error lifecycle.

Exposes
loading, success, error
Composed by
Button, FileUpload, Skeleton

Observe scroll position: infinite-load, scroll-spy, reveal-on-scroll, parallax.

Exposes
atStart, atEnd, scrolled

atEnd → wire → async-state.start = infinite-load

progressdeterminate · indeterminate

Determinate / indeterminate completion.

Exposes
complete
Composed by
ProgressBar
livenesspolite · assertive

Announce dynamic changes (polite/assertive).

Exposes
no states: a transducer
Requires
a11y.screenreader
Composed by
Toast, Alert, ProgressBar

#Composites

7 familiar behaviours are not atoms. They are compositions, kept as first-class conveniences that compile down to their canonical form:

  • disclosure = toggle + presentation - ≈ toggle(expanded) + presentation(inline); exposes expanded
  • typeahead = scheduler + browse - jump to a member by typed prefix; requires input.keyboard
  • dnd = gesture + ordering - drag-and-drop move/reorder across containers; ordering is a non-behavior (collection mutation)
  • resize = gesture - drag-resize a region/panel; requires input.pointer
  • auto-dismiss = scheduler - self-close after a timeout (toast)
  • stepping-nav = navigation - ≈ navigation(ordered) + constraint; ordered progress through steps; exposes active, complete
  • pressability = gesture - press/hover/active feedback (ripple, highlight); contributes pressed/hovered feedback states ONLY - does not fire the action (that is activation)

#Decorations

Decorations shape how something happens or is presented without adding states of their own; they decorate machines and surfaces the way paint decorates parts:

  • motion - decorates existing transitions (spring/flip/fade+slide); adds no states
  • masking - format/constrain entry (date/phone/currency) - decorates value-entry draft
  • anchoring - position a surface relative to a reference (placement/flip/offset/match-size) - decorates presentation(popover|menu)
  • backdrop - scrim / blur behind a layer - decorates a modal presentation; painted via the `backdrop` facet on the backdrop anatomy part
  • momentum-scroll - inertial scroll with snap / detent - decorates scroll/browse on touch surfaces

#Non-behaviours

Four things that look like behaviours are deliberately excluded. They transform data or the render, not interaction, and belong to the data layer or the generator:

  • filter - derived view over a collection (data, not interaction)
  • virtualization - render windowing
  • ordering - collection mutation (reorder/sort)
  • aggregation - data transformation (grouping/totals) - DataGrid math

#The states

The vocabulary paint keys on: the atom states every target can draw, plus ambient gates, collection-position pseudo-states and the calendar's cell states. It is a closed list, and a word outside it is reported. A machine state no target draws yet, such as validation's invalid, is reached through a bound prop instead. Each one, and the atom or source that contributes it:

  • hoveredpressability
  • pressedpressability
  • focusedvalue-entry
  • focus-visiblevalue-entry (keyboard focus)
  • activebrowse
  • selectedselection
  • checkedtoggle
  • indeterminatetoggle (tristate)
  • expandeddisclosure
  • openpresentation
  • disabledambient (global gate)
  • readonlyambient
  • loadingasync-state
  • errorasync-state
  • successasync-state
  • firstcollection-position
  • lastcollection-position
  • oddcollection-position
  • evencollection-position
  • todaythe calendar core (DatePicker day)
  • outside-monththe calendar core (DatePicker day)
  • range-startthe calendar core (range mode)
  • range-endthe calendar core (range mode)
  • in-rangethe calendar core (range mode)
  • highlightedbrowse (the calendar cursor)

How a part uses them: Facets, under “States and conditions”.

#What a file says about behaviour

A component names its archetype and gets its composition. Beyond that, the file speaks about behaviour in four places, all on parts or in the contract:

  • emits { change on input payload bind value } - which declared event an interaction raises, with what.
  • bind value value, bind state open open - a prop as the part's value; a prop driving a state.
  • a11y { labelled-by label }, control switch, group segmented, the per-archetype config blocks - naming and realization choices the archetype offers.
  • behavior roving-tabindex { orientation vertical } - a free behaviour attached to a part, from a closed list: focus-trap, typeahead, cursor-navigation, clickaway, overlay-management, scroll-lock, roving-tabindex, filter.

#Authored composition

A component may also write its composition in the algebra the prelude uses, under aliases that and refer to:

milda
archetype SingleSelect
props {
  options : array<string> required
  value : string bind selected
  placeholder : string = "Choose"
}
events {
  change from S.change
}
milda
uses presentation(surface: dialog) as P
uses dismiss as D
wire D.dismissRequested -> P.close
gate D active when open

The reader lowers this into the document and the file round-trips it. No target reads it yet: a component's behaviour today is its archetype's canonical composition, which for every archetype is the same wiring the spec writes down. The statement is in the language because the spec is, and because an agent proposing a new interaction needs a place to say it.

Accessibility is modelled the same way
Accessible naming and label association are authored as neutral intent - this control is named by that part - and each target realizes it into its own attributes. Liveness (announcing changes), focus scope and the roles come with the archetypes. Correctness is in the model, not in each hand-written implementation.

These words, in the reference

  • Composes a behaviour atom from the prelude into the component, under an alias that wire and gate refer to.
  • Coordination between composed behaviours: when one atom signals, another acts.
  • A composed behaviour is only active while a prop condition holds.
  • A capability the component needs (input.pointer, platform.web).
  • Which declared event this part raises, and on what interaction.
  • A prop drives something about the part.
  • A free behaviour attached to the part: portable interactions that are not tied to an archetype.
  • Inside a part: a presentation intent.
  • How assistive technology names and describes the part: a name of its own (fixed or bound), or another part’s text by path.
  • A demo interaction, meaningful only inside an example: when the part is activated, flip or set one of the scene’s demo variables.

Open a word for its entry, or read them all in the reference.

See it built in the tour8. Inputs and behaviour4. Variants and states