Language reference
Every statement a .milda file can contain: where it may stand, how it is spelled, what it means, what the document stores, and what happens when it is left out. Use it to read a file you exported, or to check what a word means.
The other language pages explain the ideas - values, facets & tokens, layout, behaviors, archetypes. This page is for looking things up. It is checked against the parser, so a keyword the language accepts cannot be missing here, and every example on it parses.
#Index
@a11yactionaliasaltarchetype- Arrows
assetsbehaviorbindcell- Comments
componentcompute- Config blocks
contentcontext-groupcontroldemodestinationdocsemitsescapeeventsexampleforeignfoundationsgateglobalglobal-propgroupComponentsgroupThe library around the componentsgroupParts: events, bindings and behaviouriconsinstancekindlayerlayout- Literals
mediametamildamotionorigin- Paint facets
part- Paths
- Predicates
preludepresentpresentation- Prop constraints
propsrawrealizerepeatrequiredrequiresruleslotsourcestate- Statement terminators
tokentype- Type expressions
usesvaluewhenwire
#Lexical basics
Everywhere in the file.
# text to the end of the line
A comment. Everything from # to the end of the line is ignored, which is why a hex colour is written hex(3b82f6) rather than #3b82f6.
Comments are not carried: a file that is read and written back loses them. Anything that should survive a round trip has a statement of its own - a description string, a meta entry, a note.
# Brand colours, from the 2026 refresh milda 0.10
Explained on The .milda file
statement ; statement | statement <newline> statement
A statement ends at a newline or a semicolon. The two are interchangeable, so a short block can stay on one line.
part Toolbar: container { layout { stack row; gap space.sm; align center } }
Explained on The .milda file
name . name …
A dotted path addresses something by name: a token (space.sm), a part (Header.Title), a context value. A token NAME may be written with / (space/sm); a reference to it uses dots.
Nothing in a .milda file is addressed by a database id. Every reference is a name the file itself declares, so the file resolves on its own.
token space/sm : spacing = 8px token gap/default : spacing = alias by Density { default -> space.sm }
Explained on The .milda file
left -> right | left → right
The arrow maps one thing to another: a context to a token in an alias, a predicate to a value in a content block, one end of a wire to the other. -> and → are the same token.
token violet/500 : color = hex(8b5cf6) token violet/600 : color = hex(7c3aed) token accent : color = alias by ColorScheme { default -> violet.600; Dark -> violet.500 }
Explained on The .milda file
#File header
At the top level, usually first.
milda <version>
Which version of the surface syntax the file is written in. Bumped whenever the grammar gains capability, so a reader can tell "this file predates motion" from "this file has no motion".
Today the version is recorded, preserved and printed, but nothing gates on it: a newer construct is read whatever the header says.
- When omitted
- The reader assumes the current surface version, and the printer writes that. A file that does not say is not treated as an old file.
- Stored as
document.milda
milda 0.10
Explained on The .milda file
See also prelude
prelude <version>
Which version of the prelude - the built-in archetypes and behaviour atoms - the file was authored against.
- When omitted
- The current prelude version.
- Stored as
document.prelude
milda 0.10 prelude 0.0.2
Explained on The .milda file
meta
proposal 0026meta { <key> <value> … }Descriptive metadata. At the top level, name, version and description describe the design system itself and every other key becomes a project metadata entry. Inside a component it is the component’s metadata.
A value is a string, a number, true/false, a bare word, or a list in [ ].
A component is declared with an identifier, so a component whose display name is free text ("Color picker") carries that name as meta { name "Color picker" }.
- Stored as
document.meta, foundations.metadata[], component.meta
meta { name "Acme" version "2.1.0" tags [web, ios] }
Explained on The document
#Foundations and tokens
At the top level (context-group, foundations), and inside foundations { }.
context-group
proposal 0001context-group <Name> { <Context> … }A dimension a token can answer differently along: colour scheme, density, platform, brand. Its members are the contexts. A token chooses per context with alias by <Name>, and a prop typed by the group chooses the context per instance.
- Stored as
foundations.contextGroups[]
context-group ColorScheme { Light Dark }
Explained on Tokens & context
See also alias, Type expressions
foundations { token … | layer <Name> { token … } … }The design tokens. Tokens written directly inside it land in a default layer; layer blocks give them an authored order.
- Stored as
foundations.layers[].tokens[]
foundations { token space/sm : spacing = 8px }
Explained on Tokens & context
layer
proposal 0006layer <Name> { token … }A named layer of tokens, such as primitives and then the semantic tokens that alias them. Declaration order is layer order.
- When omitted
- Every token goes into one default layer. A fully layered file gains no empty default layer.
- Stored as
foundations.layers[]
layer Base { token violet/600 : color = hex(7c3aed) } layer Semantic { token accent : color = alias by ColorScheme { default -> violet.600 } }
Explained on Tokens & context
token <name> : <type> = <value> [ "description" ]
Declares a design token. The type is a closed word that decides what the value means, so 1.5 is a ratio for a ratio token and an error for a spacing one.
A length type (spacing, radius, size, border, font-size, letter-spacing) needs a unit: 8px, or scaled(1.25) for a length relative to the reader’s text size. A bare number is rejected there.
The trailing string is the token’s description, which the docs show next to it.
Older spellings are still read and never written: dimension for size, line-height and number for ratio, camelCase forms such as fontSize.
color- A colour, written with a colour function:
hex(…),oklch(…),rgb(…). spacing- A gap or padding length.
radius- A corner radius.
pillmeans fully rounded. size- A length for a width or height.
border- A border width.
font-size- A text size.
letter-spacing- Tracking.
font-weight- A numeric weight, 100 to 900.
font-family- A font family record: family, fallback, source, licence, asset.
typography- A text style record: family, size, weight, line height, letter spacing.
ratio- A unitless ratio, such as a line height of 1.5.
duration- A time:
120ms,0.2s. easing- A timing curve.
opacity- A transparency from 0 to 1.
shadow- A shadow.
elevation- Depth. Each platform realizes it its own way (shadow, tonal surface, nothing).
tonal- A tonal elevation step.
ring- A focus-indicator colour.
backdrop- A colour behind a layer (a scrim).
blur- A blur radius.
gradient- A gradient.
none- The explicit absence of a value, typically one platform’s slot of an
alias.
- Stored as
foundations.layers[].tokens[] { name, type, value, description }
token space/md : spacing = 12px "Default gap between related controls" token leading/normal : ratio = 1.5
Explained on Tokens & context
#Token values
After the = of a token declaration, and in the slots of an alias block.
hex(…) | oklch(…) | srgb(…) | rgb(…) | p3(…) | hsl(…) | <n>px | scaled(<n>) | <n>ms | <n> | pill | transparent
A value written as itself. Literals type themselves: a colour function is a colour, a number with a unit is a length or a time, a bare number takes the meaning the token’s type gives it. The full table is on the Values & literals page.
px and dp are the same density-independent unit; rem and sp are read as text-scaled lengths and written as scaled(n). rgba/hsla are read as rgb/hsl.
hex- sRGB as 3, 4, 6 or 8 hex digits:
hex(3b82f6). oklch- Perceptual lightness, chroma and hue.
srgb- sRGB channels in 0..1.
rgb- sRGB channels in 0..255.
p3- Display-P3 channels in 0..1, a wider gamut than sRGB.
hsl- Hue, saturation, lightness.
scaled- A length relative to the reader’s text size:
scaled(1.25). transparent- No colour at all.
pill- A radius that fully rounds the shorter side.
px- A density-independent length. Canonical; what the printer writes.
dp- The same unit as
px, read for authors coming from Android. rem- Read as a text-scaled length and written back as
scaled(n). sp- The same as
rem. ms- Milliseconds.
s- Seconds.
token brand : color = oklch(0.62 0.19 256) token radius/round : radius = pill token fast : duration = 120ms
Explained on Values & literals
See also token
raw <value> | raw { <field>: <value>; … }An explicit typed value. Needed for an opaque string (a shadow or easing written out) and for the structured records of font-family and typography; a bare { … } record may omit the keyword.
A typography record is a text style when it names a family: a font-family token path, or a font-family record written in place. Without one it is carried as an opaque value.
- Stored as
token.value = { kind: "raw", value }
token standard : easing = raw "cubic-bezier(0.2, 0, 0, 1)" token font/sans : font-family = { family: "Inter"; fallback: sans-serif; source: google; license: "OFL-1.1" } token body : typography = { family: font.sans; size: 15px; weight: 400; line-height: 1.5 }
Explained on Values & literals
alias by <ContextGroup> { default -> <value>; <Context> -> <value>; … }A token whose value depends on a context. Each slot names a context of the group (or default) and points at another token, a literal, or a compute.
default is the fallback for every context the block does not name.
A literal or compute in a slot is stored as a token of its own and printed back inline; the reader notes each one with an inline-literal message.
Writing a bare token path after = (token on-accent : color = white) is sugar for an alias with only a default slot, and the reader says so with a ref-sugar warning.
- Stored as
token.value = { kind: "alias", by, refs }
token white : color = hex(ffffff) token slate/900 : color = hex(0f172a) token surface : color = alias by ColorScheme { default -> white Dark -> slate.900 }
Explained on Tokens & context
See also context-group
escape "platform text" [ note "why" ]
A platform-specific value the language cannot express, carried verbatim. It marks the token as partial: a target that cannot read the string has nothing to fall back on, so use it as a last resort and say why in the note.
- Stored as
token.value = { kind: "escape", raw, note }
token tint : color = escape "color-mix(in srgb, red 40%, blue)" note "web only, until compute can mix in srgb"
Explained on Values & literals
compute
proposal 0044compute <base> [ in <space> ] { <step> … }A value derived from another one, live: "the accent, 20% lighter". When the base changes, the result follows. The steps that are legal depend on the token’s type, so a colour step on a length is an error, not a no-op.
The base is a token path, a literal, or another compute.
in <space> picks the colour space the maths happens in: srgb, display-p3, oklch, hsl, oklab, lab, lch. It is wider than the set a literal can be written in, because the maths space and the spelling space are different questions.
A literal base is stored as a token of its own, like a literal in an alias slot.
A fraction is written as a percentage or a number: 20% and 0.2 are the same step.
lighten- Colour: raise lightness by a fraction.
darken- Colour: lower lightness by a fraction.
saturate- Colour: raise saturation by a fraction.
desaturate- Colour: lower saturation by a fraction.
alpha- Colour: set the opacity.
rotate- Colour: turn the hue by degrees:
rotate 30deg. mix- Colour: blend with another operand by a fraction.
scale- Length: multiply.
offset- Length: add a length (
2px). round- Length: round to a multiple of a length.
- Stored as
token.value = { kind: "compute", base, ops, space }
token accent : color = hex(7c3aed) token accent-hover : color = compute accent in oklch { darken 10% } token space/sm : spacing = 8px token space/lg : spacing = compute space.sm { scale 2 }
Explained on Tokens & context
#Types
At the top level (type), and wherever a type is expected: a prop, a demo variable, a part value.
type <Name> = <type expression>
A shared type, declared once and used by name in any prop. A bare name in a type position resolves to a shared type or, failing that, to a context group.
- Stored as
foundations.sharedTypes[]
type Option = object { label : string value : string disabled? : boolean }
Explained on Components, parts & the contract
See also Type expressions
string | number | boolean | enum(a, b) | ref <Name> | array<T> | object { f : T; g? : T } | union(T, U) | component[(A, B)] | context <Group> | <Name>What a prop, a demo variable or a part value holds. These are neutral types: each target maps them to its own (a TypeScript union, a Swift enum).
string- Text.
number- A number.
booleantrueorfalse.enum- One of a fixed set of words:
enum(primary, secondary). ref- A shared type by name:
ref Option. array- A list:
array<string>. object- A record of fields;
?after a field name makes it optional. union- Any one of several types.
component- A slot for a component instance, optionally only the listed ones:
component(Icon, Avatar). context- A context of a context group, chosen per instance:
context Size. A bare group name means the same.
props { tone : enum(neutral, danger) = neutral items : array<string> leading : component(Icon) }
Explained on Components, parts & the contract
#System-wide declarations
At the top level.
global-prop
proposal 0051global-prop <name> : <type> [ = <default> ] [ "description" ]
A prop declared once for the whole system, so every component that takes it agrees on its name, type and default. A component takes it with global <name> in its props block.
- Stored as
foundations.globalProps[]
global-prop size : enum(sm, md, lg) = md "The control size, shared by every input"
Explained on Components, parts & the contract
See also global
rule
proposal 0052rule <id> error|warning { <statement> because "reason" }A usage rule: how the system is meant to be composed, checked over the instances a consumer writes. One rule states one thing, and the reason is mandatory - it is what a person or an agent reads when the rule fires.
A subject is a component by name or archetype <Name>, optionally narrowed with where <predicate> over its props.
A reference that resolves to nothing is a warning, and the rule is kept.
error- Severity: the composition is wrong.
warning- Severity: the composition is suspicious.
because- The reason, as a quoted string. Required.
minmin 1 Tab within Tabs- at least N of the subject inside the container.maxmax 1 Button where variant = primary within Form- at most N.nevernever Badge within Button- the subject must not appear inside the container.onlyonly Tab within Tabs- the subject may appear only inside the listed containers.within- Introduces the container of a count,
neveroronlyrule. where- Narrows a subject by a predicate over its props.
tokenstokens color, spacing- those token types may only be used through tokens, never as literals.preferprefer Select for archetype SingleSelect- use this component wherever that archetype is wanted.
- Stored as
foundations.rules[]
rule no-stacked-dialogs error { never archetype Dialog within archetype Dialog because "A dialog over a dialog traps focus twice." }
Explained on Usage rules & constraints
#Components
At the top level (component), and inside component { }.
component <Name> [ "description" ] { … }A component of the library: its contract (props, events), its anatomy (parts), and how it is realized. The name is an identifier, because every reference to the component resolves against it.
- Stored as
components[]
component Button "The primary action." { archetype Button }
Explained on Components, parts & the contract
archetype <Archetype>
The built-in blueprint the component is an instance of (Button, Select, Dialog, ...). It brings the contract, the anatomy and the behaviour the component starts from. The Archetypes reference lists them.
- When omitted
- An archetype-less component (a Card, a layout): nothing to inherit, every part is the author’s.
- Stored as
component.archetype
archetype SelectExplained on Archetypes
group <path/to/group>
Inside a component: the library category the component sits in, by group path. The group itself is declared at the top level.
- Stored as
component.group
group Forms/Inputs
Explained on The library around the components
uses
proposal 0024uses <atom> [ ( <param>: <value>, … ) ] as <Alias>
Composes a behaviour atom from the prelude into the component, under an alias that wire and gate refer to. The Behaviors reference lists the atoms.
- Stored as
component.composition.uses[]
uses selection.single as S uses presentation(surface: popover) as P
Explained on Behaviours
wire <A.signal> [ when <prop>[=<value>] ] -> <B.action>[(<arg>)]
Coordination between composed behaviours: when one atom signals, another acts. Also allowed inside realize.
- Stored as
component.composition.coordination[] (wire)
uses selection.single as S uses presentation as P wire S.change -> P.close
Explained on Behaviours
gate <Alias> active when <prop>[=<value>]
A composed behaviour is only active while a prop condition holds.
- Stored as
component.composition.coordination[] (gate)
uses presentation as P gate P active when disabled=false
Explained on Behaviours
requires <capability> …
A capability the component needs (input.pointer, platform.web). Read and reported, but not stored: the document has no field for it yet, so the reader warns and moves on.
requires input.pointer
Explained on Behaviours
part
proposal 0041part <path> [ : <node kind> ] { <part statement> … }A node of the component’s anatomy. The name is a PATH, and the path is how the tree is written down: Header.Title is the child Title of the part Header.
The FIRST part in the component is its root. Every part whose path has no dotted prefix naming another part is a child of the root.
The header says what the part IS where it is named: part Title: text { is the same part as one whose body says kind text. The colon reads as everywhere else on the surface - a name, then what it is. Exports write the header (surface 0.9); the statement keeps working, and saying a kind both ways is reported, with the header winning a contradiction (proposal 0055).
Which parts a component cannot do without is its archetype’s answer, not the file’s: a Button has a label. A file may leave a required part out and the reader adds it; editor tooling reports the gap as an error and offers to write the part in.
A part keeps its braces even when nothing follows the header: part icon: icon {}.
Parts are addressed by path everywhere else too: an accessible name’s labelled-by, a behaviour’s target node, an ancestor predicate leaf.
- Stored as
component.anatomy (one node per part)
component Card { part Card: container {} part Header: container {} part Header.Title: text { content "Hello" } }
Explained on Components, parts & the contract
#Props and events
Inside a component’s props { } and events { } blocks.
props { <name> : <type> [ = <default> ] [ required [when <predicate>] ] [ bind <param> ] [ @<key> <value> … ] [ "description" ] … }The component’s public inputs. A name, a colon, a type; then optionally a default, whether it is required, which archetype parameter it drives, annotations, and its documentation.
bind <param> connects the prop to one of the archetype’s bindable parameters - value : ref Option bind selected makes value the controlled selection of a select.
The colon is required (since surface 0.4): a name then its type is written one way everywhere.
- Stored as
component.contract.props[]
props { label : string = "Save" "The visible text" variant : enum(primary, secondary) = primary disabled : boolean = false }
Explained on Components, parts & the contract
See also required, Prop constraints, global, @
required
proposal 0052<prop> : <type> required [ when <predicate> ]
The prop must be given. With when, it must be given while a condition over the component’s other props holds. Only prop leaves are allowed in that predicate.
- Stored as
prop.required / prop.requiredWhen
props { href : string kind : enum(button, link) = button label : string required target : string required when kind = link }
Explained on Usage rules & constraints
Prop constraints
proposal 0052one-of a, b | any-of a, b | exclusive a, b
A constraint over a group of props. Written on its own line in the props block, and read as a keyword only when a prop name follows, so a prop may still be called exclusive.
one-of- Exactly one of the props is given.
any-of- At least one of them is given.
exclusive- At most one of them is given.
- Stored as
component.contract.constraints[]
props { label : string icon : string any-of label, icon }
Explained on Usage rules & constraints
global
proposal 0051global <name>, <name> …
Takes system-wide props declared with global-prop. Their type and default come from the declaration. A name nothing declares is an error and the prop is dropped.
- Stored as
component.contract.props[] with global: true
global-prop size : enum(sm, md, lg) = md component Input { props { global size label : string } }
Explained on Components, parts & the contract
See also global-prop
@
proposal 0026<prop> : <type> @<key> <value> …
Descriptive annotations on a prop, such as its lifecycle. They describe the prop and never change its contract.
- Stored as
prop.meta
props { tone : string @status deprecated @since 1.2.0 }
Explained on Components, parts & the contract
events { <name> [ from <Machine.signal> ] … }The events the component raises. A part says WHEN with emits; from names the behaviour signal an event surfaces, when it is one.
- Stored as
component.contract.events[]
events { click valueChange from S.change }
Explained on Components, parts & the contract
See also emits
#Realization
Inside a component’s realize <target> { } block.
realize <target> [ when <prop>=<value> ] { … }How the component is realized on one target, where the targets genuinely differ in behaviour or structure (a listbox on the web, a wheel on iOS). Style divergence does not belong here - that is token aliasing.
presentationpresentation popover { place bottom; flip; matchWidth }- the surface the content is presented on, and how it is placed.browsebrowse roving- how the user moves through items.commitcommit explicit on click enter|commit continuous { live input; settled change }- when a choice becomes the value.dropdrop typeahead- leave out composed atoms this target does not realize.notenote "…"- prose about the realization.dismissdismiss outside escape|dismiss none- what closes an overlay.backdropbackdrop scrim|blur|none- what is drawn behind an overlay.wire- Target-specific coordination, as at the component level.
explicit- Commit mode: the value changes only on the listed interactions (
on click enter). continuous- Commit mode: the value follows the user as they go, as on a slider.
live- In a
continuousblock: the event raised while the user is moving. settled- In a
continuousblock: the event raised once they let go.
- Stored as
component.realize[]
realize web { presentation dialog { place center } backdrop scrim dismiss outside escape note "Focus is trapped while open." }
Explained on Archetypes
#Parts: what a part is
Inside part <path> { }, in a component or an example; the kind also in its header.
kind
proposal 0041part <path>: <node kind> { … } | kind <node kind>What the part IS, in neutral terms. The platform element (div, UIView, Composable) is the target’s decision and is deliberately not in the file.
Two spellings, one meaning: after the colon in the part’s header (part label: text {), which is what an export writes, or as a statement in its body. Both at once is a warning when they agree and an error when they do not, and then the header wins (proposal 0055).
An export states the kind of EVERY part rather than leaving it to the archetype’s role: a role is a safe default only while the prelude keeps it, and a saved file should not change meaning when the prelude does.
container- Holds and lays out other parts.
item- One entry of a collection (an option, a menu item).
text- Text.
control- Something the user activates or toggles.
input- Something the user types or picks a value into.
output- A computed or status value shown to the user.
icon- A glyph.
content- Media: an image, a video, an embed.
fragment- A grouping with no box of its own.
foreign- Quarantined target-specific code.
table- A table.
row- A table row.
cell- A table cell.
instance- Another component of the library, nested.
- When omitted
- The archetype’s own role for the part, if it names one; otherwise inferred - a part with children is a container, a part with text paint is text.
- Stored as
node.kind
part label: text {} part icon { kind icon }
Explained on Components, parts & the contract
See also part
origin
proposal 0041origin root | archetype | author
Where the part came from: provenance. It answers "did the archetype give me this part, or did I add it?" - and for the root, "this is the component’s outermost node".
Which part IS the root is decided by position - the first part of the component - not by this statement. That is also why the printer leaves origin root out (proposal 0055): it would repeat what the position says. The reader still accepts it, and writing it on a later part does not move the root.
Unlike the kind, provenance is not a header word: the header says what a part is, and where it came from stays in the body.
root- The component’s root node, exactly one per component. What it may contain comes from what the archetype produces (a Button’s root accepts inline content only), and it is never a transparent wrapper.
archetype- Born from the archetype’s anatomy, like a checkbox’s indicator. The default, so the printer leaves it out.
author- Added by the author: a part the archetype does not declare.
- When omitted
rootfor the first part,archetypewhen the archetype declares a part of that name (or the component has no archetype),authorotherwise.- Stored as
node.origin
part Button: container {} part spinner: icon { origin author }
Explained on Components, parts & the contract
See also part
present
proposal 0031present when <predicate>
The part exists only while the predicate holds - not hidden, absent. An icon that renders only when the icon prop is set, a clear button only while there is a value.
- When omitted
- The part is always present.
- Stored as
node.presence
part icon: icon { present when icon }
Explained on Components, parts & the contract
See also Predicates
instance
proposal 0012instance <Component> { <prop> = <value> … }The part is another component of the library, nested, with its props set. A value is fixed or bind <prop> to pass one of this component’s props through. A component cannot contain itself, directly or through others.
- Stored as
node.instance
part status: instance { instance Badge { label = "Beta" tone = bind tone } }
Explained on Components, parts & the contract
foreign
proposal 0041foreign <target> [ "label" ] "code"
Code written in one target’s own language, quarantined. A reader that does not implement that target keeps it verbatim and skips it rather than interpreting it. The escape hatch of last resort: the rest of the system stays portable.
- Stored as
node.foreign
part chart: foreign { foreign web-react "Sparkline" "<Sparkline data={props.points} />" }
Explained on Components, parts & the contract
#Parts: content and data
Inside part <path> { }.
slot
proposal 0004slot [ single | optional | many ] [ of content | of <Type> ] [ keyed-by <field> ] [ default ] [ as <name> ] [ role trigger|panel ] [ sample <sample> ] [ "description" ]
The part is a hole the consumer fills: the label of a button, the items of a menu. What it accepts and how many are part of the component’s public API.
single- Exactly one fill. The default.
optional- Zero or one.
many- Any number.
ofof content(free content, the default) orof <Type>(typed data or a child component).keyed-by- The field that identifies each item of a
manyslot. default- This slot receives the component’s positional children.
as- The slot’s public name, when it differs from the part’s.
role- Its structural role in a disclosure:
triggerorpanel. trigger- Role: the part that opens the disclosure.
panel- Role: the part that is disclosed.
sample- A design-time fill for the preview, never generated:
"Item",example "Name", or a list["a", "b"].
- Stored as
node.slot
part label: text { slot of content default sample "Get started" }
Explained on Components, parts & the contract
content "text" | content bind <prop> | content { default <v>; when <predicate> -> <v>; otherwise <v> }The text the part shows: fixed, bound to a prop, or chosen by conditions. In the block form the rules are tried in order and default answers when none match.
Not text: text is the paint facet for the text style, and a keyword whose meaning depends on its argument reads fine and parses wrong.
- Stored as
node.content
part label: text { content { default bind label when disabled -> "Unavailable" } }
Explained on Components, parts & the contract
value <type>
The type of value an input part holds, such as string for a text field or number for a slider.
- Stored as
node.value.type
part control: input { value string bind value value }
Explained on Components, parts & the contract
See also bind
repeat <prop> [ as <alias> ] | repeat static [ a, b, … ] [ as <alias> ]
The part is drawn once per item of a list prop (or of a fixed list). Inside, <alias> names the current item.
- When omitted
- The part is drawn once. The alias defaults to
item. - Stored as
node.repeat
part option: item { repeat items as option }
Explained on Components, parts & the contract
cell [ header ] [ col | row ]
A table cell’s role: a data cell, or a header cell for its column or its row.
header- A header cell.
col- Heads its column.
row- Heads its row.
- Stored as
node.cell
part heading: cell { cell header col }
Explained on Components, parts & the contract
media
proposal 0028media img | video | audio | embed
What kind of media a content part shows.
img- An image.
video- A video.
audio- Audio.
embed- An embedded document.
- Stored as
node.media
part avatar: content { media img source bind src sample url "https://example.com/a.png" alt bind name }
Explained on Components, parts & the contract
source
proposal 0028source static <asset> | source [bind] <prop> [ sample asset <asset> | sample url "…" ]
Where a media part’s file comes from: a fixed asset of the library, or a prop - with an optional sample the preview shows while the prop is empty.
- Stored as
node.mediaSource
part logo: content { media img source static brand-logo }
Explained on Components, parts & the contract
alt "text" | alt bind <prop>
A media part’s text alternative, fixed or bound to a prop.
- Stored as
node.mediaAlt
part photo: content { media img alt bind caption }
Explained on Components, parts & the contract
destination "url" | destination bind <prop>
Where a navigating part goes - a link’s target - fixed or bound to a prop. Stated, never guessed from a prop name.
- Stored as
node.destination
part Link: container { destination bind href }
Explained on Components, parts & the contract
#Parts: events, bindings and behaviour
Inside part <path> { }.
emits { <event> [ on <interaction> ] [ payload <value> ] [ signal <name> ] [ locked ] … }Which declared event this part raises, and on what interaction. The event must be declared in the component’s events block.
on- The interaction that fires it. Defaults to
activate. payload- What the event carries: a fixed value or
bind <prop>. signal- The behaviour signal this emission stands for.
locked- The emission belongs to the archetype and cannot be removed in the editor.
activate- Interaction: clicked, tapped, or Enter/Space.
change- Interaction: the value changed and was committed.
input- Interaction: the value changed while editing.
focus- Interaction: received focus.
blur- Interaction: lost focus.
select- Interaction: an item was chosen.
open- Interaction: opened.
close- Interaction: closed.
dismiss- Interaction: dismissed by the user (outside press, Escape).
- Stored as
node.emits[]
part control: input { emits { valueChange on input payload bind value } }
Explained on Behaviours
See also events
bind value <prop> | bind state <state> <prop>
A prop drives something about the part. bind value makes the prop the part’s value (two-way for an input). bind state puts the part into a state while the prop is true - bind state disabled disabled.
The same word is the "bound to a prop" form of a value elsewhere: content bind label, alt bind caption, tone = bind tone.
- Stored as
node.valueBinding / node.stateBindings[]
part Field: container { bind state disabled disabled bind state error invalid }
Explained on Behaviours
behavior
proposal 0041behavior <kind> { <field> <value> … }A free behaviour attached to the part: portable interactions that are not tied to an archetype. Fields that name a node take a part path. behaviour is the same keyword.
focus-trap- Keep focus inside while open:
initial-focus-node-id,return-focus-on-close,allow-escape-key. typeahead- Jump to an item by typing its first letters:
target-node-id,label-node-id,reset-delay-ms,case-sensitive. cursor-navigation- Arrow keys move a cursor through items:
orientation,wrap,target-node-id,item-node-id. clickaway- React to a press outside:
event-type,exclude-node-ids. overlay-management- Position and open/close an overlay:
anchor-node-id,placement,offset-px,flip,same-width,open-prop-name,close-on-select,commit-from-binding. scroll-lock- Stop the page scrolling while open:
target. roving-tabindex- One tab stop for a group, arrows move within it:
orientation,target-node-id,item-node-id,loop. filter- Narrow the items by a query:
query-prop-name,item-field,match-mode,case-sensitive.
- Stored as
node.behaviors[]
part list: container { behavior roving-tabindex { orientation vertical loop } }
Explained on Behaviours
Config blocks
proposal 0034<config> { <field> <value> … } | severity <level> | accordion single|multipleThe per-archetype settings that change what a component does rather than how it looks. Every field is checked against a fixed list, because a .milda file is untrusted input. A block-shaped config is read as one only when { follows its name, which keeps overlay { … } apart from the overlay paint facet.
calendarselection-mode single|range,week-starts-on <n>,disabled-weekdays [0, 6].time-pickerstep <minutes>,use24-hour.tabsorientation horizontal|vertical,activation automatic|manual.sliderrange,orientation horizontal|vertical.ratingmax <n>,allow-half.color-pickerformats,default-format hex|rgb|hsl|hsb,color-space srgb|oklch,alpha,eyedropper,swatches,layout popover|inline.overlaydismiss outside escape closeButton,placement top|bottom|left|right|center,backdrop none|scrim|blur.severity- Single-valued:
severity info|success|warning|danger. accordion- Single-valued:
accordion single|multiple.
- Stored as
node.calendar, node.tabs, node.overlay, …
part tablist: container { tabs { orientation vertical activation manual } }
Explained on Archetypes
control
proposal 0016control checkbox | switch
How a boolean control is realized: as a checkbox or as a switch. The contract is the same either way.
checkbox- A box with a check glyph; can be indeterminate.
switch- A sliding track and thumb.
- Stored as
node.control
part toggle: control { control switch }
Explained on Archetypes
group
proposal 0022group radio | segmented
Inside a part: how a one-of-N choice is realized, as a radio group or as a segmented control.
radio- A list of radio buttons.
segmented- Joined segments, one selected.
- Stored as
node.group
part options: container { group segmented }
Explained on Archetypes
presentation
proposal 0022presentation accessible-name
Inside a part: a presentation intent. accessible-name means the part’s text is not drawn but becomes the accessible name - how an icon-only button keeps a label.
accessible-name- Not shown; used as the accessible name.
- Stored as
node.presentation
part label: text { presentation accessible-name }
Explained on Behaviours
See also realize
a11y
proposal 0013a11y { name <value>; labelled-by <part>; described-by <part> }How assistive technology names and describes the part: a name of its own (fixed or bound), or another part’s text by path. labeled-by is read as labelled-by.
name- The accessible name:
"Close"orbind label. labelled-by- Another part supplies the name.
described-by- Another part supplies the description.
- Stored as
node.a11y
part label: text { content "Email" } part hint: text { content "We never share it." } part control: input { a11y { labelled-by label described-by hint } }
Explained on Behaviours
action
proposal 0021action <interaction> toggle <variable> | action <interaction> set <variable> <value>
A demo interaction, meaningful only inside an example: when the part is activated, flip or set one of the scene’s demo variables. It lets a demo scene open its own dialog.
toggle- Flip a boolean demo variable.
set- Write a value into a demo variable.
- Stored as
node.actions[]
example "Open dialog" for Dialog { demo { open : boolean = false } part trigger: control { action activate toggle open } }
Explained on Behaviours
#Parts: paint, layout, states and motion
Inside part <path> { }, and inside its state and when blocks.
<facet> <value> …
A paint facet: an abstract slot such as "background" or "text colour", pointed at a token. There are no CSS properties in the language; each target maps facets to its own primitives. A dotted value is a token reference, a number is a literal, a bare word is an intent keyword.
A facet cannot be context-aliased itself (fill alias by … is an error): point it at a token and put the alias on the token.
Edges are logical, so a design system reads the same right to left. inset.left and the other physical words are read as the logical edge they name left to right, with a warning, and never written.
fill- The surface behind the part.
ink- The foreground: text and icon colour.
border- The edge: a colour token, a width token, and
solid/dashed/dotted, in any order. border.top- One physical edge. Also
border.right,border.bottom,border.left. border.inline-start- One logical edge. Also
border.inline-end,border.block-start,border.block-end. corner- The corner radius.
inset- Padding: one token for all sides, or two for block then inline.
inset.inline- Padding on one axis only:
inset.inlinefor the start and end edges,inset.blockfor the top and bottom. inset.inline-start- Padding on one logical edge. Also
inset.inline-end,inset.block-start,inset.block-end. The more specific statement wins on its edge, soinset space.2withinset.inline-start space.1is 2 everywhere and 1 on the leading side. gap- Space between children.
text- The text style or size.
text.clamp- Truncate to N lines.
text.wrap- How text wraps.
weight- The font weight.
font- The font family.
slant- Italic or upright.
elevation- Depth.
overlay- A state layer, such as the hover tint.
opacity- Transparency.
ring- The focus indicator.
backdrop- A scrim or blur behind the part.
- Stored as
node.facets
part Button: container { fill color.accent ink color.on-accent border color.line border.hairline solid corner radius.sm inset space.sm space.lg }
Explained on Facets
layout [ when <prop>=<value> ] { <key> <value>; … }How the part lays out its children and how it sizes itself, in the propose/choose model. The Layout model page explains the model; this is the vocabulary. Every word here is read, stored, printed and rendered by every target (proposal 0056).
stackstack row|column|layers- the axis children flow along (layersdraws them on top of each other, the stack sizing to the largest). A part with nostackis not a layout container.wrapwrap nowrap|wrap|wrap-reverse- whether children start new lines when out of room.gap- Space between children, a spacing token or a length.
align- Cross-axis:
start|center|end|stretch|baseline. Vertical in alayersstack. distribute- Main-axis:
start|center|end|between|around|evenly. Horizontal in alayersstack. inset- Padding, as the facet of the same name.
sizesize fill fit(width then height),size fill(width only), orsize width fill/size height fitto name one axis. Each axis is an intent, optionally followed bymin(…)andmax(…):size fill min(size.sm) max(size.lg) fit.width- Names the width axis after
size. height- Names the height axis after
size. fit- Size to content.
fill- Take all the room offered. On the main axis the web keeps the siblings whole (
flex: 1withmin-width: 0); across it, the whole width. weightweight(2)- a share of the leftover room, against the siblings’ weights.fixedfixed(size.lg)- exactly a token’s size, or a length.ratioratio(16:9)- this axis follows the other one by the ratio:size fill ratio(16:9)is a width that fills and a height that keeps 16:9. The key formratio 16 9is read as "the height follows the width" and never written.minmin(size.sm)after an intent - the axis never shrinks below it.maxmax(size.lg)after an intent - the axis never grows past it.positionposition flow(the default) |overlay(out of flow, on top of itslayersstack, placed by the stack’salignanddistribute) |pinned <edge>…(stays at that edge of its scroll container) |bleed <edge>…(stays in flow and cancels the parent’s inset on those edges).pinnedposition pinned block-start- takes one or more logical edges:block-startblock-endinline-startinline-endblockinlineall.bleedposition bleed inline- the same edges; the part extends past the parent’s padding on them. The physical wordstopbottomleftrightare read as the logical edge they name left-to-right, and never written.grid- Reserved.
grid cols 2is read and reported; no target draws a grid yet (proposal 0056 §3.3).
- Stored as
node.layout
part Toolbar: container { layout { stack row; gap space.sm; align center; distribute between; size fill fit } }
Explained on Layout
state
proposal 0025state <state> [ when <prop>=<value> ] { <facet> …; layout { … } }Paint for an interaction state. States come from behaviours, not from pseudo-classes, so the same block works whether a target highlights by hover, by keyboard or by a wheel’s centre band. With when, it applies only for that prop value.
hovered- A pointer is over it.
pressed- Being pressed.
focused- Has focus.
focus-visible- Has focus, and the focus should be shown (keyboard).
active- The browse cursor is on it.
selected- Chosen.
checked- On.
indeterminate- Neither on nor off.
expanded- Its disclosure is open.
open- Its overlay is open.
disabled- Not interactive.
readonly- Shown but not editable.
loading- Waiting for data.
error- Invalid.
success- Validated.
first- The first of its repeated siblings.
last- The last of them.
odd- An odd-numbered one.
even- An even-numbered one.
today- Calendar: today’s date.
outside-month- Calendar: a day of the neighbouring month.
range-start- Calendar: the first day of a selected range.
range-end- Calendar: the last day of a selected range.
in-range- Calendar: inside a selected range.
highlighted- Emphasised by the component (a matched search result).
- Stored as
node.states[]
part Button: container { fill color.accent state hovered { fill color.accent-hover } state hovered when variant = ghost { fill color.accent-subtle } state disabled { opacity 50 } }
Explained on Facets
when
proposal 0032when <predicate> { <facet> …; layout { … } }Paint that applies while a condition holds, with no interaction state involved: the variants of a component. The predicate can combine props, states, contexts and ancestors.
- Stored as
node.states[] with a predicate
part Badge: container { fill color.neutral when tone = danger { fill color.danger } }
Explained on Facets
See also Predicates, state
motion
proposal 0017motion { transition <what> … duration <token> [ easing <token> ] [ delay <token> ] }How the part animates between its states. Each transition names what animates, then its timing as tokens. A transition without a duration is skipped.
A motion line directly inside a component (rather than a part) is read as a note and skipped with a warning.
transition- One animated change.
duration- How long, a duration token. Required.
easing- The curve, an easing token.
delay- How long to wait first, a duration token.
- Stored as
node.motion.transitions[]
part Button: container { motion { transition fill duration fast easing standard } }
Explained on Facets
#Predicates
After present when, when { }, required when, a content rule’s when, and a rule’s where.
Predicates
proposal 0032<leaf> [ <op> <value> ] { and|or <…> } | not <leaf> | not ( … ) | ( … )A condition. A leaf is a prop by name, or state <s>, context <Group>, ancestor <part> <state>. A leaf with no operator means "is set"; not <leaf> means "is not set". and binds tighter than or; parentheses group.
Operators: =, !=, <, <=, >, >=, contains. A value is a bare word, a number, true/false, or a quoted string.
and- Both hold.
or- Either holds.
not- Negation.
state- Leaf: the part is in this interaction state.
context- Leaf: the active context of a context group.
ancestor- Leaf: an ancestor part, by path, is in a state - "style the icon while the row is hovered".
contains- Operator: a list or text contains the value.
- Stored as
node.presence, node.states[].when, prop.requiredWhen, content rules
part icon: icon { present when icon and not loading when ancestor Row hovered or state focused { ink color.accent } }
Explained on Facets
#The library around the components
At the top level.
group <path/to/group> [ "description" ]
At the top level: a category of the component library. Groups nest by path, and a group’s ancestors are implied. The description is prose the docs show for the group.
- Stored as
componentGroups[]
group Forms "Everything that collects input."
group Forms/InputsExplained on The library around the components
See also group
example
proposal 0021example "Name" [ for <Component> ] [ "description" ] { demo { … } part … }A demo scene: a composition shown in the docs and the preview, with no contract of its own. for names the component it demonstrates; its parts are written exactly like a component’s.
- Stored as
examples[]
example "Primary" for Button { part stage: instance { instance Button { label = "Save" } } }
Explained on The library around the components
demo
proposal 0021demo { <name> : <type> [ = <initial> ] … }Inside an example: the scene’s own variables, which its parts can bind and its actions can change. A separate word from state, which in a part means an interaction state.
- Stored as
example.demo
example "Toggle" { demo { open : boolean = false tone : enum(info, danger) = info } }
Explained on The library around the components
docs
proposal 0018docs { site { … } footer { … } page "Title" [ in "Section" ] [ under "Parent" ] { <block> … } }The design system’s documentation site: its header, its footer, and its pages. A page’s blocks are prose or transclusions, and every transclusion names what it shows by name, so the docs stay current as the system changes.
sitesite { name "Acme"; tagline "…"; version "2.1"; search-placeholder "…" }.footerfooter { copyright "…"; link "Label" "https://…" }.copyright- The footer’s copyright line.
link- A footer link: label, then address.
page- A page.
inputs it in a sidebar section,undernests it below another page by title. heading- Prose block. Any prose block may end with
anchor <id>. subheading- Prose block.
paragraph- Prose block.
list- Prose block.
quote- Prose block.
callout- Prose block.
code- Prose block.
divider- A horizontal rule.
imageimage asset <name>- an image from the asset library.component- A live preview of a component.
component-props- The component’s props table.
component-events- The component’s events table.
component-composition- The behaviours the component composes.
component-prop- One prop:
component-prop Button variant. component-event- One event:
component-event Button click. example- A demo scene, by name.
component-group- Every component of a library group.
tokens- A table of the tokens of one type:
tokens color. swatch- Swatches of the tokens of one type.
- Stored as
docs
docs { site { name "Acme"; tagline "One system, every surface" } page "Button" in "Components" { heading "Button" anchor top paragraph "Use one primary action per view." component Button component-props Button } }
Explained on The library around the components
assets { folder <path> | <kind> "name" [ in <folder> ] { <field> <value> … } }The asset library: fonts, images, SVGs, videos and animations, in folders. An asset says where its bytes are: url (beside the file, in a bundle) or data (inside the file, self-contained).
Every asset may also carry mime, size, uploaded and tags.
folder- A folder, by path. Ancestors are implied.
font- A font file:
font-family,font-style,font-weight,formats. image- An image:
width,height,alt. svg- A vector image:
view-box,width,height. video- A video:
width,height,duration-ms,poster. animation- An animation file:
format,duration-ms,loop. url- The bytes are at this address.
data- The bytes are in this
data:URI.
- Stored as
assets
assets { folder brand image "brand-logo" in brand { mime "image/png" width 240 height 64 url "assets/brand-logo.png" } }
Explained on The library around the components
icons { set <prefix> [ "name" ] { … } | glyph <prefix> <name> { … } | custom "name" { … } }The icon library. A part names a glyph by its bare name, which resolves to a curated glyph first, then to the FIRST set’s prefix - so the order of the sets is meaning.
set- An icon set:
provider,license,samples [a, b, c, d]. glyph- A curated glyph of a set:
label, andsvg, its vendored body. custom- A glyph drawn by an asset of the library:
asset,label.
- Stored as
foundations.icons
icons { set lucide "Lucide" { provider lucide; license ISC } glyph lucide check { label "Done" } custom "brand-mark" { asset brand-logo } }
Explained on The library around the components