Skip to content

feat(mosaic): render compound components from Server Components - #10795

Open
alexcarpenter wants to merge 7 commits into
devin/mosaic-component-exportsfrom
carp/mosaic-rsc-compound-namespaces
Open

alexcarpenter wants to merge 7 commits into
devin/mosaic-component-exportsfrom
carp/mosaic-rsc-compound-namespaces

Conversation

@alexcarpenter

@alexcarpenter alexcarpenter commented Nov 12, 2026 •

Copy link
Copy Markdown
Member

Description

Compound components (<Avatar.Root>, <Item.Group>, ...) can now be rendered from React Server Components.

Before this change, each compound was a plain object exported from a 'use client' module. Next replaces every export of such a module with a client reference, so Avatar.Root was undefined on the server.

Each of the 25 compound components now follows the Base UI layout:

  • <name>.tsx is a 'use client' leaf with prefixed exports (CardRoot, CardBanner, ...).
  • <name>.parts.ts re-exports them under the part names (Root, Banner, ...).
  • index.ts has no directive and does export * as Card from './card.parts'.

X.Part usage and the XProps types are unchanged. Each compound is now a module namespace object, so its parts are read-only.

Other changes:

  • tsdown builds with unbundle: true, so each file keeps its own 'use client' directive.
  • scripts/check-bundle.mjs now checks rules instead of a file list. It reads ., ./components/* and ./primitives/* from the exports map. Each entry must either start with 'use client' or only re-export namespaces built from directive-free parts files. Any parts module that imports react must be a 'use client' leaf.
  • dist/index.js is now a small re-export file, so pnpm bundlewatch first bundles it with rolldown (dependencies and peer dependencies left external) into dist/.bundlewatch/index.js and measures that against the existing 95KB budget. dist/.bundlewatch is excluded from the published files.
  • Panel.Title passes [ref, panelTitleRef] to useRender. The forward-ref-parts rule now checks it because it is exported, and it could not trace the old conditional ref. Behavior is unchanged, because useRender returns before attaching refs when enabled is false.

Notes for review:

  • Dialog.createHandle is the one part that isn't a component. On the server it is a client reference and can't be called.

Stacked on #10754.

Checklist

  • pnpm test runs as expected.
  • pnpm build runs as expected.
  • (If applicable) JSDoc comments have been added or updated for any package exports
  • (If applicable) Documentation has been updated

Type of change

  • 🐛 Bug fix
  • 🌟 New feature
  • 🔨 Breaking change
  • 📖 Refactoring / dependency upgrade / documentation
  • other:

@vercel

vercel Bot commented Nov 12, 2026 •

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated
clerk-js-sandbox Ready Ready Preview Nov 12, 2026 8:50pm UTC
swingset Ready Ready Preview Nov 12, 2026 8:50pm UTC

Request Review

@changeset-bot

changeset-bot Bot commented Nov 12, 2026 •

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: 6733f4e

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 2 packages
Name Type
@clerk/mosaic Patch
@clerk/swingset Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@coderabbitai

coderabbitai Bot commented Nov 12, 2026 •

Copy link
Copy Markdown
Contributor

Important

Review skipped

Auto reviews are disabled on base/target branches other than the default branch.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

Run configuration

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • Trigger review
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

@blacksmith-sh

blacksmith-sh Bot commented Nov 12, 2026 •

Copy link
Copy Markdown

Matches Compound parts render from a Server Component

Tested on e2bc13fe, untouched since — Before, the Server Component page crashed on Banner.Root being undefined in dev and failed next build; after, all six compounds render and the page prerenders.

Merge-base

Server page errors

This PR e2bc13fe

Server page renders

Merge-base

Webpack build fails

This PR e2bc13fe

Webpack build passes

Also checked · 3 match · 2 not run

Skipped Panel.Title refs unchanged · Skipped
Skipped check-bundle enforces the new rules · Skipped
Matches Client Component usage unchanged
Matches Compound parts are now read-only
Matches Bundlewatch measures the real index size

Proof on 6733f4e6 (from e2bc13fe) · Did Proof get it right? Yes · No

View full Proof report · React 👎 or comment @codesmith dismiss this proof to dismiss

This branch was successfully deployed

2 active deployments
Preview – swingset — 6733f4e6 Deployed Nov 12, 2026 by vercel[bot]
Preview – clerk-js-sandbox — 6733f4e6 Deployed Nov 12, 2026 by vercel[bot]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant