There is a very strong case to have component level tokens, the biggest reason we have found is it allows you to build more robust components when it comes to theming. With this feature we could have a bit more looser with base and semantic level tokens while the component level tokens are much stricter.
There are a couple use cases but I find the most compelling is if your semantics slightly change from theme to theme. For example, using the component Alert from Chakra-UI. The original design calls for background color to tie back to their semantic versions, success = green, critical/error = red, info = blue, and warning = yellow. In another world or another brand, the design decisions may call for the background colors all to be the same. In the current implementation of Panda that would require us to add complexity to the recipe or styling to know which theme is loaded which then in turn decreases the flexibility and increases the maintenance time any time a new theme or brand is introduced.
Ideally what this looks like today is in plain CSS:
/* base.css */
:root {
--color-bg-success: #c6f6d5;
--color-bg-neutral: #e2e8f0;
--Alert-color-bg-success: var(--colors-bg-success);
}
/* Brand-2.css */
:root {
--Alert-color-bg-success: var(--color-bg-neutral);
}
/* no matter the brand, Alert doesn't care */
.Alert {
background-color: var(--Alert-color-bg-success);
}
## Today's solution
The only way I can think of achieving this type of approach with Panda today is the following, however, I will not this feels a bit anti-pattern to Panda's recommendations today:
const theme = {
tokens: {
colors: {
green: {
200: { value: "#9AE6B4" },
},
gray: {
200: { value: "#E2E8F0" },
},
},
},
semanticTokens: {
colors: {
bg: {
success: {
value: {
base: "{colors.green.200}",
},
},
neutral: {
value: {
base: "{colors.gray.200}",
},
},
},
Alert: {
success: {
bg: {
base: "{colors.bg.success}",
},
},
},
},
},
themes: {
brand2: {
semanticTokens: {
colors: {
Alert: {
success: {
bg: {
base: "{colors.bg.neutral}",
},
},
},
},
},
},
},
};
const alert = defineRecipe({
variants: {
state: {
success: {
backgroundColor: "{colors.Alert.bg.success}",
},
},
},
});
## A proposed solution
I'm honestly not sure what the correct API might look like but based on established conventions, something might look like the following syntax
const theme = {
tokens: {
colors: {
green: {
200: { value: "#9AE6B4" },
},
gray: {
200: { value: "#E2E8F0" },
},
},
},
semanticTokens: {
colors: {
bg: {
success: {
value: {
base: "{colors.green.200}",
},
},
neutral: {
value: {
base: "{colors.gray.200}",
},
},
},
},
},
componentTokens: {
Alert: {
colors: {
success: {
bg: {
base: "{colors.bg.success}",
},
},
},
},
},
themes: {
brand2: {
componentTokens: {
Alert: {
colors: {
success: {
bg: {
base: "{colors.bg.neutral}",
},
},
},
},
},
},
},
};
const alert = defineRecipe({
variants: {
state: {
success: {
backgroundColor: "{colors.Alert.bg.success}",
},
},
},
});