CSS Custom Properties
The modern approach using CSS variables that cascade through the DOM
/* Define theme variables */
:root {
--background: #ffffff;
--foreground: #1a1a2e;
--primary: #6366f1;
--card: #f8fafc;
--border: #e2e8f0;
}
/* Dark mode override */
[data-theme="dark"] {
--background: #0f0f1a;
--foreground: #f1f5f9;
--primary: #818cf8;
--card: #1e1e2e;
--border: #2e2e3e;
}
/* Apply variables */
body {
background: var(--background);
color: var(--foreground);
}
// Toggle theme attribute
function toggleTheme() {
const html = document.documentElement;
const current = html.getAttribute('data-theme');
const next = current === 'dark'
? 'light'
: 'dark';
html.setAttribute('data-theme', next);
// Persist preference
localStorage.setItem('theme', next);
}
// Current state:
document.documentElement
.getAttribute('data-theme')
// Returns: "light"
Card Component
This card responds to CSS variable changes in real-time.
Text automatically adapts to the theme using var(--foreground)
How it works:
- 1 Define color tokens as CSS custom properties on
:root - 2 Override values using attribute selectors like
[data-theme="dark"] - 3 Toggle the attribute with JavaScript to instantly cascade changes
Class Toggle Method
Traditional approach using class names to switch between themes
/* Light theme (default) */
body {
background-color: #ffffff;
color: #1a1a2e;
}
/* Dark theme class */
body.dark-mode {
background-color: #0f0f1a;
color: #f1f5f9;
}
.card {
background: #f8fafc;
border: 1px solid #e2e8f0;
}
body.dark-mode .card {
background: #1e1e2e;
border-color: #2e2e3e;
}
// Toggle dark mode class
const body = document.body;
function toggleDarkMode() {
body.classList.toggle('dark-mode');
const isDark = body.classList
.contains('dark-mode');
localStorage.setItem(
'darkMode',
isDark
);
}
// Current class list:
body.classList.toString()
// Returns: ""
<body class="">
<div class="card">
<h3>Card Title</h3>
<p>Content here</p>
</div>
</body>
<!-- DOM Inspector -->
<!-- body element: -->
<body class="">
User Profile
The .dark-mode class cascades to all child elements.
How it works:
- 1 Define default light theme styles on base selectors
- 2 Create
.dark-modeclass with override styles - 3 Use
classList.toggle()to add/remove the class
System Preference Detection
Automatically match the user's OS theme preference using media queries
/* Default light theme */
:root {
--bg: #ffffff;
--text: #1a1a2e;
}
/* Auto-detect dark preference */
@media (prefers-color-scheme: dark) {
:root {
--bg: #0f0f1a;
--text: #f1f5f9;
}
}
/* Media query status: */
/* prefers-color-scheme: light */
// Check system preference
const query = window.matchMedia(
'(prefers-color-scheme: dark)'
);
const isDark = query.matches;
// Currently: false
// Listen for changes
query.addEventListener('change', (e) => {
console.log(
'Theme changed:',
e.matches ? 'dark' : 'light'
);
});
// Query object:
{
media: "(prefers-color-scheme: dark)",
matches: false
}
Change your system theme settings to see this update automatically!
How it works:
- 1 CSS media query
prefers-color-schemedetects OS setting - 2 JavaScript
matchMedia()provides programmatic access - 3 Event listener responds to real-time OS theme changes
Live DOM Inspector
Real-time view of the document's current state
<html data-theme="light">
DOMTokenList []
#ffffff
#1a1a2e
"light"
Implementation Comparison
About This Project
This technical demonstration showcases the dark mode feature I developed during my internship with Unadat, a financial wellness portal. Working remotely throughout the pandemic, I collaborated closely with the CEO to lead the development of a comprehensive theming system.
The Experience
Through user research and A/B testing, I validated design decisions that resulted in measurable improvements in user satisfaction and engagement. I worked with design and development teams to refine the interface, streamline navigation, and ensure visual consistency while implementing responsive design principles.
Key Contributions
- Led dark mode development with customizable color schemes
- Conducted user research and A/B testing to validate decisions
- Optimized mobile UX with responsive design improvements
- Implemented smooth theme transitions and persistent preferences
- Collaborated on feature specifications and sprint planning
Design Principles
- Progressive Enhancement: Core functionality works without JS
- Mobile-First: Fully responsive with touch-optimized controls
- Accessibility: Keyboard navigation and ARIA labels
- Performance: Optimized animations and efficient DOM updates