Dark mode using semantic colors #10274
-
I am trying to implement dark mode using semantic color tokens instead of the ContextThis approach was outlined by the Figma team in their Config 2022 presentation titled The hardest part about building dark mode is that people think it’s easy. The basic concept is to use a single semantic token to represent a color instead two atomic tokens, one for light mode and another for dark mode. For example, a single semantic token called Here's an example of how I have been able to simplify my Hero banner which should show a different shade of blue in light vs. dark mode: <!-- Before --->
<div className="bg-primary-800 dark:bg-primary-600 text-white flex flex-col items-center py-16">
...
</div>
<!-- After --->
<div className="bg-brand text-onbrand flex flex-col items-center py-16">
...
</div Implementation ApproachMy basic implementation approach is to introduce the semantic tokens as custom utility classes in my global CSS. For example, @layer utilities {
.bg-default {
background-color: theme(colors.white);
}
.dark .bg-default {
background-color: theme(colors.neutral.900);
}
.text-default {
color: theme(colors.black);
}
.dark .text-default {
color: theme(colors.white);
}
.bg-brand {
background-color: theme(colors.primary.800);
}
.dark .bg-brand {
background-color: theme(colors.primary.600);
}
.bg-brand-hover {
background-color: theme(colors.primary.700);
}
.text-onbrand {
color: theme(colors.white);
}
.bg-brand-secondary {
background-color: theme(colors.primary.100);
}
.bg-brand-secondary-hover {
background-color: theme(colors.primary.200);
}
.text-onbrand-secondary {
color: theme(colors.primary.700);
}
.bg-default-hover {
background-color: theme(colors.neutral.900 / 5%);
}
.dark .bg-default-hover {
background-color: theme(colors.white / 5%);
}
} For the most part this is working well. I have run into only one snag so far - I don't know how to implement focus ring colors (e.g. focus:ring-primary-500) because these are implemented using CSS variables and not as straight class selectors. Would appreciate any ideas from this group. QuestionWhat do you think about the overall approach? Can you suggest any improvements or a different approach? P.S. The full source code of my POC is available here: https://github.com/nareshbhatia/tailwindcss-dark-mode-semantic-colors |
Beta Was this translation helpful? Give feedback.
Replies: 2 comments 6 replies
-
You should still be able to make ring colors like you have already done, like: @layer utilities {
.ring-brand {
--tw-ring-color: theme(colors.primary.800);
}
.dark .ring-brand {
--tw-ring-color: theme(colors.primary.600);
}
} And then in HTML: <button class="focus:ring focus:ring-brand"> |
Beta Was this translation helpful? Give feedback.
-
I would define all of my colors as CSS variables and use a parent selector just to change the values of the variables, no need to create tons of custom classes: https://tailwindcss.com/docs/customizing-colors#using-css-variables This demo is several versions behind so some things are out of date but should communicate the idea clearly at least: https://github.com/adamwathan/theming-tailwind-demo Personally I think doing dark mode this way is seductive but not as practical as you expect. Tons of situations where you end up swapping the same color in light mode for two different colors in dark mode depending on how it’s used, and then you need to come up with different names for those two colors and it quickly becomes a very big project. |
Beta Was this translation helpful? Give feedback.
I would define all of my colors as CSS variables and use a parent selector just to change the values of the variables, no need to create tons of custom classes:
https://tailwindcss.com/docs/customizing-colors#using-css-variables
This demo is several versions behind so some things are out of date but should communicate the idea clearly at least:
https://github.com/adamwathan/theming-tailwind-demo
Personally I think doing dark mode this way is seductive but not as practical as you expect. Tons of situations where you end up swapping the same color in light mode for two different colors in dark mode depending on how it’s used, and then you need to come up with different names for those two c…