Browse documentation

Learning paths

Learn the UI primitives

Build interfaces by understanding their state, keyboard behavior, native hosts, and accessibility contracts.

A component is useful when you can predict what it will do. Where does focus go when a menu opens? Does moving through a list also select a value? What happens when the focused item disappears? Can a person submit the form without touching a pointer? These questions belong in the design of the feature, alongside its loading state and visual design.

Typed UI provides small pieces for answering them. Each guide below teaches one public primitive: the problem it solves, the state it needs, the markup and interactions it supplies, and the parts your application still owns. Start with a feature you are building; follow the lower-level contracts when you need to customize it.

Build your first reusable control

Begin with Button, Checkbox, and component. Together they introduce the core arrangement: an application owns state and commands, a primitive supplies interaction behavior, and a template places the host in the document. Your styles supply its appearance.

Suppose you are building a notification settings page. The persisted preference belongs to the application model. The checkbox reflects that preference and reports changes. The save button starts an application command. A disabled appearance alone must not be your duplicate-submission policy: the command also needs to decide what to do while a save is running. Connect the control to AsyncData and Fx concurrency when you add the request.

Then read Form. Browser form submission, text editing, decoded values, and request state are related, but they are different contracts. A good form makes that distinction visible through labels, validation feedback, and a predictable submission path.

Choose the interaction before the widget

A person needs to…Start withThe important distinction
Perform an action or go somewhereButton, LinkAn action and a destination have different browser behavior.
Choose one value from a known setRadioGroup, SelectAn always-visible choice and a popup have different space and interaction costs.
Search through optionsCombobox, ListboxThe text query, active option, and committed value are separate state.
Run one of several commandsMenuA command menu is not ordinary website navigation.
Complete a focused taskDialog, NativeDialogOpening, closing, modality, and returning focus form one interaction.
Reveal supporting informationDisclosure, PopoverVisibility alone does not determine dismissal or focus behavior.
Navigate structured informationTree, Grid, TreeGridHierarchy and two-dimensional movement need deliberate keyboard rules.

Read APG patterns as behavior contracts

The ARIA Authoring Practices Guide explains the expected behavior of common widgets. Adding a role does not install keyboard behavior. Native HTML already supplies many semantics and interactions; preserve those before adding custom behavior. See MDN’s ARIA introduction for that relationship.

Read a pattern while asking which state each key changes. In a listbox, focus identifies where keyboard input goes; selection identifies the application’s chosen value. They may move together, but that is a decision with consequences. In a menu, choosing an item can run a command and close the popup. The APG keyboard guide develops these distinctions across composite widgets.

The individual lessons link to their applicable patterns and explain Typed’s implementation. Some primitives, such as Group or VisuallyHidden, are structural utilities rather than complete APG widgets. A library primitive also cannot prove an assembled product accessible: labels, content, focus order, styling, and browser/assistive-technology behavior still depend on the application you build.

Make the component your own

Use component for generator-backed views. A generator with parameters creates a component function; a parameterless generator creates an Fx value. Its return value can be any Renderable. Each execution forks the parent Scope; its setup and rendered output share that child lifetime.

When the higher-level control does not fit, follow the primitive’s lower-level state and prop functions. Collection, Composite, and Focusable explain the mechanisms behind managed lists and keyboard movement. Dom explains the host boundary. These are useful when building a design system or another component library, not prerequisites for rendering a checkbox.

Keep CSS responsible for appearance: spacing, color, focus indicators, responsive layout, and states such as selected or invalid. Keep application commands responsible for business rules. This separation lets one interaction contract serve different designs without copying its keyboard behavior.

Test a whole interaction

For a command palette, test opening it from the keyboard, entering a query, moving through results, choosing a command, and returning to the invoking control. Also remove or disable the active result and close the palette while the request is pending. Those transitions expose bugs that a screenshot of the open popup will not show.

Use Storybook to isolate states, then test the assembled feature in a real browser. Keep Testing Typed systems nearby for the difference between model tests, DOM behavior, and resource cleanup. The lesson for each primitive gives you a concrete interaction sequence to work through.

Pick a primitive

The catalog below covers the public UI modules. Read a lesson to learn the behavior, then follow its API links when you need an exact signature or option. The complete UI reference includes every public export.

UI

Foundations

Meter: communicate a measurement in a known range ↗

Explain bounded measurements, threshold semantics, native rendering, and the difference from progress or input.

Alert: urgent messages without moving focus ↗

Use assertive live-region semantics deliberately and distinguish announcements from interactive recovery.

Heading: document hierarchy independent of visual size ↗

Use explicit heading levels while keeping outline semantics and design-system typography separate.

Group: make related controls understandable together ↗

Name a semantic group explicitly without inventing fieldset behavior or implicit label relationships.

Separator: a division without an interaction ↗

Choose semantic separation, orientation, and styling without implying a draggable splitter.

VisuallyHidden: retain meaning without visual layout ↗

Provide accessible text with clipping while distinguishing visual hiding, semantic hiding, and focus visibility.

Component: generators that return renderable values ↗

Understand zero-argument values, parameterized components, pipeline arguments, and E/R inference.

Focusable: an explicit keyboard entry point ↗

Use tabindex deliberately without mistaking focusability for an interaction pattern.

Collection: mounted item identity and order ↗

Register runtime element handles with scope cleanup and explicit navigation metadata.

Composite: active identity, movement, and focus ↗

Build keyboard movement from a collection while choosing roving or virtual focus explicitly.

Role: semantic output without invented behavior ↗

Use an explicit role while preserving naming, structure, and native interactions.

Dom: types, events, props, refs, and host rendering ↗

Preserve a component contract while extending its real DOM host.

Storybook: mount a story with an owned render scope ↗

Supply application services, await visible output, and dispose every mounted story.

HttpRouter: serve Typed routes through Effect HTTP ↗

Understand GET registration, decoding, request services, and buffered versus streaming HTML.

Forms

Collections

Combobox: editable queries and committed suggestions ↗

Keep input focus stable while navigating filtered suggestions and distinguish text from a validated choice.

Listbox: visible choices with selection following focus ↗

Build a persistent single-choice list and understand when navigation commits the value.

Menu: commands, checked items, and nested popups ↗

Compose native popover command menus without confusing active focus with application state.

Menubar: a persistent command row with popup menus ↗

Connect horizontal command focus to independently owned submenu popovers.

Tabs: panel visibility and deliberate activation ↗

Choose automatic or manual activation and keep tab identity separate from panel lifetime.

Tab: the singular module and reusable tab instances ↗

Use the Tab re-export correctly and design instance-safe local panel switches.

Toolbar: one keyboard surface for related commands ↗

Compose a roving command group while keeping command state and focus state independent.

Tree: hierarchical focus and expansion ↗

Model parent identities and visible descendants without mistaking focus for file selection.

Grid: spatial navigation with active-descendant focus ↗

Build a two-dimensional keyboard surface and distinguish it from an editable spreadsheet.

TreeGrid: hierarchical rows and spatial cell focus ↗

Keep row expansion identities separate from cell focus identities in a hierarchical grid.

Carousel: slide identity, controls, and rotation policy ↗

Build a manual slide sequence and understand the state required before adding automatic motion.

WindowSplitter: accessible range state for resizable panes ↗

Connect native pointer dragging and keyboard resizing to the same bounded pane layout.

Overlays