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 with | The important distinction |
|---|---|---|
| Perform an action or go somewhere | Button, Link | An action and a destination have different browser behavior. |
| Choose one value from a known set | RadioGroup, Select | An always-visible choice and a popup have different space and interaction costs. |
| Search through options | Combobox, Listbox | The text query, active option, and committed value are separate state. |
| Run one of several commands | Menu | A command menu is not ordinary website navigation. |
| Complete a focused task | Dialog, NativeDialog | Opening, closing, modality, and returning focus form one interaction. |
| Reveal supporting information | Disclosure, Popover | Visibility alone does not determine dismissal or focus behavior. |
| Navigate structured information | Tree, Grid, TreeGrid | Hierarchy 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
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
Choose button types, connect Effect handlers, and preserve browser activation through styling and custom hosts.
Link: navigation that still behaves like a link ↗Understand which clicks enter Typed Navigation and which remain browser-owned anchor behavior.
Checkbox: boolean choices and mixed summaries ↗Connect native checked and indeterminate properties to one hydrated state without confusing mixed presentation with submitted data.
Switch: a stable name for an on/off setting ↗Model a binary setting with native button activation and explicit persistence and form participation.
RadioGroup: one choice and one native group ↗Combine native radio inputs, named form values, and optional collection-based focus movement.
Select: a popover-backed list of choices ↗Assemble trigger, content, and options while making keyboard collection and native form differences explicit.
Slider: continuous native range input ↗Connect input-time numeric updates to an accessible range control and an explicit domain value.
SpinButton: numeric entry at the change boundary ↗Use native number entry while keeping empty drafts, finite state, bounds, and commit timing explicit.
Form: schema-bound controls and submission state ↗Understand decoded values, field codecs, form context, validation, metadata, and the native submit boundary.
Collections
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
Separate opening, cancel requests, accepted actions, and native modal behavior.
NativeDialog: synchronize an existing dialog ↗Connect open state to show, showModal, and close without adopting compound parts.
Popover: supporting content in the top layer ↗Build a manual popover with explicit dismissal and honest focus expectations.
NativePopover: observe open state on a real element ↗Own markup and reverse toggle synchronization while reusing the native observer.
Disclosure: reveal content without leaving the page ↗Compose native details and summary with hydrated state and predictable structure.
NativeDetails: connect details.open to application state ↗Use a one-way ref with an explicit browser-to-state toggle path.
Tooltip: a description that survives pointer and keyboard use ↗Connect a stable description ID, focusable anchor, delays, and manual popover content.
Hovercard: keep interactive previews reachable ↗Preserve pointer and focus transfer into a named non-modal preview.