A Senior Developer’s Guide to Building Dark Mode in Modern Web Applications with Angular.
Dark mode has evolved from a niche preference to an expected feature in modern web and mobile applications. In 2025, users increasingly expect interfaces that can adapt to low-light environments or personal preferences, while enterprises want consistency across products.
For senior developers, implementing dark mode is not just about flipping colors. It requires careful planning, architecture-level decisions, performance optimisation, accessibility compliance, and user experience considerations. This article explores how to implement dark mode effectively in modern web applications, with a focus on Angular-based projects and real-world best practices.
1. Why Dark Mode Matters
1.1 User Experience
Dark mode improves usability in low-light conditions, reduces eye strain, and offers a modern, visually appealing interface. Users often prefer dark mode when using devices at night or in dimly lit environments.
1.2 Energy Efficiency
On OLED and AMOLED screens, dark mode reduces power consumption because black pixels are turned off, which can extend battery life for mobile devices.
1.3 Brand and Design Consistency
Many popular applications now offer dark mode, and users expect a consistent experience across platforms. Enterprises benefit from consistent theming across their web apps, mobile apps, and internal dashboards.
1.4 Accessibility
Dark mode can enhance readability for users with visual impairments, but it must be implemented thoughtfully to maintain contrast and avoid fatigue.
2. Approaches to Dark Mode Implementation
Dark mode implementation is not one-size-fits-all. The approach depends on application architecture, frameworks, and user experience goals.
2.1 CSS Variables (Recommended)
Using CSS custom properties (variables) is the most flexible approach. You define color variables in a global stylesheet and switch them dynamically for light and dark themes.
:root {
--primary-bg: #ffffff;
--primary-text: #111111;
}
[data-theme="dark"] {
--primary-bg: #121212;
--primary-text: #e0e0e0;
}
body {
background-color: var(--primary-bg);
color: var(--primary-text);
}
Benefits: Easy to maintain, supports dynamic switching, reduces duplication
Works well with Angular’s global styles and component styles
2.2 Class-Based Theming
Another approach is toggling a class on the root element (e.g., dark-mode) and styling components accordingly.
body.dark-mode {
background-color: #121212;
color: #e0e0e0;
}
Simple to implement for smaller apps
Less scalable for large applications with many components
2.3 Component-Level Theming
For complex Angular apps, component-level theming allows individual modules to define their own dark mode styles.
Example
@Component({
selector: 'app-card',
templateUrl: './card.component.html',
styleUrls: ['./card.component.scss'],
host: { '[class.dark-mode]': 'isDarkMode' }
})
export class CardComponent {
@Input() isDarkMode = false;
}
Provides granular control
Useful in modular or multi-tenant applications
2.4 Third-Party Libraries
Some libraries provide out-of-the-box dark mode support:
Angular Material: Built-in theming with light and dark palettes
TailwindCSS: Supports
dark:variants with a single configuration flagNgx-dark-mode: Angular utility library for theme switching
3. Dark Mode in Angular
Angular provides multiple strategies to implement dark mode effectively:
3.1 Angular Material Theming
Angular Material supports dark mode natively through predefined palettes:
import { OverlayContainer } from '@angular/cdk/overlay';
...
toggleDarkMode(isDark: boolean) {
const overlayContainerClasses = this.overlayContainer.getContainerElement().classList;
if (isDark) overlayContainerClasses.add('dark-theme');
else overlayContainerClasses.remove('dark-theme');
}
Use SCSS theming for global and component-specific styles
Supports
mat-toolbar,mat-card,mat-buttontheming out-of-the-box
3.2 Using CSS Variables in Angular
With Angular 15+ and component-scoped styles, you can implement theme switching at runtime:
@Injectable({ providedIn: 'root' })
export class ThemeService {
setTheme(isDark: boolean) {
document.documentElement.setAttribute('data-theme', isDark ? 'dark' : 'light');
}
}
Combine with local storage or user preferences to persist the theme across sessions
3.3 Persisting User Preferences
Use local storage, cookies, or backend user settings to remember the preferred theme:
const theme = localStorage.getItem('theme') || 'light';
document.documentElement.setAttribute('data-theme', theme);
function toggleTheme() {
const current = document.documentElement.getAttribute('data-theme');
const next = current === 'dark' ? 'light' : 'dark';
document.documentElement.setAttribute('data-theme', next);
localStorage.setItem('theme', next);
}
3.4 Automatic Dark Mode Detection
You can detect system-level dark mode preferences using media queries:
const prefersDark = window.matchMedia('(prefers-color-scheme: dark)').matches;
document.documentElement.setAttribute('data-theme', prefersDark ? 'dark' : 'light');
Useful for improving user experience without explicit toggles
Works in combination with manual overrides
4. Best Practices for Dark Mode
4.1 Avoid Pure Black Backgrounds
Use dark greys (
#121212,#1e1e1e) instead of#000000Pure black can increase eye strain and reduce readability
4.2 Maintain Proper Contrast
Text must maintain WCAG AA or AAA contrast ratios
Use tools like Contrast Checker to validate text against background
4.3 Handle Images and Icons
Use adaptive assets: SVGs with dynamic fill or dual light/dark versions
Avoid images with fixed light backgrounds that clash with dark mode
4.4 Smooth Transitions
Use CSS transitions for theme switching:
body {
transition: background-color 0.3s ease, color 0.3s ease;
}
Improves perceived quality and user experience
4.5 Respect System Preferences
Offer automatic dark mode detection
Allow users to manually override
4.6 Accessibility Considerations
Ensure form inputs, focus states, and buttons are clearly visible
Avoid using color alone to convey information
Test with screen readers and high-contrast modes
5. Dark Mode Architecture in Large Applications
For enterprise-grade applications, dark mode should be treated as a first-class feature, not an afterthought.
5.1 Centralised Theme Management
Create a ThemeService to handle switching and persistence
Broadcast theme changes using RxJS BehaviorSubject:
@Injectable({ providedIn: 'root' })
export class ThemeService {
private themeSubject = new BehaviorSubject<'light' | 'dark'>('light');
theme$ = this.themeSubject.asObservable();
toggleTheme() {
const next = this.themeSubject.value === 'dark' ? 'light' : 'dark';
this.themeSubject.next(next);
document.documentElement.setAttribute('data-theme', next);
}
}
Components can subscribe to
theme$for dynamic styling
5.2 Component-Level Theme Awareness
Angular components should respect the central theme state
Use host bindings or CSS variables to dynamically apply theme styles
5.3 Theming for Third-Party Components
Angular Material, PrimeNG, or Kendo UI often support dark mode, but verify component overrides
Custom CSS may be needed for consistent experience
6. Performance Considerations
Preload critical CSS variables to avoid flash of unstyled content (FOUC)
Minimise recalculation of styles on theme switch
Avoid heavy DOM manipulations during theme toggling
Example: Using CSS variables avoids recalculating every element style:
:root {
--bg-color: #ffffff;
--text-color: #111111;
}
[data-theme="dark"] {
--bg-color: #121212;
--text-color: #e0e0e0;
}
body {
background-color: var(--bg-color);
color: var(--text-color);
}
Angular’s change detection does not need to rerun for theme switching
7. Testing Dark Mode
Testing is critical to ensure a polished experience.
7.1 Manual Testing
Check readability, contrast, and UX
Test in various lighting conditions and devices
7.2 Automated Visual Regression Testing
Use tools like Percy, Chromatic, or Cypress
Compare screenshots in light and dark modes for unexpected changes
7.3 Accessibility Testing
Validate contrast ratios
Test with screen readers
Check focus indicators, keyboard navigation, and ARIA attributes
8. Real-World Examples
8.1 Angular Material Dashboard
Light and dark palettes applied via
OverlayContainerPersistent theme using local storage
Dynamic component styling for charts, tables, and cards
8.2 E-Commerce Platform
Adaptive product images with dark/light versions
Dark mode toggle in user profile
CSS variable-based theming for performance
8.3 Marketing Websites
Pre-rendered dark mode via Angular Universal
Automatic detection of system preferences
Smooth transition between themes
9. Challenges in Dark Mode Implementation
Legacy Components – Older UI libraries may not support dark mode
Third-Party Widgets – May require overrides or custom theming
Content with Fixed Colors – Images, videos, and charts may clash
Performance – Switching themes on large DOM trees can cause lag
Accessibility – Incorrect contrast or focus styles can harm usability
10. Future of Dark Mode
AI-assisted theme adaptation: Automatically adjust brightness, contrast, and colors based on environment and user preferences
Dynamic dark mode: Changes according to ambient light sensor
Cross-platform consistency: Unified theme across web, mobile, and desktop applications
Smart content adaptation: Images, charts, and icons automatically switch versions for dark mode
In 2025, dark mode is no longer optional; it is expected by users and enterprises alike.
Best Practices for Senior Developers
Use CSS variables or Angular Material themes for maintainability
Respect user preferences and system settings
Ensure accessibility compliance
Optimize performance to prevent FOUC and DOM recalculations
Test thoroughly, including visual and accessibility testing
Consider component-level and app-wide architecture for scalability
Handle third-party libraries and custom assets correctly
Persist user preferences using local storage or backend settings
Offer smooth transitions between light and dark themes
Plan for future enhancements, like AI-based or dynamic themes
Conclusion
Dark mode has evolved into a critical feature of modern web applications. Its implementation requires a combination of technical skill, thoughtful UX design, and accessibility considerations.
For Angular developers, leveraging CSS variables, Angular Material theming, signals, and component-level architecture enables maintainable, scalable, and performant dark mode implementations.
Senior developers should approach dark mode as a first-class feature, integrating it into the application architecture, CI/CD pipeline, and user experience strategy. When done correctly, dark mode not only improves usability but also elevates the overall perception of the product.
Dark mode is not just a design choice. It is a responsibility for modern web developers.

Join the conversation! Your thoughts help the community grow.