Skip to content

feat(ui): add composed profile shell, providers infra and stub router#9133

Open
alexcarpenter wants to merge 2 commits into
carp/profile-stack-03-extract-sectionsfrom
carp/profile-stack-04-composed-shell
Open

feat(ui): add composed profile shell, providers infra and stub router#9133
alexcarpenter wants to merge 2 commits into
carp/profile-stack-03-extract-sectionsfrom
carp/profile-stack-04-composed-shell

Conversation

@alexcarpenter

@alexcarpenter alexcarpenter commented Jul 10, 2026

Copy link
Copy Markdown
Member

Stack 4/7. New (unexported) infra for the composed profile API: ProfileProviderShell, stubRouter, useBillingRouter, useRequirePage, PageContext, createSection, plus the shared APIKeysSection/BillingSection used by both User and Org composed dirs.

Nothing is exported from the package yet.

Changesets live only on the release PR #9144; this PR carries none.


Stack

Reviewed as a stack. The 7 PRs merge bottom-up into release branch #9144, which integrates into main as a single unit.

# PR Layer
#9144 release → main (integration)
1 #9130 moduleManager getter across build boundary
2 #9131 shared profile UI infra
3 #9132 extract Section components from profile pages
4 #9133 👈 composed shell + providers infra
5 #9134 composed UserProfile
6 #9135 composed OrganizationProfile
7 #9136 expose @clerk/ui/experimental (public API)

@changeset-bot

changeset-bot Bot commented Jul 10, 2026

Copy link
Copy Markdown

⚠️ No Changeset found

Latest commit: 96548da

Merging this PR will not cause a version bump for any packages. If these changes should not result in a new version, you're good to go. If these changes should result in a version bump, you need to add a changeset.

This PR includes no changesets

When changesets are added to this PR, you'll see the packages that this PR includes changesets for and the associated semver types

Click here to learn what changesets are, and how to add one.

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

@coderabbitai

coderabbitai Bot commented Jul 10, 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

Configuration used: Repository YAML (base), Repository UI (inherited)

Review profile: CHILL

Plan: Pro Plus

Run ID: fa66fdf3-f203-4ef2-9dd8-a3dd49920523

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

Comment @coderabbitai help to get the list of available commands.

@vercel

vercel Bot commented Jul 10, 2026

Copy link
Copy Markdown

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

Project Deployment Actions Updated (UTC)
clerk-js-sandbox Ready Ready Preview, Comment Jul 15, 2026 2:09pm
swingset Error Error Jul 15, 2026 2:09pm

Request Review

@github-actions github-actions Bot added the ui label Jul 10, 2026
@alexcarpenter alexcarpenter force-pushed the carp/profile-stack-04-composed-shell branch from 6ff5709 to cb7fd8a Compare July 13, 2026 14:08
@alexcarpenter alexcarpenter force-pushed the carp/profile-stack-03-extract-sections branch from 411027c to 9c65dee Compare July 13, 2026 14:12
@alexcarpenter alexcarpenter force-pushed the carp/profile-stack-04-composed-shell branch from cb7fd8a to 13f68a7 Compare July 13, 2026 14:12
@alexcarpenter alexcarpenter force-pushed the carp/profile-stack-03-extract-sections branch from 9c65dee to e791dc6 Compare July 13, 2026 14:34
@alexcarpenter alexcarpenter force-pushed the carp/profile-stack-04-composed-shell branch from 13f68a7 to 669a561 Compare July 13, 2026 14:34
… on nonce/layer

Consolidate the duplicated environment + module-manager reads from the composed
providers into resolveComposedClerkRuntime, dropping the `as any` casts for
narrow structural types and warning once on version skew instead of a silent
blank render. Store the shared emotion cache with the nonce/cssLayerName it was
built from so a later change rebuilds it (matching the AIO StyleCacheProvider).
}
}

export function useBillingRouter(): { router: RouteContextValue; route: BillingRoute } {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is this a pattern we're going to need elsewhere? We have the VirtualRouter component already, which could potentially be usable here in some fashion, but that one is sort of geared towards modal routing so might not slot in as cleanly.

Food for thought, don't think we need to adjust now but I expect to see this pattern emerge more than once.

export function useRequirePage(componentName: string): boolean {
const page = useContext(PageContext);
if (!page) {
if (typeof __DEV__ === 'undefined' || __DEV__) {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this would only throw when the package is being developed, not in Clerk dev mode. I think this is intentional, but calling it out regardless

Comment on lines 4 to +12
// Why: composed profile roots (UserProfile + OrganizationProfile) mount as
// separate React roots in the consumer tree, so N can be live per clerk instance.
// One `cl-internal` emotion cache per instance is the invariant (two live caches,
// same key = duplicate style inserts, broken emotion dedup/ordering). AIO gets this
// free from its single portal tree; composed reconstructs it by keying the cache
// on the clerk instance here so sibling roots reuse one cache instead of each making
// their own.
const store = new WeakMap<object, EmotionCache>();
// their own. The cache is stored with the nonce/cssLayerName it was built from so a
// later change to either rebuilds it (matching the AIO StyleCacheProvider) instead
// of pinning whatever the first-mounted root happened to see.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

not sure if this is really needed. I would recommend that the comment is trimmed down to more clearly explain why this construct exists, or removed.

Comment on lines +153 to +154
// Match the portal path's normalization (Components.tsx:209) so a cssLayerName
// nested inside appearance.theme gets hoisted to top-level for @layer wrapping.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this reference file / line no. will get out of date quickly

Comment on lines +71 to +73
// SAFETY: __internal_environment is a real getter on the clerk-js Clerk class
// but not on the shared LoadedClerk interface. Narrowing to an optional field
// (not `any`) keeps the access typed and forces callers to handle `undefined`.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
// SAFETY: __internal_environment is a real getter on the clerk-js Clerk class
// but not on the shared LoadedClerk interface. Narrowing to an optional field
// (not `any`) keeps the access typed and forces callers to handle `undefined`.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants