feat: Next.js (React Server Components) support#469
Conversation
Mark component entries with "use client" so the directive survives the build into each dist chunk, and expose compound sub-components as named exports so they work in React Server Components without dot access (which does not cross the client boundary). - Add 'use client' to all 43 component entry files (previously only on the barrel, where Rollup flattened it away so no directive reached dist/) - Remove the now-dead 'use client' from src/components/index.ts - Expose named subpart exports (dot-matching aliases) for all 17 compound components (Select, Accordion, Sidebar, RadioButton, Dialog, Drawer, Table, DropdownMenu, SearchBox, Breadcrumb, Pagination, Tabs, Menu, Topbar, HamburgerMenu, Container, ProgressSteps) - Add 'use client' to Drawer sub-part files so the bundler cannot hoist past the client boundary - Guard render-path window access in Sidebar and getOperatingSystem() for SSR safety
Add a "Next.js Usage" MDX doc page for every component (41), nested under each component below its Docs page. Each documents Server Component usage; compound components show the named subpart-export pattern (required in RSC) plus a dot-notation note, backed by a hidden example story that powers an isolated Canvas live preview. - 41 *.nextjs.mdx doc pages (one per component) - 17 *.nextjs.stories.tsx hidden example stories (tags: !dev, !autodocs) - .storybook/main.ts: allow MDX to build under the library vite config (strip lib/externals/output, drop lib-only plugins vite:dts + preserve-directives, normalize the addon-docs mdx-react-shim file:// import); order *.stories before *.mdx so Docs sorts above Next.js Usage
Fix the live previews and make the Next.js docs approachable for all levels. Previews: match each compound example to its main story's layout/sizing; drop docs.story.height (it clipped shadows/dropdowns); wrap Dialog/Drawer Title + CloseButton in flex justify-between so the X sits top-right. Clarity: add a plain-language TL;DR callout to every page; add an 'Event handlers & state' section (the client-component gotcha) to simple + non-stateful-compound pages; add a shared 'Guides / Using force-ui with Next.js' overview (Server vs Client components, install, CSS import, named-export rule with the real errors).
| @@ -1,3 +1,4 @@ | |||
| 'use client'; | |||
There was a problem hiding this comment.
What: The addition of the 'use client' directive is correct, but ensure consistent application across all components that directly interact with client-side functionalities.
Why: The 'use client' directive is necessary for Next.js Server Components to correctly interpret component behavior. This helps to prevent potential rendering issues when components need to access client-specific behavior, such as DOM manipulation or state management.
How: Double-check that this directive is present for all components intended to be rendered as client components. Review all component files to ensure consistency and functionality.
The Select Next.js example story rendered the combobox button with no accessible name, failing the test-runner's axe button-name rule. Add a label (matching the main Select story) so the button has discernible text.
ButtonGroup's default export is a compound object ({ Group, Button }) used via dot notation, which the earlier compound rollout missed (its scan only matched Object.assign and X.Sub = patterns). Dot access fails in Server Components, so expose ButtonGroupContainer (.Group) and ButtonGroupButton (.Button) as named exports, and add its Next.js Usage doc + hidden example story. Completes coverage: every public component now has a Next.js Usage page.
mohitsbsftester
left a comment
There was a problem hiding this comment.
Reviewed the RSC boundary approach, root barrel changes, named compound exports, directive preservation strategy, and the SSR guards added for window access. I did not find a concrete compatibility regression in the implementation. The one remaining automated thread on the Accordion use client directive is generic and the PR already applies the directive across the component entry modules as intended.
Related issue: brainstormforce/surerank#1860
Summary
Adds Next.js (React Server Components) compatibility to force-ui. Components can now be imported and rendered directly inside Server Components in the App Router, and compound components expose named subpart exports so they work across the server/client boundary. Fully backward compatible (existing dot-notation usage in client components is unchanged).
What changed
Core (RSC support)
'use client'directive added to every component entry file so it survives the build into eachdistchunk (previously only on the barrel, where Rollup flattened it away and no directive reacheddist/).SelectButton,DialogPanel,TabsTab,ContainerItem). Dot access (Select.Button) can't cross the RSC boundary; named exports are individual client references.'use client'(they live in separate modules the bundler would otherwise hoist past the client boundary).Sidebarinitial collapsed state andgetOperatingSystem()no longer touchwindowduring render.Storybook docs
<Canvas>preview..storybook/main.tsadjusted so MDX builds under the library Vite config.Changelog
1.8.0entry added.package.jsonversion intentionally left unbumped (to be cut separately).Verification
npm run build(tsc + vite) andbuild-storybookboth pass.dist/components/*/*.{es,cjs}.jsentry chunk leads with"use client".Notes