From 97c6cd7efff9539d9fbec13a295c26561d887b3c Mon Sep 17 00:00:00 2001 From: Kaan Barmore-Genc Date: Thu, 10 Aug 2023 00:36:31 -0500 Subject: [PATCH] Add article about theme colors in JS --- content/img/2023-08-10.chartjs.png | 3 + ...-daisyui-tailwindcss-theme-colors-in-js.md | 132 ++++++++++++++++++ 2 files changed, 135 insertions(+) create mode 100644 content/img/2023-08-10.chartjs.png create mode 100644 content/posts/2023.08.10.react-daisyui-tailwindcss-theme-colors-in-js.md diff --git a/content/img/2023-08-10.chartjs.png b/content/img/2023-08-10.chartjs.png new file mode 100644 index 0000000..9bd5146 --- /dev/null +++ b/content/img/2023-08-10.chartjs.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:63ec23bd29d1752c8451ba2bcd85a94d3364f7771bfae52ad3a041e8038034f0 +size 37015 diff --git a/content/posts/2023.08.10.react-daisyui-tailwindcss-theme-colors-in-js.md b/content/posts/2023.08.10.react-daisyui-tailwindcss-theme-colors-in-js.md new file mode 100644 index 0000000..2bb1af3 --- /dev/null +++ b/content/posts/2023.08.10.react-daisyui-tailwindcss-theme-colors-in-js.md @@ -0,0 +1,132 @@ +--- +title: "Getting theme colors in JavaScript using React with DaisyUI and TailwindCSS" +date: 2023-08-10T00:18:27-05:00 +toc: false +images: +tags: + - web + - dev + - react +--- + +I've been building a web app using React and TailwindCSS, with DaisyUI. But +while working on it I hit a minor snag: I'm trying to use Chart.js, and Chart.js +creates a canvas to render charts. But the canvas can't pick up the CSS +variables that are defined on the page itself. That means that my charts can't +use the colors from my theme, unless I manually copy and paste the theme colors! +This is pretty bad for maintainability because if the theme colors are ever +changed, or themes are added or removed, you'll have to come back and update the +colors for the charts as well. Boo! + +Luckily, I found out that you can read CSS variables from JavaScript. So I added +this code: + +```ts +function getPropertyValue(name: string) { + return getComputedStyle(document.body).getPropertyValue(name); +} +``` + +This returns the value of any CSS variable you pass it. For example +`getPropertyValue("--tab-border")` returns `1px` for my theme! + +Next, I just looked through the CSS on the page to figure out what CSS variables +DaisyUI sets for themes. I quickly found the most important ones I needed: the +primary and secondary colors, and the colors for the text that goes on top of +them. + +```ts +const primary = getPropertyValue("--p"); +const secondary = getPropertyValue("--s"); +const primaryText = getPropertyValue("--pc"); +const secondaryText = getPropertyValue("--sc"); +``` + +This is all great! But I had one more concern: I needed a way to change these +variables and re-render components whenever the user toggles between the light +and dark themes. + +I decided to use SWR for this. SWR is mainly meant to be used to fetch data from +an API, but there's really nothing stopping you from using it for anything else. +In this case, SWR will cache all the colors in a primary place, and allow me to +re-render all the components when the colors change using its `mutate` API. +Here's how that code looks like: + +```ts +export function useThemeColor() { + const themeFetcher = useCallback(() => { + const primary = getPropertyValue("--p"); + const primaryText = getPropertyValue("--pc"); + const secondary = getPropertyValue("--s"); + const secondaryText = getPropertyValue("--sc"); + return { primary, primaryText, secondary, secondaryText }; + }, []); + + // The key "data:theme" could be anything, as long as it's unique in the app + const { data: color, mutate } = useSWR("data:theme", themeFetcher); + + return { ...color, mutate }; +} +``` + +It's very easy to use it. + +```ts +export default function Dashboard() { + const { primary, primaryContent } = useThemeColor(); + + // ... fetch the data and labels ... + + return ( + + ); +} +``` + +Here's what that looks like: + +![A screenshot of a web page. At the top there is a dark red colored button labelled "Dashboard". There is a line chart below, which uses the same dark red color as the button.](/img/2023-08-10.chartjs.png) + +To keep the colors changing whenever the user toggles the theme, you then just +have to call the `mutate` function inside your toggle button. + +```ts +export function ThemeToggle() { + const { mutate: mutateTheme } = useThemeColor(); + const [theme, setTheme] = useState("light"); + const toggleTheme = useCallback(() => { + if (theme === "dark") { + document.body.dataset.theme = "autumn"; + setTheme("light"); + } else { + document.body.dataset.theme = "forest"; + setTheme("dark"); + } + mutateTheme(); + }, [theme, mutateTheme, setTheme]); + + return ( +
+ +
+ ); +} + +``` + +Oh and that's a bonus trick for you. You can swap the DaisyUI theme by just +setting `document.body.dataset.theme`, as long as that theme is enabled in the +settings.