@cesto/react wraps @cesto/web-sdk — you don’t need to install
both. It requires React 18 or later, is client-only, and ships a 'use client' banner,
so you can import it straight from a server component. Callbacks, being functions, still
have to live in a client component.
<CestoProvider>
Supplies the key, theme, mode, and default callbacks to everything below it, and owns a
single shared loader instance. Wrap your app once:
Provider callbacks run before any per-hook or per-call callback, so the provider is the
right place for analytics and the call site is the right place for UI state.
Nesting is supported — the nearest provider wins. Inline arrow callbacks and inline theme
literals are safe: both are latched by content, not identity, so they never churn the
context value or recreate the loader.
When the provider unmounts, an open dialog is closed. The overlay is attached to
document.body by the loader, so a route change would otherwise strand it on the page.
Closing only tears down the surface — an execution already in flight continues
server-side.<CestoInvestButton>
The CTA. Styled out of the box, themed from the same accent and radius as the dialog it
opens, and every escape hatch is first-class.
It also forwards a
ref to the underlying element and spreads every native button
attribute (type defaults to "button"). While a flow is open the element carries
data-cesto-state="open", which you can style against.
Using your own design system
asChild merges the trigger onto your element instead of rendering a <button>:
asChild opts out of the bundled spinner too — the child element’s content is yours, and
is passed through untouched. Read isOpen from useCestoInvest if you
want your own pending state.
Using your own CSS
Gating on your own validation
YouronClick runs first. Call preventDefault() to suppress the flow:
Strict CSP
The stylesheet is injected at runtime, which astyle-src without 'unsafe-inline'
blocks — the button would render unstyled. Import the stylesheet instead and mark the
document so the runtime injection stands down:
CESTO_BUTTON_CSS if you’d rather inline it yourself.
useCestoInvest()
The hook behind the button. Use it when you want the flow but not the CTA.
Options —
apiKey, baseUrl, theme, mode, plus any
callbacks. Passing apiKey, baseUrl, or theme gives the hook its
own loader rather than the provider’s shared one.
The hook works with or without a provider. Without one, pass apiKey directly:
status === 'success' and isOpen === true is a normal, reachable combination: the flow
stays open after a success until the user dismisses it. Track the two separately rather
than deriving one from the other.Errors before the flow opens
If the loader can’t be built — a missing key, a rejectedbaseUrl, or a non-browser
environment — invest() does not throw. It fires onError with
code: 'config_error', sets status to 'error', and returns an inert session. That
keeps a misconfiguration observable in your own error handling instead of crashing a render.
Next.js App Router
The package is client-only and carries a'use client' banner, so a server component can
import and render <CestoProvider> and <CestoInvestButton> directly — no wrapper needed.
Callbacks are functions and cannot cross the server boundary, so put any component that
passes them in a 'use client' file:
Exports
Next
Events
Every callback, and the order provider → hook → call site.
Theming
The tokens shared by the button and the dialog.