Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
Show all changes
60 commits
Select commit Hold shift + click to select a range
c5ff0d1
feat(react,vue,astro): Add ui prop for version metadata
jacekradko Jan 23, 2026
d8370e0
chore: add changeset for ui prop
jacekradko Jan 23, 2026
67fdc89
refactor: use ui prop instead of clerkUiCtor in chrome-extension
jacekradko Jan 23, 2026
2399eff
refactor: remove clerkUiCtor from public API, add __internal_forceBun…
jacekradko Jan 23, 2026
89bb1ff
chore: update changeset description
jacekradko Jan 23, 2026
ccac639
refactor: rename clerkUiCtor to ClerkUI and ClerkUiConstructor to Cle…
jacekradko Jan 23, 2026
cf2a354
refactor: rename __internal_ClerkUiCtor to __internal_ClerkUICtor
jacekradko Jan 23, 2026
1d2c8cf
chore: simplify changeset
jacekradko Jan 24, 2026
8f705a8
refactor: rename ui.ctor to ui.ClerkUI
jacekradko Jan 24, 2026
478a0b3
Merge branch 'main' into jrad/ui-prop-cleanup
jacekradko Jan 24, 2026
9517d40
refactor: move ClerkUI inside ui object in ClerkOptions
jacekradko Jan 24, 2026
890cd43
fix: rename ctor to ClerkUI in ui export
jacekradko Jan 24, 2026
7f7665f
chore: fix formatting
jacekradko Jan 24, 2026
a3014de
chore: fix es-ES.ts formatting
jacekradko Jan 24, 2026
9774008
fix(astro): Remove unnecessary eslint-disable directive
jacekradko Jan 24, 2026
e81f20a
test(vue): add unit tests for CDN UI loading with version pinning
jacekradko Jan 24, 2026
d3c96f3
fix(astro): honor bundled UI constructor in getClerkUiEntryChunk
jacekradko Jan 24, 2026
aa0c84b
fix(astro): preserve clerkUiUrl fallback in loadClerkUiScript call
jacekradko Jan 24, 2026
64ff3dc
fix: standardize casing for clerkUIUrl and clerkUIVersion properties
jacekradko Jan 24, 2026
76d7c96
fix(vue): preserve clerkUIUrl fallback when ui.url is not set
jacekradko Jan 24, 2026
c0d3b6f
fix(vue): use type cast for clerkUIUrl/clerkUIVersion fallback
jacekradko Jan 24, 2026
61655b1
fix: update integration templates to use clerkUIUrl casing
jacekradko Jan 24, 2026
978a0d8
Merge branch 'main' into jrad/ui-prop-cleanup
jacekradko Jan 26, 2026
18a45b8
test(react-router): Add ClerkProvider clerkUIUrl prop tests
jacekradko Jan 26, 2026
a9f4cca
fix(react): Use bundled ClerkUI by default, add __internal_preferCDN …
jacekradko Jan 26, 2026
08064ce
fix(react): Await getClerkUiEntryChunk to ensure ClerkUI is resolved
jacekradko Jan 26, 2026
f44ff91
Merge branch 'main' into jrad/ui-prop-cleanup
jacekradko Jan 27, 2026
aaecdf7
fix(integration): Wait for Clerk to load before signOut in component …
jacekradko Jan 27, 2026
b9a490f
test(react): Add unit tests for bundled vs CDN UI loading
jacekradko Jan 27, 2026
21895c2
Merge main into jrad/ui-prop-cleanup
jacekradko Jan 30, 2026
68a17c9
fix(vue): Handle ui prop in clerkPlugin and fix test mocks
jacekradko Jan 30, 2026
35eaeab
feat(react): Support bundled UI via ui.ClerkUI prop
jacekradko Feb 3, 2026
a77ede7
refactor(react,vue): Remove version/url from ui prop, require ClerkUI
jacekradko Feb 4, 2026
4e339ca
fix(vue): Use clerkUICtor option instead of ui.ClerkUI for clerk.load()
jacekradko Feb 4, 2026
f9c063b
Merge branch 'main' into jrad/ui-prop-cleanup
jacekradko Feb 4, 2026
6c4d6fe
feat(ui,react): Add react-server conditional export for RSC support
jacekradko Feb 5, 2026
512942c
test(e2e): Add integration test for bundled UI with react-server cond…
jacekradko Feb 5, 2026
208a1ac
test(ui): add snapshot tests for ui export signature
jacekradko Feb 5, 2026
04b6512
Merge branch 'main' into jrad/ui-prop-cleanup
jacekradko Feb 5, 2026
6a161e0
fix(nextjs): skip UI CDN preload when ui prop is passed
jacekradko Feb 5, 2026
d5234f7
fix(chrome-extension): use ui prop instead of clerkUICtor
jacekradko Feb 5, 2026
a87e669
Merge branch 'main' into jrad/ui-prop-cleanup
jacekradko Feb 6, 2026
41bc6f4
fix(integration): isolate @clerk/ui to bundled-UI-specific test only
jacekradko Feb 6, 2026
2803a6e
fix(astro): support bundled UI via ui prop in getClerkUIEntryChunk
jacekradko Feb 6, 2026
d12dcaf
Merge branch 'main' into jrad/ui-prop-cleanup
jacekradko Feb 6, 2026
8bd8934
refactor(shared,ui,clerk-js,react,vue,astro): replace clerkUICtor wit…
jacekradko Feb 6, 2026
955d1ea
fix(vue): fix formatting in plugin.ts
jacekradko Feb 6, 2026
f8a8f2e
fix(react): externalize @clerk/ui/entry to prevent bundling into dist
jacekradko Feb 6, 2026
244e970
fix(react,nextjs): move @clerk/ui/entry dynamic import to nextjs SDK
jacekradko Feb 6, 2026
7513813
fix(nextjs): fix lint errors for @clerk/ui/entry import
jacekradko Feb 6, 2026
ef29072
chore: clean up changeset and increase async test timeout
jacekradko Feb 6, 2026
09c5da4
Merge branch 'main' into jrad/ui-prop-cleanup
jacekradko Feb 6, 2026
536005b
Merge branch 'main' into jrad/ui-prop-cleanup
jacekradko Feb 6, 2026
15e92d8
Merge branch 'main' into jrad/ui-prop-cleanup
jacekradko Feb 7, 2026
3c7b44a
fix(nextjs): Add webpackIgnore to @clerk/ui dynamic import
jacekradko Feb 8, 2026
dd6fb56
fix(nextjs): Add comment explaining webpackIgnore usage
jacekradko Feb 8, 2026
e00c31a
refactor(ui): Consolidate __PKG_VERSION__ to PACKAGE_VERSION
jacekradko Feb 8, 2026
973f9c3
fix(ui): Skip CDN prefetch when ui prop is passed
jacekradko Feb 9, 2026
6092509
chore: Format
jacekradko Feb 9, 2026
3987c28
fix(nextjs): Fix eslint-disable-next-line placement for import/no-unr…
jacekradko Feb 9, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 23 additions & 0 deletions .changeset/shiny-owls-dance.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
---
'@clerk/ui': minor
'@clerk/react': minor
'@clerk/vue': minor
'@clerk/astro': minor
Comment thread
jacekradko marked this conversation as resolved.
'@clerk/chrome-extension': minor
'@clerk/shared': minor
---

