Browse
Archive
15
posts
- The Rosetta Stone of AI BS Mar 11, 2026
- ATS Tried to automate hiring, but got automated back Mar 03, 2026
- Learning RAG while benchmarking it Feb 17, 2026
- I Let an AI Interview Me, Then Data-Analyzed My Own Answers Feb 9, 2026
- How I discovered something interesting about ATS... Jan 25, 2026
- Me, Claude vs jsPDF - The Saga Jan 20, 2026
- 2KB to 2GB: Why Embedded Systems Engineers Will Dominate Jan 11, 2026
- All roads lead to Rome, yet my passport is empty. Jan 10, 2026
- Architecture Before Syntax: The Theme-Aware Chart.js Jan 9, 2026
- What Would AI Invent If We Started from Assembly? Jan 8, 2026
- Taming Gemini Costs & Coding with AI Jan 6, 2026
- Building Production SEO in a 29MB Binary Dec 30, 2025
- Why I built this website, its tech stack and approach Dec 30, 2025
- The Scorer Paradox: A Pragmatic Guide to Beating the ATS Dec 11, 2025
- Why I am Skeptical of AGI, but you should use AI Dec 12, 2025
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.