Components reference

All 44 semantic components: props, when to use them, accessibility, rendering rules and platform mappings.

Generated from packages/spec/components/*.json, the same source the schema, validator and renderer use. Every component also accepts id, component, key, accessibility and visible. For how these map onto the components of 13 design systems, see design-system coverage.

The five shell components (Frame, AppBar, Footer, Outlet, Custom) are the product's frame around its screens. They belong only in a shell document (surface.kind "shell", surface.origin "authored"), written once per product; the validator refuses them anywhere else, and a generator is never shown them. See Generated or authored.

ComponentWebiOSAndroid
FilterPanelSidebar + Sheet (shadcn)List with a filter sheetSide sheet / modal bottom sheet
NavigationSidebar navigation (shadcn Sidebar)TabView or a sidebar on iPadNavigationRail / NavigationDrawer
AppBarPolaris TopBar, Carbon Header, Fluent Nav header, shadcn sidebar headerNavigation bar with toolbar itemsTopAppBar
Customthe host's own componentthe host's own viewthe host's own composable
FooterGOV.UK footer, Polaris FooterHelp, Bootstrap footern/a (settings screen)n/a
FramePolaris Frame, Carbon UI Shell, Fluent App layout, shadcn Sidebar layoutNavigationSplitView / TabView with a NavigationStackScaffold with TopAppBar, NavigationRail or NavigationBar, and content
Outletthe router's outletNavigationStack contentNavHost
Cardshadcn Card (CardHeader/CardTitle/CardContent/CardFooter)GroupBox, or a Button/NavigationLink with card styling in listsCard / ElevatedCard / OutlinedCard (onClick variant when actionable)
ColumnsGOV.UK grid row, Polaris Layout, Carbon Grid, Bootstrap row/colHStack with .layoutPriorityRow with weights
Disclosureshadcn Collapsible (or Accordion for several)DisclosureGroupExpandable ListItem / AnimatedVisibility with a toggle row
Group<div role=group> with flex/grid and semantic spacing tokensVStack / HStack / Grid (ViewThatFits for inline)Column / Row / FlowRow
Panelshadcn Dialog, Sheet, Drawer, Popover.sheet, .popover, NavigationStack pushModalBottomSheet, AlertDialog, DropdownMenu
Section<section> + heading; shadcn has no Section primitive (plain markup with semantic tokens)Section(header:) inside List/Form, or VStack with .accessibilityAddTraits(.isHeader) on the titleColumn with a Text heading marked Modifier.semantics { heading() }
SplitFluent SplitView, Carbon side panel, shadcn ResizableNavigationSplitViewListDetailPaneScaffold
Viewsshadcn TabsPicker(.segmented) switching content, or TabView for top-levelPrimaryTabRow + content
Chartshadcn Chart (Recharts)Swift Charts (Chart)Third-party (e.g. Vico) or Canvas; no built-in M3 chart
Codepre > code with a Copy buttonText with monospaced design in a rounded rectangleText with FontFamily.Monospace in a Surface
CollectionList markup with Card or row template; ScrollArea for long listsList + ForEachLazyColumn + items
DetailList<dl> with semantic tokensLabeledContent rows in a Form/List sectionListItem(headlineContent, trailingContent) rows
Identityshadcn AvatarAsyncImage in a Circle + TextAsyncImage with CircleShape + Text
Media<img> / <video> / <audio> / shadcn AspectRatio; QR on <canvas>AsyncImage / VideoPlayer / CoreImage CIQRCodeGeneratorAsyncImage (Coil) / Media3 PlayerView / ZXing
MetricCard-like block with semantic tokens (no dedicated shadcn primitive)LabeledContent or a VStack; Gauge for bounded valuesColumn with Text styles
Progressshadcn Progress; meter as a native <meter>ProgressView, GaugeLinearProgressIndicator, CircularProgressIndicator
Tableshadcn Table (optionally Data Table with TanStack)Table on regular width; List of rows on compact widthLazyColumn of rows with a header row (no built-in M3 table)
Tagshadcn BadgeText with capsule backgroundAssistChip / Badge
Text<p> with type tokensTextText
TreeRadix Accordion primitives (no shadcn tree)OutlineGroup / List with childrenLazyColumn with expandable rows
Statusshadcn Alert / Skeleton / Sonner toastContentUnavailableView / ProgressView / inline LabelSnackbar / Card with status color / CircularProgressIndicator
Choiceshadcn ToggleGroup / RadioGroup / Select / Combobox (Command + Popover) / CheckboxPicker (.segmented / .inline / .menu) or multi-select ListSegmentedButton / RadioButton rows / ExposedDropdownMenuBox / Checkbox rows
CodeInputshadcn InputOTPTextField with .oneTimeCode content typeBasicTextField with KeyboardType.NumberPassword
ColorInputinput type=color + Radix RadioGroup for swatchesColorPickerCustom (no Material picker)
DateInputshadcn Calendar + Popover (Date Picker)DatePickerDatePicker / DateRangePicker
FileInputshadcn Input type=file with a drop zonefileImporter / PhotosPickerActivityResultContracts.GetContent
Formshadcn Form (react-hook-form + zod)FormColumn of fields + Button (no Form primitive)
RangeInputshadcn SliderSliderSlider
RatingRadix RadioGroup (no shadcn rating)HStack of Image(systemName: star) buttonsRow of IconButton
TextInputshadcn Input / Textarea with Label and FormMessageTextField / TextEditor with .keyboardType and .textContentTypeOutlinedTextField with KeyboardOptions
Toggleshadcn Switch / CheckboxToggleSwitch / Checkbox
Actionshadcn Button (default / secondary / ghost / destructive)Button with .borderedProminent / .bordered / .borderless; role: .destructiveButton / FilledTonalButton / OutlinedButton / TextButton
ActionBarFlex row of shadcn Buttons (DialogFooter-style).toolbar or .safeAreaInset(edge: .bottom)BottomAppBar or Row of Buttons
ActionMenushadcn DropdownMenu, ContextMenu; split as a ButtonGroupMenu, contextMenuDropdownMenu, combinedClickable for context
Comparisonshadcn Table or Cards gridGrid / Table on regular width; List of GroupBox on compactLazyRow of Cards or Column of Cards
Confirmshadcn AlertDialog.confirmationDialog / .alert with role: .destructiveAlertDialog
StepsProgress + step content (no shadcn stepper primitive)NavigationStack pushes or a paged view with a ProgressViewCustom stepper Row + content; LinearProgressIndicator

FilterPanellayout

Filters for a list of results, with the result count.

PropTypeNotes
labeltext or bindingDefaults to 'Filters'
children requiredcomponent idsThe filter inputs (Choice, RangeInput, Toggle, DateInput, TextInput)
results requiredcomponent idThe Collection or Table the filters narrow
resultCountbindingNumber of results with the current filters, from host data
clearactionOptional action that resets the filters on the host

Use when

  • Browsing results people narrow by several attributes
  • More than two filters, or filters that take space (ranges, long lists)

Don't use when

  • One or two quick filters: put a Choice (chips) above the results
  • Filling in information: use Form

Accessibility region (filters) plus the results

  • The result count is announced politely when it changes
  • Each active filter can be removed with a named button ('Remove filter: Desk')

Agents: Set filter inputs by label; read the result count; remove filters by their Remove buttons.

Rendering rules

  • Wide: filters in a sidebar beside the results
  • Compact: a 'Filters · n' button opens a bottom sheet whose action says 'Show n results'
  • Active filters show as removable chips above the results
  • Filters apply as they change (no separate Apply on wide)

A2UI: Column

The product's main navigation.

PropTypeNotes
labeltext or bindingNames the navigation, e.g. 'Main'
items requiredlist of objects
current requiredbindingKey of the current item in host data
kind"main" | "breadcrumb" | "nested" | "toc" | "local"'main' is the product's sections; 'breadcrumb' the ordered trail to here; 'nested' groups that expand; 'toc' the sections of this page (items link to anchors named by their keys); 'local' the sections of one area, as tabs
placement"auto" | "side" | "rail" | "bar" | "drawer"For kind 'main' inside a Frame: where it lives. 'auto' is a side column on wide layouts, a rail on medium and a bottom bar (≤ 5 items) or a drawer on compact; the others fix it

Use when

  • Software with sections people move between (B2B apps, dashboards)
  • Only when the host doesn't already provide navigation

Don't use when

  • Steps of one task: use Steps
  • Sections of one record: use Views
  • A surface embedded in a host that has its own navigation

Accessibility navigation

  • The current item carries aria-current="page"
  • Badges say what they count ('12 overdue')

Agents: Move between sections by activating items by their labels.

Rendering rules

  • Wide: a side navigation with grouped items
  • Compact: a menu button that opens the navigation
  • Badges sit at the end of their item
  • 'breadcrumb' is an ordered trail ending with the current item (aria-current="page"), never behind a menu button
  • 'nested' shows each group as an expandable section; the group holding the current item starts open
  • 'toc' lists the page's sections as anchors, the section in view highlighted
  • 'local' lays the items out as tabs, the current one marked
  • 'placement' fixes the layout a Frame gives the main navigation: side (240px column), rail (80px, icons with labels), bar (bottom, up to 5 items), drawer (behind the AppBar's menu button)

A2UI: Column

AppBarshell

The bar at the top of the product: brand or title, a leading action, search, trailing actions and the account.

PropTypeNotes
title requiredtext or bindingThe product's name, or the current screen's title on compact layouts
brandtext or bindingA media reference for the logo, or initials; rendered before the title
leadingcomponent idAn Action at the start: back, or the menu button the renderer adds itself when the navigation is a drawer
searchcomponent idA TextInput of kind 'search' (or a command palette opener: an Action with a shortcut)
actionscomponent idAn ActionBar at the end: notifications, help, the primary action of the product
accountcomponent idAn Identity (the signed-in person) or an ActionMenu opened from it
variant"standard" | "large" | "compact"'large' puts the title under the bar on its own line on wide screens; 'compact' is 48px for dense tools
stickyboolean

Use when

  • The header region of a Frame
  • A product that needs a persistent place for search, notifications and the account

Don't use when

  • Inside a generated surface: the frame owns the header
  • A page's own title and actions: that is the surface header (surface.title, surface.actions)

Accessibility banner

  • The title is the product's name, not a heading; the screen's h1 stays in main
  • The menu button (when present) names the navigation it opens and reports expanded state
  • Search is a labelled search landmark when present
  • Trailing icon actions have visible tooltips and accessible names

Agents: Finds the product's search and account here; opens the navigation on compact layouts through the menu button.

Rendering rules

  • Height 64px (standard), 48px (compact); large variant adds a 56px title row on wide screens
  • Background color.surface.default with a bottom border; elevation.raised once content scrolls under it
  • Leading action, brand and title at the start; search grows in the middle on wide layouts and becomes an icon on compact; actions and account at the end
  • On compact layouts the title shows the current screen's title when the Frame provides one

A2UI: custom

Customshell

A slot for a component the host implements itself: a logo, a brand moment, a bespoke widget. The document names it and gives it props; the product renders it, and a fallback stands in when it can't.

PropTypeNotes
name requiredstringThe host's name for the component, namespaced: 'brand.logo', 'store.map'
propsobjectWhat the host component takes; values may be bindings
fallback requiredcomponent idWhat renders when the host has no component of that name: a Text, a Media, a Status. Required, so the document stands on its own
labeltext or bindingAn accessible name for the slot when the host component is decorative or complex

Use when

  • The parts of a product that are truly its own: a logo, an illustration system, a map, a chart type the spec doesn't have
  • Only in authored documents: a shell or a screen a person wrote for that product

Don't use when

  • Anything a spec component can express: a Custom is invisible to the verifier beyond its fallback
  • In a generated document: a generator can't know a host's components (the validator refuses it)

Accessibility whatever the host component provides; the fallback carries its own

  • The host component is responsible for its own accessibility; the verifier audits the rendered result
  • A decorative Custom is hidden from assistive tech; a meaningful one has a name

Agents: Reads the host component if it exposes a role and name; otherwise reads the fallback.

Rendering rules

  • The renderer looks the name up in the host's registry (the same one that overrides components); found, it renders it with the resolved props
  • Not found, it renders the fallback and notes the missing name in development
  • Never renders the raw props

A2UI: custom

The bar at the bottom of the product: link groups, the legal line, locale or status.

PropTypeNotes
groupslist of objectsColumns of links, each under a heading
legal requiredtext or bindingThe line at the very bottom: copyright, licence, company details
asidecomponent idSomething at the end of the legal row: a locale Choice, a status Tag, a Text

Use when

  • The footer region of a Frame
  • Public services and marketing-adjacent products where legal and help links belong at the bottom

Don't use when

  • Dense tools where nothing lives below the fold: leave the Frame's footer out
  • Inside a generated surface

Accessibility contentinfo

  • Groups are navigation regions named by their headings
  • Links are links, not buttons, when they leave the current screen
  • The legal line is readable text, not an image

Agents: Reads the legal line and reaches help, privacy and terms by name.

Rendering rules

  • Groups as columns on wide layouts, stacked on compact; headings in type.label.default
  • Background color.surface.subtle with a top border; the legal row in type.body.small, color.text.muted
  • Never sticky

A2UI: custom

Frameshell

The product's frame: the regions around its screens (header, navigation, main, aside, footer, banner), with an outlet where screens and generated surfaces appear.

PropTypeNotes
headercomponent idAn AppBar
navigationcomponent idA Navigation of kind 'main'; its placement decides rail, bar, drawer or side
main requiredcomponent idThe outlet: a component the host replaces with the current screen. Usually an Outlet; may be a Group holding a fixed screen
asidecomponent idA secondary column beside main on wide layouts (help, context, activity)
footercomponent idA Footer
bannercomponent idA Status shown above everything (a phase banner, an outage, a trial ending)
skipTargetbooleanThe renderer adds a skip link to main
width"full" | "contained"'contained' centres main at measure.max × 1.6; 'full' lets dense tools use the whole viewport

Use when

  • The root of a shell document: the product's frame, authored once, that every screen sits in
  • A product whose navigation, header and footer should render in its design system like everything else

Don't use when

  • In a generated document: a surface lives inside a frame and never draws one (the validator refuses it)
  • A dialog or a sheet over a screen: use Panel

Accessibility landmarks: banner (header), navigation, main, complementary (aside), contentinfo (footer)

  • Exactly one main; a skip link to it is the first focusable thing
  • Each landmark is labelled when there is more than one of its kind
  • Regions keep their reading order at every width: banner, header, navigation, main, aside, footer
  • The navigation's current item is marked; the document title follows the current screen

Agents: Reads the landmarks to know where it is; moves between screens through the navigation by name; acts on what is in main.

Rendering rules

  • Wide (≥ 1024px): header on top, navigation at the start edge as a side column or a rail, main and aside as columns, footer below
  • Medium (≥ 640px): navigation becomes a rail; aside stacks below main
  • Compact: navigation becomes a bottom bar (up to 5 items) or a drawer behind a menu button in the header; the footer's groups collapse
  • Region backgrounds use color.surface.default for main and color.surface.subtle for navigation; borders are color.border.default at border.width.default
  • The outlet is where PolyxdSurface documents render: they never repeat the frame's regions

A2UI: custom

Outletshell

Where the current screen renders inside a Frame: the host fills it with a screen document or a generated surface.

PropTypeNotes
labeltext or bindingNames the region for assistive tech when the screen has no title yet
loadingcomponent idWhat shows while a screen is on its way; the renderer's skeleton when absent

Use when

  • The main region of a Frame

Don't use when

  • Anywhere else: an outlet is the frame's, and a document has at most one

Accessibility main

  • The screen's h1 is the first heading inside it
  • Focus moves to the screen's heading when the outlet's content changes on navigation

Agents: Everything it can act on is here; the frame around it is for getting elsewhere.

Rendering rules

  • Takes the main region's width; padding space.inset.comfortable (compact: default)
  • While loading, a skeleton shaped by the coming screen's pattern

A2UI: custom

Cardstructure

One self-contained entity (an account, an order, a place), optionally actionable as a whole.

PropTypeNotes
title requiredtext or bindingName of the entity
subtitletext or binding
mediacomponent idOptional Media component id
badgeobject
childrencomponent ids
actionactionActivating the card as a whole (e.g. open details)
progressobjectProgress through the entity (reading, a course, a goal)

Use when

  • Items in a Collection that each represent an entity
  • A single entity summary in a larger surface

Don't use when

  • Plain grouping: use Group
  • Tabular data with many attributes: use Table

Accessibility article (or link/button when it has an action)

  • Title is the accessible name
  • When actionable, the title is the card's one link; controls inside it (a Toggle, an Action) stay separate targets with their own names

Agents: Activate the card by its title; use controls inside it by their own labels.

Rendering rules

  • If 'action' is set, the whole card opens it; controls in children (e.g. a habit's done Toggle) sit above that target and act on their own
  • Uses surface.raised and radius.default
  • 'progress' renders a progress bar with its label or percentage

A2UI: Card

Columnsstructure

Side-by-side columns that collapse to a stack on compact layouts: a main column with a narrower one beside it, or equal halves.

PropTypeNotes
children requiredcomponent idsOne component per column, in reading order
layout"two-thirds" | "one-third" | "halves" | "thirds" | "sidebar-start" | "sidebar-end"'two-thirds' is a wide first column (GOV.UK's default); 'one-third' the reverse; 'halves' and 'thirds' equal; 'sidebar-*' a fixed 18rem column at that edge
collapse"compact" | "medium" | "never"The width below which the columns stack
align"start" | "center" | "stretch"

Use when

  • A form with help beside it; a record with a summary beside it; a list beside a preview
  • Anywhere a wide screen should use its width without the compact screen paying for it

Don't use when

  • Metrics in a row: use Group with arrangement 'inline'
  • A master–detail pair that keeps both alive: use Split

Accessibility none (layout only)

  • Reading order is the children's order at every width
  • Collapsing never reorders content

Agents: Invisible: reads the children in order.

Rendering rules

  • Gutter space.inline.loose between columns; stacked with space.stack.loose
  • Column widths follow the layout; 'sidebar-*' columns never shrink below 16rem
  • Collapses at the surface's width, not the viewport's

A2UI: Row

Disclosurestructure

Progressive disclosure: secondary content hidden behind a toggle.

PropTypeNotes
summary requiredtext or bindingAlways-visible label describing what is hidden
children requiredcomponent ids
openboolean

Use when

  • Details most people don't need (fees breakdown, advanced options, help text)

Don't use when

  • Content everyone needs to complete the task
  • Primary navigation

Accessibility button (aria-expanded) + region

  • Summary is a button with expanded state
  • Hidden content is not in the tab order while closed

Agents: Expand by the summary text; state is exposed as expanded/collapsed.

Rendering rules

  • Never hide required inputs or the primary action inside a closed Disclosure

A2UI: No direct equivalent; exports as Column (content always shown)

Groupstructure

Visually groups closely related items without a heading (proximity).

PropTypeNotes
children requiredcomponent ids
labeltext or bindingAccessible name for the group when it isn't obvious from its content
arrangement"auto" | "inline" | "grid"Hint only. 'inline' for a few short peers (e.g. metrics); renderers stack on narrow screens.

Use when

  • A few items that belong together (a key figure and its caption, several metrics)

Don't use when

  • The group needs a heading: use Section
  • Choosing between items: use Choice or Comparison

Accessibility group

  • Has an accessible name when it contains interactive items

Agents: Treated as one unit when its label is present.

Rendering rules

  • 'inline' collapses to a stack below the compact breakpoint
  • Gap uses space.stack.default or space.inline.default

A2UI: Column or Row

Panelstructure

Content over the current view: a dialog, a drawer, a bottom sheet or a popover, opened from an action and dismissed to return.

PropTypeNotes
kind"dialog" | "drawer" | "sheet" | "popover"'dialog' centres and blocks; 'drawer' slides from the side for a form or a record; 'sheet' rises from the bottom on phones; 'popover' floats by its opener for a small choice
title requiredtext or binding
children requiredcomponent idsWhat the panel holds
actionscomponent idAn ActionBar in the panel's footer: its primary action and a Cancel
openboolean or bindingBound to host data: true shows the panel; the renderer writes false on dismiss. Open when absent
dismissiblebooleanEscape, the close control and the backdrop dismiss it; false for a panel that must be completed
size"small" | "default" | "large"

Use when

  • A short task on top of the page: edit one thing, pick one thing, see one record
  • Detail the person asked for that shouldn't replace where they are
  • A small set of options next to the control that opened them (popover)

Don't use when

  • Confirming a consequential action: use Confirm, which is a dialog with the right words and order
  • A whole flow of several steps: use Steps on its own surface
  • Passing feedback: use Status

Accessibility dialog (aria-modal for dialog, drawer and sheet) named by the title; popover is a non-modal dialog

  • Focus moves into the panel on open and back to the opener on close
  • Tab stays inside a modal panel; Escape dismisses a dismissible one
  • The page behind a modal panel is inert
  • A sheet can be dismissed by dragging down as well as by the close control

Agents: Opens, reads the content and closes it by name; the footer actions are exposed like any ActionBar.

Rendering rules

  • A backdrop of color.surface.inverse at opacity.overlay for modal kinds
  • dialog: max 560px on desktop, full width with space.inset.default on phones; drawer: 420px from the end edge; sheet: from the bottom with radius.large on the top corners; popover: color.surface.overlay with elevation.overlay and an arrow
  • The title is type.heading.medium with the close control at the end of the header
  • The action bar sits in a footer; on phones it is fixed to the bottom, full width
  • Motion uses motion.duration.default and motion.easing.standard; reduced motion fades instead

A2UI: Modal

Sectionstructure

A titled region of the surface that groups related content under a heading.

PropTypeNotes
title requiredtext or bindingHeading for the section
descriptiontext or bindingOptional one-line explanation under the heading
children requiredcomponent ids

Use when

  • The surface has two or more distinct topics (e.g. 'Recipient' and 'Amount')
  • Content would otherwise exceed one screen and needs signposting

Don't use when

  • Only one topic: put content directly under the root
  • Visual grouping without a heading: use Group

Accessibility region (with heading)

  • Title is rendered as a real heading; nesting depth sets the heading level
  • Title is the region's accessible name

Agents: Navigate by heading; the title names the region.

Rendering rules

  • Heading level follows nesting depth, never chosen by the model
  • Spacing between sections uses space.stack.section

A2UI: No direct equivalent; exports as Column with a Text(variant: h2) first child

Splitstructure

Master and detail side by side: a list that stays while the chosen item's detail shows beside it; on compact layouts the detail replaces the list.

PropTypeNotes
primary requiredcomponent idThe list: a Collection or a Table with selection 'single'
detail requiredcomponent idWhat shows for the selected item; its bindings resolve against the selected item's scope
selected requiredbindingThe selected item's value in host data, shared with the primary's 'selected'
emptycomponent idA Status shown in the detail pane while nothing is selected
ratio"narrow" | "balanced" | "wide"The list's share: about a third, half, or two thirds
resizableboolean

Use when

  • Mail, tickets, messages, files: a list people move through while reading
  • Settings with many sections on wide screens

Don't use when

  • Under about 640px of surface width: it becomes a list then a page, so don't use it for a single record
  • Two unrelated things side by side: use Columns

Accessibility none; the primary and detail keep their own roles

  • Selection in the list moves focus to the detail on compact layouts and announces the item's name
  • A Back control returns to the list on compact layouts
  • The list keeps its scroll position and selection while the detail changes

Agents: Selects an item in the primary by name and reads the detail; on compact layouts it goes back to choose another.

Rendering rules

  • Wide: two panes with a border between; the list scrolls independently
  • Compact: the list, then the detail as a page with a back control when an item is selected
  • Selection state in the list uses color.selection.*
  • Resizable splits keep the handle at size.target.min wide with a visible focus ring

A2UI: custom

Viewsstructure

Switch between alternative views of the same subject (tabs).

PropTypeNotes
views requiredlist of objects
selectedbindingKey of the selected view in host data
variant"tabs" | "segmented"'tabs' for sections of a record; 'segmented' for switching how the same thing is shown

Use when

  • 2–6 peer views of the same data (Overview / Transactions / Settings)

Don't use when

  • Sequential steps: use Steps
  • Filtering one list: use Choice

Accessibility tablist / tab / tabpanel

  • Each tab has a visible label
  • Arrow keys move between tabs

Agents: Select a view by its label.

Rendering rules

  • More than 4 views on compact screens become a menu or scrollable tabs
  • Counts sit beside their labels and are part of the tab's accessible name

A2UI: Tabs

Chartcontent

A visual summary of data, always paired with a text summary.

PropTypeNotes
intent required"trend" | "comparison" | "composition" | "distribution" | "relationship" | "flow" | "hierarchy" | "matrix" | "range"What the chart should communicate; the renderer picks the chart type. 'relationship' between two measures; 'flow' of amounts from each x value into the series; 'hierarchy' of parts by size; 'matrix' of x values against series; 'range' from the first series to the second
data requiredbindingArray of data points in host data
title requiredtext or binding
summary requiredtext or bindingText alternative stating the takeaway (required)
x requiredobject
series requiredlist of objects

Use when

  • A trend, comparison, share or spread matters more than exact values

Don't use when

  • Exact values matter most: use Table or Metric
  • A single number: use Metric

Accessibility img (figure) with the summary as description, plus a data-table alternative

  • 'summary' states the takeaway in words
  • Series are distinguishable without color (labels, markers)
  • The underlying data is available as a table

Agents: Reads the summary, and the data through the table alternative.

Rendering rules

  • trend → line, comparison → bar, composition → stacked bar (pie only for ≤ 4 parts), distribution → histogram
  • relationship → scatter (x is a measure too), flow → stacked flows from each x value to each series, hierarchy → treemap of the first series, matrix → heatmap of x values by series, range → bars from the first series to the second
  • Series colors use color.data.categorical.N in order; a matrix shades one color by value and prints the value in each cell

A2UI: No equivalent in the Basic catalog; exports as Text(summary) + List

Codecontent

Code, a command or preformatted text, shown as written and copyable.

PropTypeNotes
text requiredtext or bindingThe code itself, usually bound to host data (an API key, a command, a snippet)
labeltext or bindingWhat it is, shown above: 'Install', 'Your API key'
languagestringA language name for highlighting, when the renderer has it: 'bash', 'json', 'ts'
copyablebooleanA Copy control beside it
wrapbooleanWrap long lines instead of scrolling sideways
secretboolean or bindingMasked until revealed: a key shown once

Use when

  • A command to run, a snippet to paste, an identifier to copy
  • Structured text whose spacing matters

Don't use when

  • Prose: use Text
  • Something the person types: use TextInput

Accessibility region named by the label, holding a code element; the copy control is a button named 'Copy <label>'

  • Text is real text: selectable and read by screen readers line by line
  • Copying is announced ('Copied')
  • A secret is masked with the same length, with a 'Show' control

Agents: Reads the text verbatim; can activate Copy.

Rendering rules

  • type.mono at type.body.small on color.surface.subtle, with radius.control
  • Overflow scrolls sideways unless wrap is set; never clipped
  • The copy control sits in the top-right corner and says 'Copied' for two seconds after use

A2UI: Text

Collectioncontent

A list of items from host data, each rendered with the same template.

PropTypeNotes
items required{ path, componentId }
label requiredtext or bindingWhat the list contains, e.g. 'Recent payments'
emptycomponent idStatus component shown when there are no items
selection"none" | "single" | "multiple"
selectedbindingSelected item value(s) in host data when selection is not 'none'
layout"auto" | "list" | "grid" | "timeline" | "carousel" | "calendar"'grid' for visual items (products, books); 'list' for rows; 'timeline' for dated activity; 'carousel' for a row people page through; 'calendar' places items on a month grid by 'datePath'; 'auto' lets the renderer choose from the item template
datePathJSON PointerFor 'calendar': relative path in each item to the ISO date that places it
pageobjectPaging state, owned by the host
bulkActionscomponent idActionBar shown while items are selected (selection 'multiple')
reorderablebooleanPeople can drag items, or move them with the keyboard, into a new order
orderbindingItem values (ids) in the order people put them, written when reorderable

Use when

  • Browsing a set of similar entities
  • Search results

Don't use when

  • Attributes compared across items: use Table or Comparison
  • Choosing an option in a form: use Choice

Accessibility list / listitem (listbox when selectable)

  • Announces the item count
  • An empty state is provided

Agents: Items are enumerated with their titles; each item exposes its own actions.

Rendering rules

  • Long lists are virtualized by the renderer
  • Items keep their order from host data
  • grid: 2 columns on phones, more as width allows; list: one item per row
  • auto: grid when the item template is a Card with media, otherwise list
  • 'timeline' marks each item on a line, newest first, for activity feeds
  • 'carousel' scrolls horizontally with snap points, Previous and Next buttons and an 'N of M' readout; every item stays reachable by keyboard
  • 'calendar' is a month grid with the items on their days; Previous and Next move a month at a time
  • Paging shows items per page, the range and the total, as a Table does
  • Selection shows the bulk-action bar, naming how many items are selected, while any are
  • reorderable: a drag handle per item, plus Move up / Move down buttons; the new order is written to 'order'

A2UI: List (templated children)

DetailListcontent

Label/value pairs describing one thing (a summary, a receipt, a review step).

PropTypeNotes
items requiredlist of objects
titletext or binding
variant"default" | "receipt"'receipt' for money: values right-aligned in tabular figures, with an optional total row
layout"rows" | "grid"'grid' packs many short fields into columns (record pages); 'rows' keeps one per line
rowActionactionOffered per row as a 'Change' link named after the row (GOV.UK summary list); the row's key is sent as 'key' with the context

Use when

  • Reviewing before submitting
  • Showing the attributes of one entity
  • Receipts
  • Fees, prices and totals before someone commits (variant 'receipt')

Don't use when

  • Many entities with the same attributes: use Table
  • Comparing entities: use Comparison

Accessibility list of term/definition pairs (dl)

  • Label and value are programmatically associated

Agents: Read each label with its value.

Rendering rules

  • Keeps the item order stable across generations (keys are remembered)
  • receipt: values right-aligned in tabular figures, the total row emphasised; people read amounts from the right
  • 'grid' lays fields out in columns by width, label above value
  • rowAction: each row ends with a 'Change' link whose accessible name includes the row's label; the total row has none

A2UI: Column of Row(Text, Text)

Identitycontent

A person, team or organisation: picture, name and details, or several of them together.

PropTypeNotes
name requiredtext or bindingAlways bound to host data: a name is never invented
detailtext or bindingOne line under the name: a role, an email, a team, a status
imagetext or bindingA media reference from host data, resolved by the host as Media's is; initials from the name are shown without one
kind"person" | "team" | "organization"A person's picture is round; a team's or organisation's is square
size"small" | "default" | "large"
actionactionActivating the identity as a whole, e.g. open the person's record
groupobjectSeveral identities as one element ('Rhea, Tom and 3 others'). name is then the group's accessible summary

Use when

  • Who something belongs to, was sent by or is assigned to
  • The recipient on a payment, the owner on a record, the members on a team
  • A list of people where the face helps recognition

Don't use when

  • Choosing a person from a list: use Choice with avatarPath
  • A person's full record: use Card or DetailList

Accessibility group named by the name; the picture is decorative and the name is text

  • The name is real text, never only an image or initials
  • A group's accessible name lists the first names and how many more
  • With an action, the whole element is one button or link named by the name

Agents: Reads the name and detail; a group exposes every member's name.

Rendering rules

  • Initials come from the name's first letters, on a neutral surface with color.text.default; a pack may derive a stable colour from the name
  • Sizes: small 24px, default 40px, large 64px; the name uses type.body.default or type.heading.small for large
  • A group overlaps pictures by a quarter, with a '+N' tag for the rest
  • Images are never stretched; missing images fall back to initials, never to a broken image

A2UI: Row of Image + Text

Mediacontent

An image, video, audio clip, gallery or QR code supplied by the host.

PropTypeNotes
srcbindingImage, video or audio reference in host data; generated UI never contains URLs
alttext or bindingRequired unless decorative. For a gallery it names the set; for a QR code it says what the code opens
decorativeboolean
aspect"square" | "landscape" | "portrait" | "auto"
kind"image" | "video" | "audio" | "gallery" | "qr"'video' and 'audio' play with native controls; 'gallery' is several images from 'items'; 'qr' encodes 'value' as a QR code
postertext or bindingFor 'video': media reference for the frame shown before play
transcripttext or bindingFor 'video' and 'audio': the words, offered under the player
itemsbindingFor 'gallery': array of images in host data
imagePathJSON PointerFor 'gallery': relative path in each item to its image reference
altPathJSON PointerFor 'gallery': relative path in each item to its alt text
valuetext or bindingFor 'qr': the text encoded, e.g. a payment link from host data

Use when

  • Photos or illustrations that help identify something (a product, a place, a person)
  • A recording people play, or a code they scan

Don't use when

  • Decoration with no information
  • Icons for actions (renderer supplies those)

Accessibility img (video / audio players, list for a gallery)

  • Has alt text unless decorative (then hidden from assistive technology)
  • Video and audio have native controls and offer a transcript
  • A QR code's alt says what scanning it does

Agents: Reads the alt text; a gallery's images by their own alt text; a QR code's value.

Rendering rules

  • Images never convey information that is not also in text
  • 'video' shows 'poster' until played; 'audio' is a compact player; both put 'transcript' under a disclosure
  • 'gallery' is a grid of the items' images, each with its own alt text
  • 'qr' is drawn on a canvas at a size that scans from a phone, with the alt as its accessible name

A2UI: Image (video, audio and gallery export as Image + Text; a QR code as Text of its value)

Metriccontent

A key figure with a label, and optionally its change.

PropTypeNotes
label requiredtext or binding
value requiredbindingAlways bound to host data
formatformat
changeobject
captiontext or binding

Use when

  • One to four headline numbers the user asked about

Don't use when

  • Many numbers: use Table or DetailList
  • Trends over time: use Chart

Accessibility group (label + value)

  • Change direction is conveyed in text as well as color
  • Screen readers read label, value and change as one sentence

Agents: Read label and value.

Rendering rules

  • Value uses type.numeric.display
  • Change uses color.data.positive / negative according to 'favorable'

A2UI: Column of Text

Progresscontent

How far along something is, or how much of a bounded amount is used: a bar, a ring or a meter.

PropTypeNotes
label requiredtext or bindingWhat is being measured: 'Storage used', 'Upload', 'Goal'
value requirednumber or bindingBound to host data. A fraction from 0 to 1, or an amount when max is given
maxnumber or bindingThe whole, when value is an amount rather than a fraction: 200 for '180 of 200 GB'
kind"bar" | "ring" | "meter"'bar' and 'ring' show progress towards done; 'meter' shows a measured amount within bounds, with tone by threshold
captiontext or bindingText beside the readout: '180 of 200 GB', '3 days left'. The readout itself is derived from value
formatformatHow the readout is shown; percent without it
tonetoneFixed tone; a meter without one takes warning past thresholds.warning and danger past thresholds.danger
thresholdsobjectFractions at which a meter changes tone
indeterminateboolean or bindingThe task is running and how far along isn't known

Use when

  • A task that takes time, with a known share done
  • How much of a quota, budget or capacity is used
  • Progress towards a goal (pages read, steps walked)

Don't use when

  • A number the person came to see: use Metric
  • Steps of a task the person moves through: use Steps
  • A short wait with nothing to measure: Status 'loading'

Accessibility progressbar (bar, ring) or meter, named by the label, with aria-valuenow, aria-valuemin, aria-valuemax and aria-valuetext

  • The readout is real text next to the graphic, never only the fill
  • A meter's tone is also said in text ('nearly full'), not only shown by colour
  • Indeterminate progress has no value attributes and is announced as busy

Agents: Reads label, value and max as text.

Rendering rules

  • The track uses color.surface.subtle; the fill uses color.action.primary.background, or color.status.<tone>.emphasis for a toned meter
  • Height is size.control.small / 3 for a bar; a ring is size.control.default across
  • Readout in tabular figures, type.body.small, after the label
  • The bar's length means the fraction: never used for an amount with no bound

A2UI: Text

Tablecontent

Tabular data: many items sharing the same attributes.

PropTypeNotes
rows requiredbindingArray of row objects in host data
caption requiredtext or bindingWhat the table shows (required for accessibility)
columns requiredlist of objects
rowActionactionActivated per row; context bindings resolve against the row
emptycomponent idStatus component shown when there are no rows
sortobjectSorting state, owned by the host
selection"none" | "multiple"'multiple' adds a checkbox column and a select-all
selectedbindingArray of selected row values in host data
rowValuePathJSON PointerRelative path to each row's id, used for selection
bulkActionscomponent idActionBar shown instead of the toolbar while rows are selected
rowActionscomponent idActionBar offered per row, in a menu named after the row
expandablebooleanRows open to show 'detail' beneath them
detailcomponent idComponent rendered under an expanded row; relative paths inside it resolve against the row
toolbarcomponent idActionBar above the table (e.g. New, Import, Export)
searchcomponent idTextInput (kind 'search') above the table
viewslist of objectsSaved views (All, Mine, Past due…), shown as tabs with counts
viewbindingKey of the selected saved view in host data
pageobjectPaging state, owned by the host

Use when

  • Scanning or comparing many rows by several attributes
  • Records people scan, sort, select and act on in bulk (B2B lists)

Don't use when

  • One entity: use DetailList
  • A few entities where the user must choose: use Comparison

Accessibility table with caption and column headers

  • Has a caption
  • Column headers are real header cells
  • Numeric columns are right-aligned by format
  • Sortable headers carry aria-sort and say what sorting does
  • The select-all checkbox is mixed when some rows are selected
  • The bulk-action bar names how many rows are selected, announced politely
  • Each row's action menu is named after its row

Agents: Read by row and column headers; rows with rowAction are activatable. Sort by activating a column header; select rows by their checkboxes; act in bulk from the bar that appears.

Rendering rules

  • On compact screens, rows become stacked cards with label/value pairs
  • Alignment follows the column format, never chosen by the model
  • Numbers and currency are right-aligned with tabular figures; 'status' renders as a tag using 'tones'
  • On compact surfaces the table becomes a list of rows: the entity, the key fields in one line, and the status
  • Selection replaces the toolbar with the bulk-action bar while rows are selected
  • Paging shows rows per page, the range and the total
  • expandable: each row starts with a toggle (aria-expanded) named after the row; the open row's 'detail' spans the table beneath it

A2UI: No direct equivalent; exports as List of Row

Tagcontent

A short label, status or count attached to something else.

PropTypeNotes
label requiredtext or bindingThe word or two it shows: 'Past due', 'Beta', 'Design'
kind"label" | "status" | "count"'status' is the state of the thing it sits on and is coloured by tone; 'count' is a number, with the label as its accessible name
tonetoneMeaning, not decoration: a status tag's tone says whether the state is fine, a warning or a problem
countnumber or bindingFor kind 'count': the number, bound to host data
removeactionPresent when the person can take the tag off (a filter chip, a chosen recipient): the capability that removes it

Use when

  • The state of a record, next to its name: 'Past due', 'Draft', 'Live'
  • A category or label a thing carries
  • How many of something, on a navigation item or a section heading
  • Chosen items a person can take off again

Don't use when

  • A whole sentence of feedback: use Status
  • Something the person switches on or off: use Toggle
  • A metric the person came for: use Metric

Accessibility text; for 'count', the label is the accessible name of the number; for a removable tag, a button named 'Remove <label>'

  • Tone is conveyed by the label, never only by colour
  • A count reads as '<label>: <count>' to a screen reader
  • The remove control is at least size.target.min and named for what it removes

Agents: Reads label, tone and count; can activate the remove control by its name.

Rendering rules

  • status uses color.status.<tone>.background and .foreground; label and count use neutral tokens
  • count is set in tabular figures
  • A tag never wraps: long labels are truncated with the full text on hover and in the accessible name
  • Fits inline with text and in a Card header; radius.small unless the pack sets a pill

A2UI: Text

Textcontent

A run of text.

PropTypeNotes
text requiredtext or binding
variant"body" | "supporting" | "caption" | "rich" | "list" | "quote"'rich' allows **bold**, *italic*, `code` and [links](href) in the text; 'list' is a bulleted or numbered list of 'items'; 'quote' is a quotation with an optional 'cite'
formatformatOnly when 'text' is bound to a non-string value
itemsbindingFor 'list': array in host data, one entry per item; 'text' introduces the list
itemPathJSON PointerFor 'list': relative path in each entry to the text shown, when the entries are objects
orderedbooleanFor 'list': numbered rather than bulleted
citetext or bindingFor 'quote': who or what is quoted

Use when

  • Explanations, instructions, messages

Don't use when

  • Headings: use Section title
  • Label/value pairs: use DetailList
  • Key figures: use Metric

Accessibility text

  • Body text is at least 16px (type.body.default)
  • Line length is capped by measure.max

Agents: Read as text.

Rendering rules

  • 'supporting' uses color.text.muted
  • No inline styling; emphasis comes from structure
  • 'rich' renders only the four markup forms, as real elements; anything else, including HTML, is shown as typed, and only http, https, mailto and tel links are live
  • 'list' renders a ul or ol; entries are shown as text, or by 'itemPath' when they are objects
  • 'quote' is a blockquote, the cite on its own line after it
  • format 'color' shows a swatch of the value beside it; 'bytes' shows a size like 1.2 MB

A2UI: Text

Treecontent

A hierarchy people expand, browse and pick from: folders, an org chart, nested categories.

PropTypeNotes
label requiredtext or bindingWhat the tree holds, e.g. 'Folders'
items requiredbindingThe top-level nodes in host data: a list
labelPath requiredJSON PointerRelative to each node: the text shown
childrenPath requiredJSON PointerRelative to each node: its list of child nodes, absent or empty for a leaf
valuePathJSON PointerRelative to each node: what selection writes; the label when absent
detailPathJSON PointerRelative to each node: a count or note shown after the label
selection"none" | "single" | "multiple"
selectedbindingSelected node value(s) in host data when selection is not 'none'
expandedbindingValues of the nodes shown open; the first level is open without it
actionactionActivating a node, e.g. open that folder; context may bind to the node's fields

Use when

  • Things that contain things: folders and files, an organisation, nested categories
  • Picking a place in a hierarchy (move to folder, choose a category)

Don't use when

  • A flat list, however long: use Collection or Table
  • Nested navigation of the product itself: use Navigation
  • Progressive disclosure of one section: use Disclosure

Accessibility tree with treeitem nodes; aria-expanded on nodes with children, aria-selected when selectable

  • Arrow keys move and expand; Home and End jump; typing jumps to a label
  • Level and position are exposed (aria-level, aria-setsize, aria-posinset)
  • Expanded state is announced; selection is announced

Agents: Reads every node by label and level; expands a node by name and selects or activates one by name.

Rendering rules

  • Indent per level uses space.inline.default; the expander is a chevron at size.target.min
  • Leaves have no expander and align with siblings' labels
  • Selection uses color.selection.background; the focused node shows color.border.focus
  • Beyond 200 nodes the renderer virtualises rows

A2UI: Nested Column of Text

Statusfeedback

Feedback about state: info, success, warning, error, empty or loading.

PropTypeNotes
kind required"info" | "success" | "warning" | "error" | "empty" | "loading" | "undo"
title requiredtext or binding
messagetext or binding
actioncomponent idOptional Action (or ActionBar for a primary and a secondary) to recover or continue, e.g. 'Try again'; for 'undo', the Undo action
icon"lock" | "trash" | "clock" | "tag" | "info" | "alert" | "mail" | "shield" | "search" | "book" | "inbox" | "check"Optional icon for empty states; the renderer picks one by kind otherwise
variant"default" | "inline"'inline' is a notice inside a page (a warning above a record) rather than a block of its own

Use when

  • Results of an action
  • Empty collections
  • Errors with a way to recover
  • Loading states
  • 'undo': after a reversible action ran, say what happened and offer Undo instead of asking first

Don't use when

  • Validation errors on a field: inputs show their own errors
  • Confirmation before acting: use Confirm

Accessibility status or alert (live region)

  • success/info/loading are polite live regions; error is assertive
  • Meaning is in text, not only color or icon

Agents: Reads the title and message; the recovery action is exposed.

Rendering rules

  • error and warning use color.status.* tokens and an icon
  • empty states explain why and what to do next
  • loading shows a skeleton when layout is known, otherwise a progress indicator
  • 'undo' renders as a snackbar at the bottom of the surface, announced politely, with the Undo action
  • Empty states may carry an ActionBar: one primary and one secondary action
  • 'inline' renders a bordered notice with its action on the right

A2UI: Text + Icon

Choiceinput

Pick one or several options from a known set. The renderer chooses the control.

PropTypeNotes
label requiredtext or binding
options requiredoptions (list or from data)
value requiredbindingTwo-way binding into host data
mode"single" | "multiple"
helptext or binding
requiredboolean

Use when

  • Any choice from a known set of options

Don't use when

  • On/off setting: use Toggle
  • Picking between rich entities by comparing attributes: use Comparison

Accessibility radiogroup / group of checkboxes / listbox / combobox (depends on rendering)

  • Visible group label
  • Every option has a text label

Agents: Select options by label.

Rendering rules

  • single, 2–4 short options → segmented control or radios
  • single, 5–10 → radios (or select on compact screens)
  • single, > 10 → searchable select
  • multiple, ≤ 10 → checkboxes; > 10 → searchable multi-select
  • Option order comes from host data or remembers the last order used

A2UI: ChoicePicker

CodeInputinput

A one-time code or PIN, typed into one box per character.

PropTypeNotes
label requiredtext or binding'Enter the code we emailed you'
value requiredbindingThe code so far in host data, as a string
lengthinteger
kind"numeric" | "alphanumeric"
helptext or bindingWhere the code came from and how long it lasts
requiredboolean or binding
actionactionRuns when every character is in, so the person needn't press a button; context binds to value

Use when

  • A verification code from email or SMS
  • A PIN or a short recovery code

Don't use when

  • A password: the host's own sign-in flow, never a generated screen
  • Any text longer than twelve characters: use TextInput

Accessibility a group named by the label; one text input per character, each named 'Digit N of M'

  • Typing moves focus forward; Backspace moves it back; pasting the whole code fills every box
  • The numeric kind opens the numeric keyboard and accepts autofill of one-time codes
  • Errors are said against the group, not one box

Agents: Reads the label and length; enters the code.

Rendering rules

  • Boxes are size.control.large squares with radius.control, type.heading.small, centred, in type.mono
  • The active box shows color.border.focus; a filled box shows color.border.strong
  • Boxes are grouped in threes or fours by a wider gap past six characters

A2UI: Custom (no Basic equivalent)

ColorInputinput

Pick a colour: from swatches the host offers, or any colour.

PropTypeNotes
label requiredtext or binding
value requiredbindingThe colour in host data, as CSS text in the chosen format
swatchesoptions (list or from data)Named colours to pick from (value is the colour, label its name); without them the full picker shows
format"hex" | "rgb" | "hsl"
alphabooleanLet the person set opacity too
helptext or binding
requiredboolean or binding

Use when

  • A colour for a label, a tag, a calendar, a theme
  • Choosing from a set of brand colours

Don't use when

  • A choice that happens to be shown as colours (a plan, a size): use Choice

Accessibility swatches are a radiogroup of radios named by their labels; the free picker is a native color input plus a text field for the value

  • Every swatch has a name; colour alone is never the only identification
  • The value is editable as text, so it can be typed and read
  • The chosen colour is shown beside its text value

Agents: Reads the swatch names; picks one by name or types a value.

Rendering rules

  • Swatches are size.control.default squares with radius.control and a 1px color.border.default ring; the chosen one shows color.border.focus
  • The free picker is the platform's, with the text value beside it in type.mono

A2UI: Custom (no Basic equivalent)

DateInputinput

A date, time, date-time or date range.

PropTypeNotes
label requiredtext or binding
value requiredbindingISO 8601 value(s) in host data
kind"date" | "time" | "datetime" | "dateRange" | "month" | "year"'month' stores YYYY-MM and 'year' stores YYYY
multiplebooleanSeveral dates rather than one; the value is a list
mintext or binding
maxtext or binding
helptext or binding
requiredboolean

Use when

  • Any date or time entry

Don't use when

  • Relative choices like 'This month / Last month': use Choice

Accessibility group of spinbuttons or a date picker dialog

  • Typing the date is always possible, not only picking from a calendar

Agents: Fill by label with an ISO date.

Rendering rules

  • Memorable dates (birthdays) use separate day/month/year fields; near dates use a calendar
  • 'month' and 'year' take only that part; the year field is typed, four digits
  • multiple: each chosen date becomes a chip with a remove control; the field adds another

A2UI: DateTimeInput

FileInputinput

Choose or drop files to attach or upload.

PropTypeNotes
label requiredtext or binding
value requiredbindingThe chosen files in host data: a list of { name, size, type, ref }, written by the renderer; the host uploads them
acceptlist of stringAllowed types as extensions or MIME types: ['.pdf', 'image/*']
multipleboolean
maxSizeintegerLargest file, in bytes; the renderer refuses larger ones with a message
helptext or bindingWhat to attach and why; the accepted types and size are said by the renderer
requiredboolean or binding

Use when

  • Attaching a document, a receipt, a photo
  • Importing a file the product reads

Don't use when

  • Taking a photo with the camera: the host's own flow
  • Pasting text: use TextInput

Accessibility a native file input, labelled; the drop zone is a large target for the same input

  • Keyboard opens the chooser; drag-and-drop is an addition, never the only way
  • Chosen files are listed as text with a 'Remove <name>' button each
  • Type and size limits are said before choosing and in any refusal

Agents: Reads the label and limits; attaches files through the host.

Rendering rules

  • A dashed drop zone on color.surface.subtle with radius.control, the chooser control inside it
  • Each chosen file shows name, size and a remove control; a progress bar while the host uploads
  • Refusals use color.status.danger text under the zone

A2UI: Custom (no Basic equivalent)

Forminput

Collects inputs and submits them together.

PropTypeNotes
children requiredcomponent ids
submit required{ label, action }
cancel{ label, action }Optional; defaults to ui.dismiss when omitted and the surface is dismissible
asidecomponent idOptional summary (DetailList, Card or Group) kept beside the form, e.g. the running total
layout"stacked" | "horizontal"'horizontal' puts label and help on the left and the control on the right (settings pages), on wide surfaces

Use when

  • Any set of inputs that are submitted together

Don't use when

  • Settings that apply immediately: use Toggles with actions
  • Several distinct stages: use Steps

Accessibility form

  • Submit is a real submit button
  • On submit errors, focus moves to an error summary that links to each field

Agents: Fill fields by label, then activate the submit button by its label.

Rendering rules

  • One column; labels above fields
  • Submit is the primary action; cancel is secondary
  • Submit context is built from the form's input bindings
  • 'horizontal' becomes stacked on compact surfaces
  • 'aside' sits beside the form on wide surfaces; on compact ones it comes first, before the fields, so people read what they are agreeing to

A2UI: Column + Button

RangeInputinput

A number, or a range between two numbers, within known bounds.

PropTypeNotes
label requiredtext or binding
value requiredbindingNumber in host data, or [min, max] when mode is 'range'
min requirednumber
max requirednumber
stepnumber
formatformat
mode"single" | "range"'range' picks a lower and upper bound; value is then [min, max]

Use when

  • Approximate values within a range (budget cap, volume)
  • A price or date range for filtering (mode 'range')

Don't use when

  • Exact values: use TextInput with kind 'number' or 'currency'

Accessibility slider

  • Current value is shown as text
  • Keyboard arrows change the value by step

Agents: Set the value directly by label.

Rendering rules

  • Shows min, max and the current formatted value
  • mode 'range' shows two thumbs and min/max fields that stay in sync

A2UI: Slider

Ratinginput

A score out of N: given by the person, or shown as others gave it.

PropTypeNotes
label requiredtext or bindingWhat is rated: 'Your rating', 'Average rating'
value requiredbindingThe score in host data; written when the person can rate
maxinteger
readOnlyboolean or bindingShow a score rather than take one
countnumber or bindingHow many ratings the score is from, shown after it: '4.6 (212)'
helptext or binding
requiredboolean or binding
actionactionRuns when a rating is given, with context bound to value

Use when

  • Asking how something went, out of five
  • Showing a product's or place's rating with the count behind it

Don't use when

  • A number within bounds that isn't a score: use RangeInput
  • Yes or no: use Toggle or Choice

Accessibility radiogroup of radios named '1 star' to 'N stars' when it can be given; an image named '4.6 out of 5' when read-only

  • Every star is a real control at size.target.min when the person can rate
  • The current value is announced; half values are said as such
  • Read-only ratings carry the score as text, not only as filled shapes

Agents: Reads the score and the count; sets a score by choosing '<n> stars'.

Rendering rules

  • Filled shapes use color.status.warning.emphasis; empty ones use color.border.default
  • The readout ('4.6') is shown after the shapes in tabular figures, with the count in color.text.muted
  • A rating that can be given shows the label above, like every input

A2UI: Row of Icon

TextInputinput

A single text-like value: text, number, email, phone, currency, search or long text.

PropTypeNotes
label requiredtext or binding
value requiredbindingTwo-way binding into host data
kind"text" | "multiline" | "number" | "currency" | "email" | "phone" | "url" | "search" | "suggestions" | "richtext" | "tags" | "mentions" | "code" | "masked" | "inline"'suggestions' offers completions from 'options' while leaving any text allowed; 'richtext' is short formatted text (bold, italic, lists) stored as markdown-ish text; 'tags' is a list of short values entered one at a time; 'mentions' offers 'options' after an @; 'code' is monospace with no autocorrection; 'masked' follows 'mask'; 'inline' reads as text until it is clicked
optionsoptions (list or from data)For 'suggestions' and 'mentions': the completions offered
maskstringFor 'masked': # for a digit, A for a letter, * for either, anything else typed for you, e.g. '#### #### #### ####'
currencytext or bindingISO 4217 code when kind is 'currency'
helptext or bindingHint shown below the label (not a placeholder)
requiredboolean
validationobject
autocompletestringHTML autocomplete token hint (e.g. 'email', 'postal-code')
placeholdertext or bindingOnly for kind 'search', shown inside the field. Never a substitute for the label.
size"default" | "hero"'hero' for the one number a surface is about (an amount to send): large and centred

Use when

  • Free-form values the user types

Don't use when

  • A value from a known set: use Choice
  • Dates: use DateInput
  • Secrets (passwords, card numbers): not generated; hosts provide their own secure flows

Accessibility textbox / searchbox / spinbutton

  • Visible label, never placeholder-only
  • Help and errors are associated with the field
  • Kind sets the right keyboard and autocomplete

Agents: Fill by label.

Rendering rules

  • Width suggests expected length
  • Errors appear after the user leaves the field or submits, not while typing
  • kind 'search' renders as a pill search field with an icon; the label stays as its accessible name
  • size 'hero' renders a large centred amount with the currency symbol dimmed
  • 'suggestions' and 'mentions' are comboboxes: the list opens as you type, arrow keys move through it, Enter takes an option, Escape closes it
  • 'richtext' is an editable area with Bold, Italic and List controls; the value is text with **bold**, *italic* and '- ' items
  • 'tags' shows each value as a chip with a remove control; Enter or a comma adds what was typed, Backspace in an empty field removes the last chip; the value is a list of strings
  • 'code' uses type.numeric (monospace) and turns off autocorrect, autocapitalize and spellcheck
  • 'masked' fills the mask's literal characters as you type and stores the text as shown
  • 'inline' renders the value as text with an Edit control; Enter saves, Escape restores the previous value

A2UI: TextField

Toggleinput

An on/off setting.

PropTypeNotes
label requiredtext or binding
value requiredbindingBoolean in host data
descriptiontext or binding
actionactionSet when the change applies immediately (a setting); omit inside a Form

Use when

  • Settings that take effect immediately
  • A single yes/no inside a form

Don't use when

  • Choosing between named options: use Choice

Accessibility switch (immediate) / checkbox (in a form)

  • Label says what 'on' means

Agents: Toggle by label; state is exposed as on/off.

Rendering rules

  • With 'action' it renders as a switch; inside a Form without action, as a checkbox

A2UI: CheckBox

Actionaction

A button that triggers a host capability.

PropTypeNotes
label requiredtext or bindingVerb-first label saying what happens ('Send £20', not 'OK')
action requiredaction
emphasis"primary" | "secondary" | "tertiary"
tone"default" | "danger"
disabledboolean or binding
descriptiontext or bindingA second line under the label saying what the action does, for menu-like actions
copytext or bindingFor the renderer action ui.copy: the text put on the clipboard; otherwise the action context's 'text' is copied
shortcutstringKeyboard shortcut that triggers the action while the surface has focus, e.g. "mod+enter" or "shift+d". 'mod' is Command on Apple platforms and Control elsewhere. The renderer shows the hint beside the label and never binds it outside the surface.

Use when

  • Anything the user can do that isn't typing or choosing

Don't use when

  • Navigating between views: use Views
  • Confirming something destructive: wrap in Confirm

Accessibility button

  • Label describes the outcome
  • Target at least size.target.min
  • Disabled actions explain why nearby
  • A shortcut is a hint, never the only way: the button itself stays clickable and focusable

Agents: Activate by label.

Rendering rules

  • At most one primary action visible at a time
  • danger tone uses color.action.danger.*
  • 'description' sits under the label in type.body.small, muted; the button's accessible description
  • ui.copy is handled by the renderer: it copies 'copy' (or the context's 'text') and announces 'Copied' politely
  • 'shortcut' shows as a keyboard hint (kbd) beside the label, with mod written as ⌘ or Ctrl for the platform; it fires only while focus is inside the surface, never over the host page, and never on a disabled action

A2UI: Button

ActionBaraction

The set of actions for a surface or section; the renderer places it where that platform expects.

PropTypeNotes
children requiredcomponent idsAction component ids, in order of importance

Use when

  • Two or more actions that apply to the whole surface or section

Don't use when

  • A single action inline with content: use Action directly

Accessibility toolbar / group

  • Order in the accessibility tree is order of importance

Agents: Actions are listed together.

Rendering rules

  • Web: bottom of the section, primary last on desktop and first on mobile stacks
  • iOS/Android: toolbar or bottom bar on compact screens

A2UI: Row of Button

ActionMenuaction

Secondary actions behind one control: an overflow menu, a dropdown, a split button or a context menu.

PropTypeNotes
label requiredtext or bindingThe control's name: 'More actions' for an overflow, or the verb for a dropdown ('Export')
kind"overflow" | "dropdown" | "split" | "context"'overflow' is the '…' control; 'dropdown' is a labelled button that opens the menu; 'split' pairs a primary action with a menu of alternatives; 'context' opens on right-click or long-press of the component it belongs to
children requiredcomponent idsThe Actions in the menu, in order; a danger-toned one goes last and is separated
primarycomponent idFor 'split': the Action that runs when the main part is pressed

Use when

  • Three or more secondary actions on a row, a card or a page header
  • One usual action with rarer alternatives (split: 'Save' with 'Save as draft')
  • Actions that belong to the thing under the pointer (context)

Don't use when

  • One or two actions: use Action or ActionBar, where they are visible
  • The main thing to do on the surface: never hidden in a menu
  • Navigation between views: use Views or Navigation

Accessibility a menu button (aria-haspopup, aria-expanded) opening a menu of menuitems; a split's main part is a plain button

  • Every action is reachable by keyboard: arrows move, Enter activates, Escape closes and returns focus
  • An overflow control is named for what it holds ('More actions for Acme Corp'), never just '…'
  • A context menu's actions are also reachable another way (an overflow control), since right-click and long-press aren't discoverable

Agents: Opens the menu by its name and activates an action by its label.

Rendering rules

  • The menu uses color.surface.overlay with elevation.overlay and radius.default; items are size.control.default tall with space.inset.default
  • A danger-toned Action shows in color.status.danger.emphasis after a divider
  • The overflow control is an icon-only button at size.target.min with the label as its accessible name; a dropdown shows the label with a chevron
  • A split's two parts share one outline; the menu part is at least size.target.min wide

A2UI: Custom (no Basic equivalent)

Comparisonflow

Compare a few options across the same attributes, and choose one.

PropTypeNotes
items requiredbindingArray of options in host data (2–4 recommended)
itemTitle requiredJSON PointerRelative path to each item's name
attributes requiredlist of objects
choose{ label, action }Action per item; context bindings resolve against the item
recommendedtext or bindingOptional value of the recommended item's title, with a reason in 'summary'
summarytext or binding
recommendedReasontext or bindingWhy the recommended item fits, shown on its badge (one short sentence)

Use when

  • Choosing between 2–4 plans, products, routes or offers

Don't use when

  • More than ~5 items: use Table with sorting
  • No decision needed: use Table

Accessibility table (items as columns on wide screens) or list of cards

  • Attribute names are headers
  • 'better' is conveyed in text, not only color

Agents: Reads attributes per item; choose actions are named with the item title.

Rendering rules

  • Wide: items as columns; compact: one card per item with the same attribute order
  • Best values per attribute are marked when 'better' is set
  • Exactly one item may be recommended; its badge carries recommendedReason
  • Attributes with the same group sit under one heading
  • Boolean values render as a check or a dash with text alternatives ('Included' / 'Not included')
  • On compact surfaces the recommended item comes first

A2UI: No direct equivalent; exports as List of Card

Confirmflow

Asks the user to confirm a consequential or destructive action, showing what will happen.

PropTypeNotes
title requiredtext or bindingQuestion naming the action ('Send £250 to Alex?')
messagetext or binding
consequencetext or bindingWhat happens and whether it can be undone
summarycomponent idOptional DetailList summarising what is being confirmed
severity required"consequential" | "destructive"
confirm required{ label, action }
cancel{ label, action }Defaults to 'Cancel' → ui.dismiss
typeToConfirmtext or bindingText the user must type before confirming (for irreversible, high-impact actions)
amountobjectThe amount being committed, shown large at the top
subjectobjectWho or what the action is for, shown with a face or picture
consequenceslist of objectsWhat will happen, as a short list (for destructive actions)

Use when

  • Moving money, deleting data, sending on someone's behalf, anything irreversible

Don't use when

  • Routine reversible actions (prefer undo)
  • Information only: use Status

Accessibility alertdialog

  • Focus starts on the least destructive option
  • Confirm label repeats the action verb
  • Escape cancels

Agents: Reads title and consequence; confirm and cancel are named buttons.

Rendering rules

  • destructive uses color.action.danger.*
  • Capabilities with high risk level must use Confirm (enforced by the verifier)
  • the consequence sits directly above the confirm button
  • amount and subject lead the dialog when set
  • consequences render as an icon list, two columns on wide surfaces

A2UI: Modal with Text and Buttons

Stepsflow

A task split into ordered steps with visible progress.

PropTypeNotes
steps requiredlist of objects
kind"wizard" | "tasklist" | "guide"'wizard' shows one step at a time in order; 'tasklist' lists tasks people do in any order, each with its status; 'guide' is numbered instructions with no state
currentnumber or bindingIndex of the current step (default 0)
finish required{ label, action }

Use when

  • Tasks with dependent stages or too many inputs for one view (checkout, onboarding)

Don't use when

  • Independent views: use Views
  • Under ~6 inputs: a single Form

Accessibility group with step progress (aria-current on the current step)

  • Current step and total are announced
  • Back never loses entered data

Agents: Reads 'step N of M'; next/back are exposed as buttons.

Rendering rules

  • Renderer provides Back (ui.back) and Next (ui.next); the last step shows 'finish'
  • Each step validates before moving on
  • 'tasklist' is a list of tasks with a status tag each (GOV.UK task list); a task opens its content in place, and 'finish' follows the list, saying how many are done
  • 'guide' shows every step's title and content in a numbered list, with 'finish' after the last

A2UI: No direct equivalent; exports as Column of the current step

Polyxd is an early preview. Found something unclear? It will get better with your feedback.