@stormycms/react
React components and hooks for rendering CMS-driven pages and managing session state.
pnpm add @stormycms/reactThe package is organized into subpath exports:
| Import | Contents |
|---|---|
@stormycms/react | Re-exported types (SessionUser, SiteData) |
@stormycms/react/cms | Rendering & registration: withCMS, ComponentTree, LayoutTree, Layout, Outlet, buildLayoutTree, findComponent |
@stormycms/react/cms/client | Editor state providers: CMSPageProvider, CMSLayoutProvider, useCMSPage, useCMSLayout |
@stormycms/react/stormy | Session context: StormyProvider, useStormy (client components) |
@stormycms/react/plugin | The React framework plugin for stormy generate |
@stormycms/react/cms
withCMS(cmsProps, Component)
Wraps a React component with CMS metadata (label, fields, placement rules) so the editor can offer and edit it. Covered in depth in Components & Schema.
ComponentTree
Renders a stored component tree using your export map:
import { ComponentTree } from '@stormycms/react/cms';import cmsExports from 'components';
<ComponentTree components={page.components} cmsExports={cmsExports} />;Props:
components: CMSComponentData[]— the tree (usemapPageDatafrom core to convert raw GraphQL data)cmsExports: CMSExportsMap— your export mapslotContent?: ReactNode— rendered wherever anOutletcomponent appears
Components whose name isn't in the export map are skipped.
LayoutTree and buildLayoutTree
Layouts chain parent → child, with page content rendered at the innermost Outlet:
import { LayoutTree, ComponentTree, buildLayoutTree } from '@stormycms/react/cms';
const layout = buildLayoutTree(page.layouts, page.layoutId);
<LayoutTree layout={layout} cmsExports={cmsExports}> <ComponentTree components={page.components!} cmsExports={cmsExports} /></LayoutTree>;buildLayoutTree(layouts, parentLayoutId?)— assembles a nestedCMSLayoutDatachain from the flat layout list. Pass the page'slayoutIdto build the chain for that page; returnsnullwhen there's no layout (andLayoutTreethen renders children directly).LayoutTree— recursively renders the chain.
Outlet and Layout
Built-in, layout-only CMS components. Outlet marks the content slot; Layout is the internal wrapper LayoutTree uses. Include Outlet in your export map so layouts can place it.
findComponent(components, id)
Depth-first search for a component by ID in a tree — useful in editor UIs.
@stormycms/react/cms/client
Client-side providers that hold the editor state for a page or layout:
import { CMSPageProvider, useCMSPage } from '@stormycms/react/cms/client';
<CMSPageProvider page={{ id: page.id, components: page.components, initialData: { name, slug, layoutId } }}> <PageEditor /></CMSPageProvider>;CMSPageProvider/useCMSPage— editable page state, includingcomponents,setComponents,addComponent,removeComponent,updateComponent,layoutId, andinitialData.CMSLayoutProvider/useCMSLayout— editable layout state, includingparentLayoutIdand the same component editing helpers.
The boilerplate admin wraps these providers around its PageEditor and LayoutEditor components so the editor can mutate the component tree before saving it back to the API.
@stormycms/react/stormy
Client-side session context. In Next.js apps prefer StormyServerProvider which wraps this with server-fetched initial data.
StormyProvider
'use client';import { StormyProvider } from '@stormycms/react/stormy';
<StormyProvider loginUrl="/login">{children}</StormyProvider>;Key props (all optional):
| Prop | Default | Purpose |
|---|---|---|
authUrl | /api/auth/stormy?action=session | Endpoint polled for session status |
siteUrl / sitesUrl | ...action=site / ...action=sites | Endpoints for current site / site list |
loginUrl | /login | Redirect target when the session expires |
guard | true | Watch the session and redirect on expiry |
checkThrottleMs | 60000 | Minimum delay between activity-driven session checks |
onSessionExpired | — | Callback instead of redirecting |
initialUser / initialSite / initialSites | — | Server-fetched initial state (skips client fetch) |
Session checks are driven by user activity and tab focus rather than a background interval, so an abandoned tab doesn't defeat idle timeouts.
useStormy()
const { user, site, sites, isLoading, isAuthenticated, refresh } = useStormy();Throws if used outside a StormyProvider.
@stormycms/react/plugin
The React plugin for the CLI's schema generation — parses React component files and infers CMS fields from their props. You normally don't import this directly; the CLI loads it automatically when React is detected.
Last updated: 7/9/26, 6:42 AM