Panda & @radix-ui/themes #2095
Replies: 5 comments 7 replies
-
|
Here are some projects that provide a Radix preset for Panda https://github.com/milandekruijf/pandacss-preset-radix-colors You can also take a look at https://park-ui.com/ for some inspiration |
Beta Was this translation helpful? Give feedback.
-
|
@segunadebayo Thank you for the suggestions. From what I can see those packages are a bit different that what I'm asking about specifically. One thing to note that isn't obvious to everyone; Radix Themes is different from Radix Primitives and Radix Colors. One of the exports from Radix Themes is a pre bundled styles.css with many (hundreds? thousands?) of tokens defined. Here's an example of what I see as the primary issue, but I'm so new to panda, I was hoping this preset existed :)
// I'm using colors as an example here.
export const colors = {
"tomato-1": { value: "var(--tomato-1)" },
// ...
}; |
Beta Was this translation helpful? Give feedback.
-
|
Perhaps another approach to this discussion would be something like this: What is the best way to consume existing css vars / tokens while making them available to the panda system? |
Beta Was this translation helpful? Give feedback.
-
|
I was looking for the same as found this one for Tailwind and adapted it here: import type { Preset } from "@pandacss/dev";
import { definePreset } from "@pandacss/dev";
const colorScale = 12;
const radixColors = [
"tomato",
"red",
"ruby",
"crimson",
"pink",
"plum",
"purple",
"violet",
"iris",
"indigo",
"blue",
"cyan",
"teal",
"jade",
"green",
"grass",
"bronze",
"gold",
"brown",
"orange",
"amber",
"yellow",
"lime",
"mint",
"sky",
];
const radixGrayColors = ["gray", "mauve", "slate", "sage", "olive", "sand"];
const getColor = (color: string, scale: number, alpha?: boolean) => {
const colors = Array.from(Array(scale).keys()).reduce(
(acc, _, i) => {
acc[i + 1] = { value: `var(--${color}-${alpha ? "a" : ""}${i + 1})` };
return acc;
},
{} as Record<number | string, { value: string }>,
) as Record<string | number, { value: string }>;
if (!alpha) {
colors["contrast"] = { value: `var(--${color}-contrast)` };
colors["surface"] = {
value:
color === "accent"
? "var(--accent-surface)"
: `var(--${color}-surface)`,
};
}
return colors;
};
const getGrayColor = (color: string, scale: number, alpha?: boolean) => {
const colors = Array.from(Array(scale).keys()).reduce(
(acc, _, i) => {
acc[i + 1] = { value: `var(--${color}-${alpha ? "a" : ""}${i + 1})` };
return acc;
},
{} as Record<number | string, { value: string }>,
) as Record<string | number, { value: string }>;
return colors;
};
const getColors = (arr: string[], isGray?: boolean) => {
const colors = arr.reduce(
(acc, color) => {
acc[color] = isGray
? getGrayColor(color, colorScale, false)
: getColor(color, colorScale, false);
return acc;
},
{} as Record<string, Record<number | string, { value: string }>>,
);
const alphaColors = arr.reduce(
(acc, color) => {
acc[color + "A"] = isGray
? getGrayColor(color, colorScale, true)
: getColor(color, colorScale, true);
return acc;
},
{} as Record<string, Record<number | string, { value: string }>>,
);
return { ...colors, ...alphaColors };
};
export function radixPreset(): Preset {
return definePreset({
theme: {
extend: {
breakpoints: {
xs: "520px",
sm: "768px",
md: "1024px",
lg: "1280px",
xl: "1640px",
},
tokens: {
radii: {
1: { value: "var(--radius-1)" },
2: { value: "var(--radius-2)" },
3: { value: "var(--radius-3)" },
4: { value: "var(--radius-4)" },
5: { value: "var(--radius-5)" },
6: { value: "var(--radius-6)" },
item: { value: "max(var(--radius-2),var(--radius-full))" },
full: { value: "9999px" },
},
shadows: {
1: { value: "var(--shadow-1)" },
2: { value: "var(--shadow-2)" },
3: { value: "var(--shadow-3)" },
4: { value: "var(--shadow-4)" },
5: { value: "var(--shadow-5)" },
6: { value: "var(--shadow-6)" },
},
fontSizes: {
1: { value: "var(--font-size-1)" },
2: { value: "var(--font-size-2)" },
3: { value: "var(--font-size-3)" },
4: { value: "var(--font-size-4)" },
5: { value: "var(--font-size-5)" },
6: { value: "var(--font-size-6)" },
7: { value: "var(--font-size-7)" },
8: { value: "var(--font-size-8)" },
9: { value: "var(--font-size-9)" },
},
fontWeights: {
light: { value: "300" },
regular: { value: "400" },
medium: { value: "500" },
bold: { value: "700" },
},
lineHeights: {
1: { value: "var(--line-height-1)" },
2: { value: "var(--line-height-2)" },
3: { value: "var(--line-height-3)" },
4: { value: "var(--line-height-4)" },
5: { value: "var(--line-height-5)" },
6: { value: "var(--line-height-6)" },
7: { value: "var(--line-height-7)" },
8: { value: "var(--line-height-8)" },
9: { value: "var(--line-height-9)" },
},
letterSpacings: {
1: { value: "var(--letter-spacing-1)" },
2: { value: "var(--letter-spacing-2)" },
3: { value: "var(--letter-spacing-3)" },
4: { value: "var(--letter-spacing-4)" },
5: { value: "var(--letter-spacing-5)" },
6: { value: "var(--letter-spacing-6)" },
7: { value: "var(--letter-spacing-7)" },
8: { value: "var(--letter-spacing-8)" },
9: { value: "var(--letter-spacing-9)" },
},
spacing: {
"rx-1": { value: "var(--space-1)" },
"rx-2": { value: "var(--space-2)" },
"rx-3": { value: "var(--space-3)" },
"rx-4": { value: "var(--space-4)" },
"rx-5": { value: "var(--space-5)" },
"rx-6": { value: "var(--space-6)" },
"rx-7": { value: "var(--space-7)" },
"rx-8": { value: "var(--space-8)" },
"rx-9": { value: "var(--space-9)" },
},
},
semanticTokens: {
colors: {
accent: { value: getColor("accent", colorScale) },
accentA: { value: getColor("accent", colorScale, true) },
...getColors(radixGrayColors, true),
gray: { value: getGrayColor("gray", colorScale) },
...getColors(radixColors),
whiteA: { value: getColor("white", colorScale, true) },
blackA: { value: getColor("black", colorScale, true) },
overlay: { value: "var(--color-overlay)" },
"panel-solid": { value: "var(--color-panel-solid)" },
"panel-translucent": { value: "var(--color-panel-translucent)" },
surface: { value: "var(--color-surface)" },
panel: { value: "var(--color-panel)" },
transparent: { value: "transparent" },
},
},
},
},
});
}First time using Panda, so maybe some stuff is wrong (there was, fixed thanks to @segunadebayo) |
Beta Was this translation helpful? Give feedback.
-
|
I did some digging into this myself recently and my conclusion is the design of both Radix's css var token theme and how Panda renders tokens are fundamentally incompatible with each other (as of October 6, 2025). When you define a Panda token Panda will 'wrap' this token definition, e.g.: defineTokens({
radii: {
6: { value: 'var(--radius-6)' },
},
});...becomes... :where(:root, :host) {
/* ...snip... */
--radii-6: var(--radius-6);
}And then when you use THE PROBLEM is that 'nested' CSS Variables are not dynamically re-evaluated in the cascade, whatever value that is in the 'parent' css variable (e.g. UNFORTUNATELY Radix UI has a very pleasing and dynamic theme system that relies on cascades to control values and only the light-themed color tokens have a definition at :root, .light-theme {
--color-red: ...;
}
.dark-theme {
--color-red: ...;
}
[data-radius] {
--radius-factor: ...;
--radius-1: ...;
}
[data-radius="small"] {
--radius-factor: ...;
}You'll notice above that the It does not matter if the style is used in a component that is a descendent of I haven't tested it explicitly but I'd be willing bet dollars to donuts while referencing the color CSS variables "work" if you try to swap to dark mode via Radix's recommended methods, the colors will not swap correctly. TLDR If you're using PandaCSS (as it is designed today) with another component library or design system you unfortunately cannot use Panda's tokens system unless said system does not use any form of CSS variable cascading. You must use the css vars directly. |
Beta Was this translation helpful? Give feedback.

Uh oh!
There was an error while loading. Please reload this page.
-
I'm just getting started looking into pandacss. For those more familiar with the project, I'm curious how difficult you think it would be to port the @radixui/themes tokens and utilities to panda?
I'd like to build my component library utilizing radix themes, while being able to write my component library css and application css utilizing panda's toolchain.
Beta Was this translation helpful? Give feedback.
All reactions