Skip to content

feat(clerk-js,themes,types): Introduce Clerk CSS variables #6275

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
45 commits
Select commit Hold shift + click to select a range
e0e6ef6
feat(clerk-js): Expose CSS variables for clerk appearance variables
alexcarpenter Jul 9, 2025
e246501
handle colorTextSecondary
alexcarpenter Jul 9, 2025
3d4fd36
update sizes and typography foundations
alexcarpenter Jul 9, 2025
9a2a9c6
handle types
alexcarpenter Jul 9, 2025
d9740c3
fix exports
alexcarpenter Jul 9, 2025
be27f20
fix application logo sizing
alexcarpenter Jul 9, 2025
c8f61e2
chore(clerk-js,themes,types): Variable migration (#6282)
alexcarpenter Jul 11, 2025
c65258c
Merge branch 'main' into alexcarpenter/user-2202-add-clerk-css-variab…
alexcarpenter Jul 11, 2025
daac718
feat(clerk-js): Expose CSS variables for clerk appearance variables (…
alexcarpenter Jul 11, 2025
f5c57ce
fix card footer background color
alexcarpenter Jul 11, 2025
f4bf7cc
simplify
alexcarpenter Jul 11, 2025
4270b50
handle font size scale
alexcarpenter Jul 11, 2025
9d7f66c
fix font-size-md usage
alexcarpenter Jul 11, 2025
e950c30
feat(clerk-js): Add `colorBorder` variable option (#6307)
alexcarpenter Jul 14, 2025
a65aae1
update descriptions
alexcarpenter Jul 14, 2025
444a6ea
Merge branch 'alexcarpenter/user-2202-add-clerk-css-variable-utilitie…
alexcarpenter Jul 14, 2025
aa65eec
feat(clerk-js): Add `colorShadow` variable option (#6290)
alexcarpenter Jul 14, 2025
2731ea8
Merge branch 'main' into alexcarpenter/user-2202-add-clerk-css-variab…
alexcarpenter Jul 14, 2025
6dc4f9c
add changeset
alexcarpenter Jul 14, 2025
13e0eaf
Merge branch 'alexcarpenter/user-2202-add-clerk-css-variable-utilitie…
alexcarpenter Jul 14, 2025
8a63e93
Update bundlewatch.config.json
alexcarpenter Jul 14, 2025
79f2499
sort imports
alexcarpenter Jul 14, 2025
e173b68
Merge branch 'main' into alexcarpenter/user-2202-add-clerk-css-variab…
alexcarpenter Jul 14, 2025
a7c3ea8
add test
alexcarpenter Jul 14, 2025
25cbdc3
fix $colorText usage and handle more border colors
alexcarpenter Jul 14, 2025
27254c0
Update bundlewatch.config.json
alexcarpenter Jul 14, 2025
83a1994
fix border fallback
alexcarpenter Jul 14, 2025
82a70ba
more border color updates
alexcarpenter Jul 14, 2025
c191125
feat(clerk-js): Add `colorModalBackdrop` variable option (#6312)
alexcarpenter Jul 14, 2025
17d3087
Merge branch 'main' into alexcarpenter/user-2202-add-clerk-css-variab…
alexcarpenter Jul 14, 2025
91cdac4
fix(clerk-js): Use fractions for variable ratios (#6314)
alexcarpenter Jul 15, 2025
76ae286
Merge branch 'main' into alexcarpenter/user-2202-add-clerk-css-variab…
alexcarpenter Jul 15, 2025
f1e46eb
Update bundlewatch.config.json
alexcarpenter Jul 15, 2025
4540a74
Update bundlewatch.config.json
alexcarpenter Jul 15, 2025
a92f6b8
fix createMutedForegroundColor fallback
alexcarpenter Jul 15, 2025
0f7cc63
Update bundlewatch.config.json
alexcarpenter Jul 15, 2025
5c0cdb9
fix: update resolveCSSVariable to be recursive to handle fallback css…
alexcarpenter Jul 15, 2025
077f7d6
Update bundlewatch.config.json
alexcarpenter Jul 15, 2025
a522c9d
update tests
alexcarpenter Jul 15, 2025
876741d
lint
alexcarpenter Jul 15, 2025
de632bd
Merge branch 'main' into alexcarpenter/user-2202-add-clerk-css-variab…
alexcarpenter Jul 15, 2025
da17e0c
Update bundlewatch.config.json
alexcarpenter Jul 15, 2025
e6d1ec2
Merge branch 'alexcarpenter/user-2202-add-clerk-css-variable-utilitie…
alexcarpenter Jul 15, 2025
590d502
Merge branch 'main' into alexcarpenter/user-2202-add-clerk-css-variab…
alexcarpenter Jul 15, 2025
4b1bada
Update .changeset/cuddly-heads-battle.md
alexcarpenter Jul 15, 2025
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
37 changes: 37 additions & 0 deletions .changeset/cuddly-heads-battle.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
---
'@clerk/clerk-js': minor
'@clerk/themes': minor
'@clerk/types': minor
---

Expose Clerk CSS variables as an option for theming Clerk's components. This change introduces CSS custom properties that allow developers to customize Clerk's appearance using standard CSS variables, providing a more flexible theming approach.


```css
:root {
--clerk-color-primary: #6D47FF;
--clerk-color-primary-foreground: #FFFFFF;
}
```

## Deprecated variables


| Deprecated | New |
|--------|--------|
| `colorText` | `colorForeground` |
| `colorTextOnPrimaryBackground` | `colorPrimaryForeground` |
| `colorTextSecondary` | `colorMutedForeground` |
| `spacingUnit` | `spacing` |
| `colorInputText` | `colorInputForeground` |
| `colorInputBackground` | `colorInput` |

Deprecated variables will continue to work but will be removed in the next major version.

## New variables

- `colorRing` - The color of the ring when an interactive element is focused.
- `colorMuted` - The background color for elements of lower importance, eg: a muted background.
- `colorShadow` - The base shadow color used in the components.
- `colorBorder` - The base border color used in the components.
- `colorModalBackdrop` - The background color of the modal backdrop.
8 changes: 4 additions & 4 deletions packages/clerk-js/bundlewatch.config.json
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
{
"files": [
{ "path": "./dist/clerk.js", "maxSize": "616kB" },
{ "path": "./dist/clerk.js", "maxSize": "616.27KB" },
{ "path": "./dist/clerk.browser.js", "maxSize": "72.2KB" },
{ "path": "./dist/clerk.legacy.browser.js", "maxSize": "115KB" },
{ "path": "./dist/clerk.legacy.browser.js", "maxSize": "115.08KB" },
{ "path": "./dist/clerk.headless*.js", "maxSize": "55KB" },
{ "path": "./dist/ui-common*.js", "maxSize": "111KB" },
{ "path": "./dist/ui-common*.legacy.*.js", "maxSize": "115KB" },
{ "path": "./dist/ui-common*.js", "maxSize": "111.52KB" },
{ "path": "./dist/ui-common*.legacy.*.js", "maxSize": "115.33KB" },
{ "path": "./dist/vendors*.js", "maxSize": "40.2KB" },
{ "path": "./dist/coinbase*.js", "maxSize": "38KB" },
{ "path": "./dist/stripe-vendors*.js", "maxSize": "1KB" },
Expand Down
13 changes: 7 additions & 6 deletions packages/clerk-js/sandbox/app.ts
Original file line number Diff line number Diff line change
Expand Up @@ -156,16 +156,17 @@ function appearanceVariableOptions() {
'colorPrimary',
'colorNeutral',
'colorBackground',
'colorTextOnPrimaryBackground',
'colorPrimaryForeground',
'colorForeground',
'colorDanger',
'colorSuccess',
'colorWarning',
'colorText',
'colorTextSecondary',
'colorInputText',
'colorInputBackground',
'colorForeground',
'colorMutedForeground',
'colorInputForeground',
'colorInput',
'colorShimmer',
'spacingUnit',
'spacing',
'borderRadius',
] as const;

Expand Down
24 changes: 12 additions & 12 deletions packages/clerk-js/sandbox/template.html
Original file line number Diff line number Diff line change
Expand Up @@ -216,11 +216,11 @@
/>
</label>
<label class="flex items-center justify-between border-t border-gray-100 py-2">
<span class="font-mono text-xs">colorTextOnPrimaryBackground</span>
<span class="font-mono text-xs">colorPrimaryForeground</span>
<input
class="border border-gray-200"
type="color"
id="colorTextOnPrimaryBackground"
id="colorPrimaryForeground"
value="#ffffff"
/>
</label>
Expand Down Expand Up @@ -252,38 +252,38 @@
/>
</label>
<label class="flex items-center justify-between border-t border-gray-100 py-2">
<span class="font-mono text-xs">colorText</span>
<span class="font-mono text-xs">colorForeground</span>
<input
class="border border-gray-200"
type="color"
id="colorText"
id="colorForeground"
value="#212126"
/>
</label>
<label class="flex items-center justify-between border-t border-gray-100 py-2">
<span class="font-mono text-xs">colorTextSecondary</span>
<span class="font-mono text-xs">colorMutedForeground</span>
<input
class="border border-gray-200"
type="color"
id="colorTextSecondary"
id="colorMutedForeground"
value="#747686"
/>
</label>
<label class="flex items-center justify-between border-t border-gray-100 py-2">
<span class="font-mono text-xs">colorInputText</span>
<span class="font-mono text-xs">colorInputForeground</span>
<input
class="border border-gray-200"
type="color"
id="colorInputText"
id="colorInputForeground"
value="#000000"
/>
</label>
<label class="flex items-center justify-between border-t border-gray-100 py-2">
<span class="font-mono text-xs">colorInputBackground</span>
<span class="font-mono text-xs">colorInput</span>
<input
class="border border-gray-200"
type="color"
id="colorInputBackground"
id="colorInput"
value="#ffffff"
/>
</label>
Expand All @@ -297,10 +297,10 @@
/>
</label>
<label class="flex items-center justify-between border-t border-gray-100 py-2">
<span class="font-mono text-xs">spacingUnit</span>
<span class="font-mono text-xs">spacing</span>
<input
type="text"
id="spacingUnit"
id="spacing"
value="1rem"
class="text-sm outline-none [field-sizing:content]"
/>
Expand Down
2 changes: 1 addition & 1 deletion packages/clerk-js/src/ui/common/ProviderInitialIcon.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ export const ProviderInitialIcon = (props: ProviderInitialIconProps) => {
width: t.space.$4,
height: t.space.$4,
borderRadius: t.radii.$sm,
color: t.colors.$colorTextOnPrimaryBackground,
color: t.colors.$colorPrimaryForeground,
backgroundColor: t.colors.$primary500,
})}
{...rest}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,7 @@ const SecretInputWithToggle = ({ apiKeyID }: { apiKeyID: string }) => {
>
<Icon
icon={revealed ? EyeSlash : Eye}
sx={t => ({ color: t.colors.$colorTextSecondary })}
sx={t => ({ color: t.colors.$colorMutedForeground })}
/>
</Button>
</Flex>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,7 @@ const ExpirationSelector: React.FC<ExpirationSelectorProps> = ({ selectedExpirat
<SelectOptionList
sx={t => ({
paddingBlock: t.space.$1,
color: t.colors.$colorText,
color: t.colors.$colorForeground,
})}
/>
</Select>
Expand Down Expand Up @@ -236,7 +236,7 @@ export const CreateApiKeyForm: React.FC<CreateApiKeyFormProps> = ({ onCreate, is
sx={t => ({
borderTopWidth: t.borderWidths.$normal,
borderTopStyle: t.borderStyles.$solid,
borderTopColor: t.colors.$neutralAlpha100,
borderTopColor: t.colors.$borderAlpha100,
paddingTop: t.space.$4,
paddingBottom: t.space.$4,
})}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -246,7 +246,7 @@ export const CheckoutComplete = () => {
borderRadius: t.radii.$circle,
backgroundImage: `linear-gradient(180deg, rgba(255, 255, 255, 0.30) 0%, rgba(0, 0, 0, 0.12) 50%, rgba(0, 0, 0, 0.30) 95.31%)`,
boxShadow: '0px 4px 12px 0px rgba(0, 0, 0, 0.35), 0px 1px 0px 0px rgba(255, 255, 255, 0.05) inset',
color: canHover ? t.colors.$success500 : t.colors.$colorText,
color: canHover ? t.colors.$success500 : t.colors.$colorForeground,
':before': {
content: '""',
position: 'absolute',
Expand Down Expand Up @@ -320,7 +320,7 @@ export const CheckoutComplete = () => {
animationDuration: `${transitionDurationValues.slowest}ms`,
animationTimingFunction: transitionTiming.bezier,
animationFillMode: 'forwards',
color: t.colors.$colorText,
color: t.colors.$colorForeground,
'@keyframes slideUp': {
'0%': {
transform: 'translateY(30px)',
Expand Down
6 changes: 3 additions & 3 deletions packages/clerk-js/src/ui/components/Checkout/CheckoutForm.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ export const CheckoutForm = withCardStateProvider(() => {
padding: t.space.$4,
borderBottomWidth: t.borderWidths.$normal,
borderBottomStyle: t.borderStyles.$solid,
borderBottomColor: t.colors.$neutralAlpha100,
borderBottomColor: t.colors.$borderAlpha100,
})}
>
<LineItems.Root>
Expand Down Expand Up @@ -230,7 +230,7 @@ export const PayWithTestPaymentSource = () => {
borderRadius: t.radii.$md,
borderWidth: t.borderWidths.$normal,
borderStyle: t.borderStyles.$solid,
borderColor: t.colors.$neutralAlpha100,
borderColor: t.colors.$borderAlpha100,
display: 'flex',
flexDirection: 'column',
rowGap: t.space.$2,
Expand Down Expand Up @@ -375,7 +375,7 @@ const ExistingPaymentSourceForm = withCardStateProvider(
<SelectOptionList
sx={t => ({
paddingBlock: t.space.$1,
color: t.colors.$colorText,
color: t.colors.$colorForeground,
})}
/>
</Select>
Expand Down
2 changes: 1 addition & 1 deletion packages/clerk-js/src/ui/components/Checkout/parts.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ export const InvalidPlanScreen = () => {
padding: t.space.$4,
borderBottomWidth: t.borderWidths.$normal,
borderBottomStyle: t.borderStyles.$solid,
borderBottomColor: t.colors.$neutralAlpha100,
borderBottomColor: t.colors.$borderAlpha100,
})}
>
<LineItems.Root>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -162,7 +162,7 @@ export const CreateOrganizationForm = withCardStateProvider((props: CreateOrgani
size='md'
icon={Upload}
sx={t => ({
color: t.colors.$colorTextSecondary,
color: t.colors.$colorMutedForeground,
transitionDuration: t.transitionDuration.$controls,
})}
/>
Expand All @@ -173,7 +173,7 @@ export const CreateOrganizationForm = withCardStateProvider((props: CreateOrgani
borderRadius: t.radii.$md,
borderWidth: t.borderWidths.$normal,
borderStyle: t.borderStyles.$dashed,
borderColor: t.colors.$neutralAlpha200,
borderColor: t.colors.$borderAlpha200,
backgroundColor: t.colors.$neutralAlpha50,
':hover': {
backgroundColor: t.colors.$neutralAlpha50,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,7 @@ export function OAuthConsentInternal() {
textAlign: 'left',
borderWidth: t.borderWidths.$normal,
borderStyle: t.borderStyles.$solid,
borderColor: t.colors.$neutralAlpha100,
borderColor: t.colors.$borderAlpha100,
borderRadius: t.radii.$lg,
overflow: 'hidden',
})}
Expand Down Expand Up @@ -146,13 +146,13 @@ export function OAuthConsentInternal() {
paddingBlock: t.space.$2,
borderTopWidth: t.borderWidths.$normal,
borderTopStyle: t.borderStyles.$solid,
borderTopColor: t.colors.$neutralAlpha100,
borderTopColor: t.colors.$borderAlpha100,
'&::before': {
content: '""',
display: 'inline-block',
width: t.space.$1,
height: t.space.$1,
background: t.colors.$colorTextSecondary,
background: t.colors.$colorMutedForeground,
borderRadius: t.radii.$circle,
transform: 'translateY(-0.1875rem)',
marginRight: t.space.$2,
Expand Down Expand Up @@ -340,7 +340,7 @@ function ConnectionIcon({ size = 'md', sx }: { size?: 'sm' | 'md'; sx?: Themable
borderRadius: t.radii.$circle,
borderWidth: t.borderWidths.$normal,
borderStyle: t.borderStyles.$solid,
borderColor: t.colors.$neutralAlpha100,
borderColor: t.colors.$borderAlpha100,
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
Expand Down Expand Up @@ -369,7 +369,7 @@ function ConnectionSeparator() {
height={2}
aria-hidden
sx={t => ({
color: t.colors.$colorTextSecondary,
color: t.colors.$colorMutedForeground,
})}
>
<path
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ const CreateOrganizationButton = ({
sx={t => ({
borderTopWidth: t.borderWidths.$normal,
borderTopStyle: t.borderStyles.$solid,
borderTopColor: t.colors.$neutralAlpha100,
borderTopColor: t.colors.$borderAlpha100,
padding: `${t.space.$5} ${t.space.$5}`,
})}
iconSx={t => ({
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ export const PreviewListItems = (props: PropsWithChildren) => {
overflowY: 'auto',
borderTopWidth: t.borderWidths.$normal,
borderTopStyle: t.borderStyles.$solid,
borderTopColor: t.colors.$neutralAlpha100,
borderTopColor: t.colors.$borderAlpha100,
...common.unstyledScrollbar(t),
})}
>
Expand All @@ -33,9 +33,9 @@ const sharedStyles: ThemableCssProp = t => ({
});

export const sharedMainIdentifierSx: ThemableCssProp = t => ({
color: t.colors.$colorText,
color: t.colors.$colorForeground,
':hover': {
color: t.colors.$colorText,
color: t.colors.$colorForeground,
},
});

Expand All @@ -54,7 +54,7 @@ export const PreviewListItem = (
justifyContent: 'space-between',
borderTopWidth: t.borderWidths.$normal,
borderTopStyle: t.borderStyles.$solid,
borderTopColor: t.colors.$neutralAlpha100,
borderTopColor: t.colors.$borderAlpha100,
}),
sharedStyles,
]}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -193,7 +193,7 @@ export const RoleSelect = (props: {
sx={
triggerSx ||
(t => ({
color: t.colors.$colorText,
color: t.colors.$colorForeground,
backgroundColor: 'transparent',
textWrap: 'nowrap',
}))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ const OrganizationBillingPageInternal = withCardStateProvider(() => {
return (
<Col
elementDescriptor={descriptors.page}
sx={t => ({ gap: t.space.$8, color: t.colors.$colorText })}
sx={t => ({ gap: t.space.$8, color: t.colors.$colorForeground })}
>
<Col
elementDescriptor={descriptors.profilePage}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ export const OrganizationMembersTabInvitations = withCardStateProvider(() => {
paddingRight: t.space.$1,
borderBottomWidth: t.borderWidths.$normal,
borderBottomStyle: t.borderStyles.$solid,
borderBottomColor: t.colors.$neutralAlpha100,
borderBottomColor: t.colors.$borderAlpha100,
[mqu.md]: {
flexDirection: 'column',
gap: t.space.$2,
Expand Down Expand Up @@ -73,7 +73,7 @@ export const OrganizationMembersTabInvitations = withCardStateProvider(() => {
)}
sx={t => ({
paddingLeft: t.space.$10,
color: t.colors.$colorTextSecondary,
color: t.colors.$colorMutedForeground,
[mqu.md]: {
paddingLeft: 0,
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ export const OrganizationMembersTabRequests = () => {
paddingRight: t.space.$1,
borderBottomWidth: t.borderWidths.$normal,
borderBottomStyle: t.borderStyles.$solid,
borderBottomColor: t.colors.$neutralAlpha100,
borderBottomColor: t.colors.$borderAlpha100,
[mqu.md]: {
flexDirection: 'column',
gap: t.space.$2,
Expand Down Expand Up @@ -72,7 +72,7 @@ export const OrganizationMembersTabRequests = () => {
)}
sx={t => ({
paddingLeft: t.space.$10,
color: t.colors.$colorTextSecondary,
color: t.colors.$colorMutedForeground,
[mqu.md]: {
paddingLeft: 0,
},
Expand Down
Loading
Loading