React 19 added actions, transitions, useOptimistic, Suspense for data and <ViewTransition>. FUNSTACK UI is a headless component library that uses them for you, so the async work around every button, tab and dialog is already done.
Every component with an action sets data-pending while the action runs, until its result is on screen. Style it in CSS.
Pass an async function as an action prop. The component runs it in a transition, shows the new value at once, and rolls it back if the action fails. Errors go to your Error Boundary.
The display always shows the latest click. Uncontrolled state commits only the latest one, so a slow response to an older click never overwrites a newer choice.
When the next tab, accordion item or dialog loads data, the current screen stays as it is and the trigger shows pending until the new content is ready.
Popups use the Popover API, <dialog> and CSS Anchor Positioning; form controls are native inputs. The browser handles the top layer and Escape, and popovers close on a click outside natively.
Pass transition to a part and it renders React's <ViewTransition>. Each change is tagged with a transition type, such as fsui-tabs-next, so you can animate by direction.
A favourite button that saves to a server. By hand:
const [pressed, setPressed] = useState(initial);
const [optimistic, setOptimistic] = useOptimistic(pressed);
const [isPending, startTransition] = useTransition();
<button
aria-pressed={optimistic}
data-pending={isPending ? "" : undefined}
onClick={() => {
const next = !optimistic;
startTransition(async () => {
setOptimistic(next);
await saveFavorite(next);
startTransition(() => setPressed(next));
});
}}
>
Favorite
</button>
// ...and a slow save from an earlier click can still overwrite a later one.With FUNSTACK UI:
<Toggle defaultPressed={initial} pressedChangeAction={(next) => saveFavorite(next)}>
Favorite
</Toggle>Same optimistic flip and data-pending, plus latest-click-wins and transition types for animation. Try it on the home page.
Most established headless React libraries were designed before React's async features, and support a wide range of browsers. They are mature and a safe choice. FUNSTACK UI takes a different approach:
| Typical headless library | FUNSTACK UI | |
|---|---|---|
| Callbacks | Event handlers (onValueChange, onOpenChange). Transitions, optimistic state and pending flags are yours to add. | Action props: run in a transition, may be async. Optimistic and pending state built in. |
| Content that loads data | Usually updated urgently, so content that suspends shows its fallback unless you add a transition. | Old content stays on screen until the new content is ready. |
| Popups | JavaScript for positioning, layering and dismissal, so older browsers work too. | The platform: Popover API, <dialog>, CSS Anchor Positioning. Some components work before hydration. |
| Animation | CSS, with exit-animation states built in. No <ViewTransition> integration. | CSS, plus <ViewTransition> through the parts' transition prop (Transitions). |
| Browsers | Wide support, including older versions. | Latest stable Chrome, Edge, Safari and Firefox. No fallbacks. |
| Maturity | Stable APIs, large component sets. | Experimental alpha. APIs change without notice. |