Reference
Packages
Every @uniflowed/* package, what it is for, and whether it is real yet. They
are plain Flow — no native bindings — so what runs in the browser is what you
can read.
Three rules hold across all of them, and uf_lib has tests that enforce each:
no export *, so the surface is a list somebody wrote; no side effects at
import time, so a bundler can drop what you do not use; and a // @flow pragma
on every file.
Core
| Package | What it is |
|---|---|
@uniflowed/core | The pieces every other package builds on |
@uniflowed/react | React, re-exported by name, with Flow's own types |
@uniflowed/jsx-runtime | The JSX runtime uf compiles to |
@uniflowed/react-compiler | The official React Compiler, wired for uf |
@uniflowed/runtime | Host capabilities, resolved at run time |
@uniflowed/std | The standard library |
Application
| Package | What it is |
|---|---|
@uniflowed/router | The file-system router: matching, layouts, loaders, Link |
@uniflowed/server | The server adapter |
@uniflowed/config | defineConfig, and the config's Flow types |
@uniflowed/vite | The Vite plugin, the driver, and the host Flow loaders |
@uniflowed/loader | Module loading on each host |
@uniflowed/markdown | Markdown and MDX |
@uniflowed/web | Web platform bindings, and web vitals |
Data
| Package | What it is |
|---|---|
@uniflowed/fetch | Typed HTTP |
@uniflowed/query | Caching, revalidation, request de-duplication |
@uniflowed/effect | Typed effects: failures in the type, not in a catch |
@uniflowed/state | Atomic state — the guide |
@uniflowed/cell | Fine-grained reactivity: state and derived — the layer below |
@uniflowed/validator | Schemas that parse rather than assert |
@uniflowed/i18n | MessageFormat 2, with a message's arguments in the type |
@uniflowed/orm | Database access |
@uniflowed/graphql, @uniflowed/relay | GraphQL |
@uniflowed/temporal | Temporal, on every host. The implementation is @uniflowed/core/temporal, which is what installs today; this name adds the calendar surface that needs the binary |
Interface
| Package | What it is |
|---|---|
@uniflowed/ui | Components you own, built on the render types |
@uniflowed/hooks | The hook library — the browser half has a server answer for every one |
@uniflowed/motion | Animation |
@uniflowed/stylex | Static styles |
@uniflowed/react-native | React Native bindings |
@uniflowed/tui | Terminal interfaces — see the guide |
Testing
| Package | What it is |
|---|---|
@uniflowed/test | describe, it, expect, the hooks, and the worker uf test spawns |
@uniflowed/testing | The same API under its other name |
@uniflowed/react-testing | React Testing Library's surface. Needs a DOM |
@uniflowed/mock | Mocking |
@uniflowed/browser | Browser automation |
@uniflowed/story, @uniflowed/vrt | Stories and visual regression |
Tooling
| Package | What it is |
|---|---|
@uniflowed/cli | The CLI's JavaScript half |
@uniflowed/lint | Lint rule types |
@uniflowed/lib | The registry every package is declared in |
@uniflowed/pm, @uniflowed/rm | Package and runtime management |
@uniflowed/prepare, @uniflowed/pwa | Build preparation, progressive web apps |
@uniflowed/brand | The design tokens this site is built from |
What @uniflowed/ui ships today
The registry in crates/uf_lib/src/ui.rs names every component the package is
going to have. These are the ones that exist. Each implements the WAI-ARIA
authoring practices pattern it is named after — the roles, the aria-* wiring,
the focus management and the whole keyboard map — and ships no styles at all.
| Component | Pattern | The part that is easy to leave out |
|---|---|---|
Field | — | The label, description, error and aria-invalid wiring, and never an aria-describedby pointing at an element that is not there |
Switch, Checkbox, Toggle | Switch, Checkbox, Button (aria-pressed) | Three components, because a reader hears "on", "checked" and "pressed" — a setting, an answer, an action that stays applied — and the third state and the Enter key differ between them |
RadioGroup | Radio Group | Arrows that check as they move, and a tab stop on the first item while nothing is chosen, without which an unanswered group cannot be reached by Tab at all |
ToggleGroup | Button, Radio Group | One tab stop for a row of toggle buttons. type="single" is a radio group drawn as segments, and is rendered by RadioGroup rather than written twice |
Tabs | Tabs | One tab stop for the whole list, and the choice between automatic and manual activation |
Collapsible | Disclosure | aria-expanded, and an aria-controls that names the content only while there is content to name |
Accordion | Accordion | The heading level is the caller's, each panel is a region named after its header, and the closed ones stay findable by the browser's find-in-page |
NavigationMenu | Disclosure Navigation Menu | A <nav> of links behind aria-expanded buttons — not role="menu", which is for application commands and tells a reader the wrong thing about what they are looking at |
Dialog | Dialog (Modal) | A focus trap that cannot be escaped, focus given back, the page held still and made inert |
Menu | Menu | Arrow keys, Home/End, typeahead, submenus, and one Escape closing one level |
Combobox | Combobox | aria-activedescendant over a list the caller filters, and the count a reader is told |
The arrow keys follow the reader, not the compass. In a page that reads
right to left the first item of a row is the rightmost one, so ArrowLeft moves
to the next tab and a submenu opens onto the left. Every set here asks the DOM
which way the page reads at the moment a key is pressed, so putting dir="rtl"
where you would have put it anyway is the whole configuration; a dir="ltr"
island inside an RTL page keeps its own keys. Home and End are not mirrored:
they name the first and last item in reading order.
Which arrow keys a set claims follows its orientation, and the pair it does
not claim is left to the page — ArrowDown in a horizontal set scrolls, as it
does everywhere else. aria-orientation says which pair is live, so a reader is
told rather than left to guess. This is a deliberate narrowing of the WAI-ARIA
practices for RadioGroup, which list both pairs; the reasoning is in
packages/ui/radio-group.js.
A closed section is hidden, not removed. Collapsible and Accordion leave
their panels in the document and mark them hidden="until-found", so the
browser's find-in-page can still reach the text inside a collapsed section,
reveal it, and scroll to the match. Closed tab panels and closed navigation
groups are removed instead, and both modules say why. React cannot express
hidden="until-found" through the hidden prop — it is on React's list of
boolean attributes, so the string is flattened to hidden="" — so the
components upgrade the attribute after React commits it.
Publishing status
Some of these are on npm and most are not. The published set —
tools/release/published-packages.txt in the repository — is the closure a
real uf project needs plus the test runner, and every name in it goes out
together on each uf@* tag, so they are always at one version. The rest
resolve only through the repository's npm workspace, which is how this site — a
real uf project in docs/ — imports them.
Every release so far is a prerelease, so name the prerelease tag when you
install one by hand: npm install @uniflowed/ui@alpha. That gives you the
newest release whatever the latest tag happens to point at.
uf new needs no tag at all. The manifest it writes pins the exact version
of the uf that wrote it, so a new project's packages and the binary that
scaffolded them are one release.