Add `ui` prop to ClerkProvider for UI version metadata

The `ui` object from `@clerk/ui` contains version info and the bundled constructor. Each SDK decides whether to use `ui.ctor` based on its support level:
- Chrome Extension: Uses bundled UI via `ui.ctor`
- React/Next.js, Vue, Astro: Uses CDN loading

Usage:
```tsx
import { ui } from '@clerk/ui';

<ClerkProvider ui={ui}>
...
</ClerkProvider>
```
7 changes: 1 addition & 6 deletions packages/astro/src/internal/create-clerk-instance.ts
Original file line number Diff line number Diff line change
Expand Up @@ -109,16 +109,11 @@ async function getClerkJsEntryChunk<TUi extends Ui = Ui>(options?: AstroClerkCre
}

/**
* Gets the ClerkUI constructor, either from options or by loading the script.
* Returns early if window.__internal_ClerkUiCtor already exists.
* Gets the ClerkUI constructor by loading from CDN.
*/
async function getClerkUiEntryChunk<TUi extends Ui = Ui>(
options?: AstroClerkCreateInstanceParams<TUi>,
): Promise<ClerkUiConstructor> {
if (options?.clerkUiCtor) {
return options.clerkUiCtor;
}

await loadClerkUiScript(options);

if (!window.__internal_ClerkUiCtor) {
Expand Down
5 changes: 5 additions & 0 deletions packages/astro/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,11 @@ type AstroClerkIntegrationParams<TUi extends Ui = Ui> = Without<
* The URL that `@clerk/ui` should be hot-loaded from.
*/
clerkUiUrl?: string;
/**
* The Clerk UI bundle to use. When provided with a bundled UI via
* `ui.ctor`, it will be used instead of loading from CDN.
*/
ui?: TUi;
};

type AstroClerkCreateInstanceParams<TUi extends Ui = Ui> = AstroClerkIntegrationParams<TUi> & {
Expand Down
7 changes: 4 additions & 3 deletions packages/chrome-extension/src/react/ClerkProvider.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import type { Clerk } from '@clerk/clerk-js/no-rhc';
import type { ClerkProviderProps as ClerkReactProviderProps } from '@clerk/react';
import { ClerkProvider as ClerkReactProvider } from '@clerk/react';
import type { Ui } from '@clerk/react/internal';
import { ClerkUi } from '@clerk/ui/entry';
import { ui } from '@clerk/ui';
import React from 'react';

import { createClerkClient } from '../internal/clerk';
Expand Down Expand Up @@ -32,11 +32,12 @@ export function ClerkProvider<TUi extends Ui = Ui>(props: ChromeExtensionClerkPr
return null;
}

// Chrome extension uses bundled UI via ui.ctor
return (
<ClerkReactProvider
{...rest}
{...(rest as any)}
Clerk={clerkInstance}
clerkUiCtor={ClerkUi}
clerkUiCtor={ui.ctor}
Comment thread
coderabbitai[bot] marked this conversation as resolved.
Outdated
Comment thread
brkalow marked this conversation as resolved.
Outdated
standardBrowser={!syncHost}
>
{children}
Expand Down
1 change: 1 addition & 0 deletions packages/react/src/contexts/ClerkProvider.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import { ClerkContextProvider } from './ClerkContextProvider';

function ClerkProviderBase<TUi extends Ui>(props: ClerkProviderProps<TUi>) {
const { initialState, children, ...restIsomorphicClerkOptions } = props;

const isomorphicClerkOptions = restIsomorphicClerkOptions as unknown as IsomorphicClerkOptions;

return (
Expand Down
2 changes: 1 addition & 1 deletion packages/react/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ declare global {
/**
* @interface
*/
export type ClerkProviderProps<TUi extends Ui = Ui> = Omit<IsomorphicClerkOptions, 'appearance'> & {
export type ClerkProviderProps<TUi extends Ui = Ui> = Omit<IsomorphicClerkOptions, 'appearance' | 'clerkUiCtor'> & {
children: React.ReactNode;
/**
* Provide an initial state of the Clerk client during server-side rendering. You don't need to set this value yourself unless you're [developing an SDK](https://clerk.com/docs/guides/development/sdk-development/overview).
Expand Down
10 changes: 9 additions & 1 deletion packages/shared/src/types/clerk.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2436,7 +2436,15 @@ export type IsomorphicClerkOptions = Without<ClerkOptions, 'isSatellite'> & {
* This is a structural-only type for the `ui` object that can be passed
* to Clerk.load() and ClerkProvider
*/
ui?: { version: string; url?: string };
ui?: {
version: string;
url?: string;
/**
* The Clerk UI constructor. When provided, this will be used instead of
* loading the UI from CDN. This is useful for bundling the UI with your app.
*/
ctor?: ClerkUiConstructor | Promise<ClerkUiConstructor>;
};
} & MultiDomainAndOrProxy;

export interface LoadedClerk extends Clerk {
Expand Down
16 changes: 14 additions & 2 deletions packages/ui/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,24 @@
import type { Ui } from './internal';
import type { Appearance } from './internal/appearance';

import { ClerkUi } from './ClerkUi';

declare const PACKAGE_VERSION: string;

/**
* Default ui object for Clerk UI components
* Tagged with the internal Appearance type for type-safe appearance prop inference
* UI object for Clerk UI components.
* Pass this to ClerkProvider to use the bundled UI.
*
* @example
* ```tsx
* import { ui } from '@clerk/ui';
*
* <ClerkProvider ui={ui}>
* ...
* </ClerkProvider>
* ```
*/
export const ui = {
version: PACKAGE_VERSION,
ctor: ClerkUi,
} as Ui<Appearance>;
7 changes: 7 additions & 0 deletions packages/ui/src/internal/index.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import type { ClerkUiConstructor } from '@clerk/shared/ui';

import type { Appearance } from './appearance';

export type { ComponentControls, MountComponentRenderer } from '../Components';
Expand Down Expand Up @@ -26,6 +28,11 @@ export type Ui<A = any> = Tagged<
{
version: string;
url?: string;
/**
* The Clerk UI constructor. When provided, this will be used instead of
* loading the UI from CDN. This is useful for bundling the UI with your app.
*/
ctor?: ClerkUiConstructor | Promise<ClerkUiConstructor>;
/**
* Phantom property for type-level appearance inference
* This property never exists at runtime
Expand Down
16 changes: 7 additions & 9 deletions packages/vue/src/plugin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -78,15 +78,13 @@ export const clerkPlugin: Plugin<[PluginOptions]> = {
void (async () => {
try {
const clerkPromise = loadClerkJsScript(options);
const clerkUiCtorPromise = pluginOptions.clerkUiCtor
? Promise.resolve(pluginOptions.clerkUiCtor)
: (async () => {
await loadClerkUiScript(options);
if (!window.__internal_ClerkUiCtor) {
throw new Error('Failed to download latest Clerk UI. Contact support@clerk.com.');
}
return window.__internal_ClerkUiCtor;
})();
const clerkUiCtorPromise = (async () => {
await loadClerkUiScript(options);
if (!window.__internal_ClerkUiCtor) {
throw new Error('Failed to download latest Clerk UI. Contact support@clerk.com.');
}
return window.__internal_ClerkUiCtor;
})();
Comment thread
jacekradko marked this conversation as resolved.
Outdated

await clerkPromise;

Expand Down
Loading