Architecture Before Syntax: The Theme-Aware Chart.js
I recently added a dashboard to this site, felt pretty good about it, and then clicked the "Dark Mode" toggle. The entire interface went smooth black, but the charts stayed blindingly white. It looked like trash. It was honestly jarring.
The problem is that Chart.js renders to an HTML5 Canvas. Unlike a <div>, a canvas is a bitmap. It doesn't give a damn about your CSS media queries once it draws those pixels. If you want it to change color, you have to wipe it and paint it again.
The Architecture
To make this seamless, we need to connect our CSS variables to the JavaScript engine. We don't want to hardcode colors in JS, because then we have to maintain them in two places.
Step 1: The CSS (The Buckets)
Think of CSS variables like buckets of paint with labels. You don't paint your wall "Blue". You paint it "Primary Color".
When the sun is out (Light Mode), the bucket labeled "Primary" is filled with dark blue paint. When you switch to Dark Mode, you empty that bucket and fill it with neon blue paint. The label stays the same, but the paint changes.
Here is exactly how you set this up in your CSS file.
/* Light Mode (The Default) */
:root {
--text-primary: #2d2d2d; /* Dark text */
--grid-lines: #e5e5e5; /* Light gray */
--chart-accent: #4f46e5; /* Indigo */
}
/* Dark Mode (The Override) */
[data-theme="dark"] {
--text-primary: #e5e5e5; /* White text */
--grid-lines: #404040; /* Dark gray */
--chart-accent: #8ab4f8; /* Light Blue */
}
Step 2: The Logic (The Painter)
Now we need a script that reads those buckets. We use getComputedStyle to fetch the current color directly from the DOM, then we destroy the old chart and paint a new one.
(function() {
let chartInstance = null;
// Helper: Reads the actual CSS variable value from the DOM
function getVar(name) {
return getComputedStyle(document.documentElement).getPropertyValue(name).trim();
}
function initChart() {
// 1. Cleanup
if (chartInstance) chartInstance.destroy();
// 2. Read 'Truth' from CSS
const colors = {
text: getVar('--text-primary'),
grid: getVar('--border-primary'),
accent: getVar('--accent')
};
const ctx = document.getElementById('YOUR-UNIQUE-ID');
if (!ctx) return;
// 3. Rebuild
chartInstance = new Chart(ctx, {
type: 'bar',
data: { /* ... */ },
options: {
scales: {
x: { ticks: { color: colors.text } },
y: { grid: { color: colors.grid } }
}
}
});
}
// 4. Listen for the global event
document.addEventListener('themeChanged', initChart);
initChart();
})();
The Result
Use the toggle button below. It calls my site's native theme function, and you'll see the chart update instantly to match the rest of the page.
Live Interaction
Fig 1. A chart that reads CSS variables directly from the DOM.
Key Takeaways
Don't Hardcode: Never write hex codes in JS. Use
getComputedStyleto read what CSS is already doing.Unique IDs: Every canvas needs a unique ID or they will overwrite each other in the DOM.
Event Listeners: The chart won't know the theme changed unless you listen for the event.