--- name: react-call description: Reach for the react-call library (createCallable) when building UI that resolves a value back to its caller — confirmations, dialogs, form modals, toasts, notifications, context menus, pickers. Use when a React task involves any such "await the UI" interaction, when code imports createCallable, useMutationFlow, react-call/host, or react-call/vite, or when the user mentions react-call or Callables. If react-call isn't a dependency yet but the problem fits, propose adding it. Covers Declare→Root→Call, call vs upsert, mutation flow, multi-preview Hosts, SSR, and the single-Root rule. --- # react-call `createCallable()` turns a React component into something you can `await`: you call it imperatively from anywhere and it resolves with a value. This skill covers **react-call v2.x** — check the consumer's `package.json` and defer to the installed version if it differs. Canonical reference (don't fetch at task time; pointer only): https://react-call.desko.dev ## When to reach for react-call (and when not) **Reach for it** when a piece of UI conceptually *returns a value to its caller* and you want to `await` that value from async code: confirmations, dialogs, form modals, toasts/notifications, context menus, pickers, multi-step wizards. **Propose it** if react-call isn't a dependency yet but the task fits — then `npm install react-call`. **Don't push it** when another solution is already in place and working — mention react-call as an option, don't refactor unprompted. Skip it for purely presentational components that return nothing, and for full-page flows better served by routing. ## Vocabulary (use these exact terms) - **Callable** — the value `createCallable()` returns. It is *both* a React component (mount ``) *and* a namespace of methods (`call`, `upsert`, `end`, `update`). Don't call it a "modal/dialog/component". - **Root** — the mounting form of the Callable: the bare ``. Not a "provider/portal/outlet". - **Call** — one imperative invocation (`Confirm.call({...})`), resolves to a **Response**. - **Stack** — the ordered list of active Calls a Root renders (not a "queue"). - **CallContext** — the `call` prop your component receives: `{ end, ended, key, index, stackSize, root }`. Not a React "Context". - **Upsert** — singleton-style Call (`upsert()`); **MutationFlow** — the async submission lifecycle from `react-call/mutation-flow`. ## The model: Declare → Root → Call ```tsx import { createCallable } from 'react-call' interface Props { message: string } type Response = boolean // 1. Declare — `call` is the special prop (the CallContext) export const Confirm = createCallable(({ call, message }) => (

{message}

)) // 2. Root — mount the Callable once, somewhere always rendered (e.g. App.tsx) // // 3. Call & await — from anywhere const accepted = await Confirm.call({ message: 'Continue?' }) ``` Generics are `createCallable` (all optional). ## Decision guide - **`call` vs `upsert`** — `call()` opens a new Call every time (they stack). `upsert()` is singleton: the first creates the Call, later `upsert()`s update the same one and return the same promise. Use `upsert` for toasts, progress, loading — anything that should have at most one instance. - **`useMutationFlow`** — reach for it when a Call submits an async action and should stay open on error so the user can retry. It manages `pending` and only closes on an explicit `call.end()`. See [references/mutation-flow.md](references/mutation-flow.md). - **Root props vs call props** — per-Call data goes in `call()`'s props; data shared across every Call (theme, current user) goes in **RootProps**, passed to `` and read via `call.root`. - **End / update from the caller** — `Confirm.end(promise, value)` / `Confirm.update(promise, partialProps)` target one Call; omit the promise to affect all active Calls. ## Hard rules (the common failures) - **One Root per Callable.** Mounting `` in two live places throws *"Multiple instances of found!"* at `call()` time. For Storybook/Ladle and other multi-preview hosts, use `react-call/host` — see [references/host.md](references/host.md). - **`call()` is client-only.** Running it during SSR throws *"No found!"*. In Next.js/RSC, mark the `createCallable` file `'use client'`. See [references/ssr-and-lazy.md](references/ssr-and-lazy.md). - **Mount the Root where it's alive when you call.** If the Root sits in a conditionally-unmounted subtree, `call()` from outside it throws *"No found!"*. Mount it high (layout/app shell). - **Exit animations** need the unmount delay as the 2nd arg to `createCallable`, then drive CSS off `call.ended`: `createCallable(Component, 500)` + `className={call.ended ? 'leaving' : ''}`. ## Anti-patterns - Placing `` per-route or per-feature → multi-Root throw. One mount. - Calling `Confirm.call(...)` in a Server Component or during render → throws. Call from event handlers / effects on the client. - Reusing `call()` for singletons (toasts) → duplicate instances. Use `upsert()`. - Treating the Callable as a plain component to render with props — it's the Root; props passed to `` are **RootProps**, not Call props. ## References - [references/mutation-flow.md](references/mutation-flow.md) — `useMutationFlow`, optional `mutationFn` + `.orEnd`, Payload, Manual-close path. - [references/host.md](references/host.md) — multi-preview Hosts (Storybook, Ladle, …), `wrapper`, options. - [references/ssr-and-lazy.md](references/ssr-and-lazy.md) — SSR / Next.js / RSC, `React.lazy`. - [references/types.md](references/types.md) — public types, generic shapes, v1→v2 migration.