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);
}

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;
}

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;
}

2.4 Third-Party Libraries

Some libraries provide out-of-the-box dark mode support:

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');
}

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');
  }
}

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');

4. Best Practices for Dark Mode

4.1 Avoid Pure Black Backgrounds

4.2 Maintain Proper Contrast

4.3 Handle Images and Icons

4.4 Smooth Transitions

body {
  transition: background-color 0.3s ease, color 0.3s ease;
}

4.5 Respect System Preferences

4.6 Accessibility Considerations

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

@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);
  }
}

5.2 Component-Level Theme Awareness

5.3 Theming for Third-Party Components

6. Performance Considerations

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);
}

7. Testing Dark Mode

Testing is critical to ensure a polished experience.

7.1 Manual Testing

7.2 Automated Visual Regression Testing

7.3 Accessibility Testing

8. Real-World Examples

8.1 Angular Material Dashboard

8.2 E-Commerce Platform

8.3 Marketing Websites

9. Challenges in Dark Mode Implementation

  1. Legacy Components – Older UI libraries may not support dark mode

  2. Third-Party Widgets – May require overrides or custom theming

  3. Content with Fixed Colors – Images, videos, and charts may clash

  4. Performance – Switching themes on large DOM trees can cause lag

  5. Accessibility – Incorrect contrast or focus styles can harm usability

10. Future of Dark Mode

In 2025, dark mode is no longer optional; it is expected by users and enterprises alike.

Best Practices for Senior Developers

  1. Use CSS variables or Angular Material themes for maintainability

  2. Respect user preferences and system settings

  3. Ensure accessibility compliance

  4. Optimize performance to prevent FOUC and DOM recalculations

  5. Test thoroughly, including visual and accessibility testing

  6. Consider component-level and app-wide architecture for scalability

  7. Handle third-party libraries and custom assets correctly

  8. Persist user preferences using local storage or backend settings

  9. Offer smooth transitions between light and dark themes

  10. 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.