How to Implement Dark Mode in React, Angular, and Pre-processed CSS

Table of contents
- Prerequisites
- React Setup
- Angular Setup
- Sass/LESS Setup
- Designing the Theme Structure
- Defining CSS Variables
- Framework-Specific Configurations
- Angular: Theme Service
- Sass/LESS: Variables and Mixins
- Implementing Theme Switching
- Sass/LESS Implementation: Style with Conditional Attributes
- Debugging Common Issues
- Conclusion

Implementing dark mode has become essential in modern web applications, offering users a visually appealing and comfortable experience.
Perhaps you’re working with frameworks like React and Angular or pre-processed CSS tools like Sass and LESS, the process involves a series of practical steps to achieve smooth functionality and maintainable code.
This guide will take you through setting up your project in React, Angular, or Sass/LESS and configuring the tools and dependencies needed for theming.
Let’s get started and turn your dark-mode vision into reality!
Prerequisites
Before diving into the core content of this tutorial, let’s first make sure you’re equipped with the necessary tools and frameworks. You’ll need a few things set up depending on which stack or preprocessor you’re working with. Don’t worry – we’ll walk you through each one.
Tools and Frameworks
For React:
To follow along with React, you'll need a few key tools:
Node.js
React relies on Node.js for running JavaScript outside the browser and managing packages with npm. To install it, head over to the Node.js website and download the latest version. After installation, you can verify it by running:
```bash
node -v
npm -v
```
React
We’ll be using React, of course. If you haven’t already, you can install it by setting up a new React project using the following command:
```bash
npx create-react-app my-app
```
This will scaffold out the basic project structure and install all dependencies. Navigate into your new app folder:
```bash
cd my-app
```
Text Editor
A text editor is a must. While there are many options out there, we recommend VS Code because of its excellent support for JavaScript, React, and extensions.
For Angular
If Angular is your framework of choice, you’ll need the following:
- Angular CLI: The Angular Command Line Interface (CLI) is a powerful tool for creating, building, and managing Angular applications. Install it globally by running:
```bash
npm install -g @angular/cli
```
- Node.js: Just like with React, Angular requires Node.js to manage dependencies. Follow the same steps mentioned above to install it.
Basic Angular App: Create a new Angular application by running:
```bash
ng new my-angular-app
cd my-angular-app
```
This will generate a starter Angular project that’s ready to go.
For Sass/LESS
When working with CSS preprocessors like Sass or LESS, there are a couple of things you’ll need to set up:
- Dart Sass (for Sass): Dart Sass is the reference implementation of Sass and is what we’ll be using here. Install it globally by running:
```bash
npm install -g sass
```
- LESS.js (for LESS): Alternatively, if you’re using LESS, you’ll need to install the LESS compiler:
```bash
npm install -g less
```
Again, a simple HTML file with a linked LESS file is all you need to get started.
React Setup
- Initialise a React App
To start, create a new React application. If you haven’t already, ensure Node.js is installed on your machine. Then, run the following command in your terminal:
```bash
npx create-react-app my-app
```
Replace my-app
with your desired project name. This command sets up a fully functional React app with a default folder structure and all essential dependencies.
- Install Dependencies
For theming, you can use libraries like styled-components
or Tailwind CSS
. Install them using the following commands:
For styled-components
:
```bash
npm install styled-components
```
- For Tailwind CSS, follow these steps:
- Install Tailwind via npm:
```bash
npm install -D tailwindcss postcss autoprefixer
npx tailwindcss init
```
- Configure the tailwind.config.js
file and import Tailwind into your CSS:
```css
@tailwind base;
@tailwind components;
@tailwind utilities;
```
Once these are in place, you’re ready to start styling your React components with ease.
Angular Setup
Create an Angular Project
Ensure you have the Angular CLI installed. Then, create a new project by running:
```bash
ng new my-angular-app
```
Follow the prompts to set up the project, such as adding Angular routing and choosing your preferred CSS preprocessor.
- Install Theme Libraries
Angular Material is a popular choice for UI theming. Install it with:
```bash
ng add @angular/material
```
The CLI will guide you through selecting a theme, configuring global typography, and adding animations.
For custom theming, consider importing your stylesheets or using additional libraries like ng-bootstrap
or PrimeNG
based on your project’s needs.
Sass/LESS Setup
- Install the Compiler
If you’re using Sass, install the compiler globally or locally in your project:
```bash
npm install -g sass
```
For LESS:
```bash
npm install -g less
```
- Compile Your Styles
Create your .scss
or .less
files and compile them to CSS using the following commands:
For Sass:
```bash
sass styles.scss styles.css
```
For LESS:
```bash
lessc styles.less styles.css
```
- Integrate with Your Project
Link the compiled CSS file in your project’s HTML file, or import it directly into your application. This allows you to write modular and reusable styles, streamlining your workflow.
With these steps completed, your project environment is ready, and tailored to your preferred stack.
Designing the Theme Structure
When implementing themes in a web application, designing a flexible and scalable theme structure is the first step. Let’s break down the essentials for creating a theme structure, starting with CSS variables and moving into framework-specific configurations.
CSS Variables for Themes
CSS variables are an excellent choice for managing light and dark themes because they provide a reusable, declarative way to define and switch theme properties. Here’s how you can create and organize them effectively.
Defining CSS Variables
Start by defining CSS variables for key theme properties, such as colours for the background, text, and interactive elements. Place these variables within : root
for the default theme (e.g., light) and within a custom class (e.g., .dark-theme
) for the alternate theme.
```css
/* Light Theme */
: root {
--bg-color: #ffffff;
--text-color: #000000;
--accent-color: #007bff;
}
/* Dark Theme */
.dark-theme {
--bg-color: #121212;
--text-color: #e0e0e0;
--accent-color: #bb86fc;
}
```
These variables will act as your single source of truth for theming, making updates straightforward and consistent.
Applying Variables
You can use the variables in your CSS properties by referencing them with the var()
function. This ensures your styles automatically adapt to the active theme.
```css
body {
background-color: var(--bg-color);
color: var(--text-color);
}
button {
background-color: var(--accent-color);
border: none;
color: var(--text-color);
}
```
Switching between themes becomes as simple as toggling the .dark-theme
class on the root element (e.g., <html>
or <body>
), which we’ll cover later.
Framework-Specific Configurations
When working with frameworks like React, and Angular, or preprocessors like Sass/LESS, you can take your theming strategy to the next level by incorporating dynamic logic and reusable structures.
React: Using a Theme Object
In React, you can centralize theme configurations using a dedicated theme.js
file. This file houses theme objects for light and dark themes.
```javascript
// theme.js
export const lightTheme = {
bgColor: "#ffffff",
textColor: "#000000",
accentColor: "#007bff",
};
export const darkTheme = {
bgColor: "#121212",
textColor: "#e0e0e0",
accentColor: "#bb86fc",
};
```
Use a context or state management solution to dynamically apply themes across your app. For example:
```javascript
import { useState } from "react";
import { lightTheme, darkTheme } from "./theme";
function App() {
const [theme, setTheme] = useState(lightTheme);
const toggleTheme = () => {
setTheme(theme === lightTheme ? darkTheme : lightTheme);
};
return (
<div style={{ backgroundColor: theme.bgColor, colour: theme.textColor }}>
<button onClick={toggleTheme}>Switch Theme</button>
</div>
);
}
```
This approach gives you precise control over theme behaviour and is particularly useful for component-based styling.
Angular: Theme Service
In Angular, creating a dedicated service to handle theme switching simplifies your logic. Define your themes in a JSON-like structure and use a service to toggle between them.
Theme Configuration Example:
```typescript
export const themes = {
light: {
"--bg-color": "#ffffff",
"--text-color": "#000000",
"--accent-color": "#007bff",
},
dark: {
"--bg-color": "#121212",
"--text-color": "#e0e0e0",
"--accent-color": "#bb86fc",
},
};
```
Theme Service Example:
```typescript
import { Injectable } from '@angular/core';
import { themes } from './themes';
@Injectable({ providedIn: 'root' })
export class ThemeService {
applyTheme(theme: string) {
const themeProperties = themes[theme];
for (const key in themeProperties) {
document.documentElement.style.setProperty(key, themeProperties[key]);
}
}
}
```
In your component, call the service method to switch themes:
```typescript
this.themeService.applyTheme('dark');
```
Sass/LESS: Variables and Mixins
Sass and LESS preprocessors allow you to define variables and mixins for themes, offering more flexibility for advanced designs.
Sass Example
```scss
$light-theme: (
bg-color: #ffffff,
text-color: #000000,
accent-color: #007bff,
);
$dark-theme: (
bg-color: #121212,
text-color: #e0e0e0,
accent-color: #bb86fc,
);
@mixin theme($theme) {
background-color: map-get($theme, bg-color);
color: map-get($theme, text-color);
}
body {
@include theme($light-theme);
}
.dark-theme {
@include theme($dark-theme);
}
```
Switching themes dynamically requires additional configuration using JavaScript to apply classes or variables.
Implementing Theme Switching
Switching between light and dark themes (or even custom themes) is an essential feature in modern web applications. Let’s explore how to implement this functionality in React, Angular, and Sass/LESS, catering to different development environments.
React Implementation: Managing Themes with Context API
In React, the Context API offers a robust way to manage global states like themes. Here’s how you can implement theme switching step by step:
- Set Up Context for Theme State
Start by creating a ThemeContext
to hold the theme's state and provide it across your application.
export cons ```jsx
import React, { createContext, useState, useContext } from 'react';
const ThemeContext = createContext();
export const ThemeProvider = ({ children }) => {
const [theme, setTheme] = useState('light');
const toggleTheme = () => {
setTheme((prevTheme) => (prevTheme === 'light' ? 'dark': 'light'));
};
return (
<ThemeContext.Provider value={{ theme, toggleTheme }}>
{children}
</ThemeContext.Provider>
);
};
t useTheme = () => useContext(ThemeContext);
```
- Create a Theme Toggle Button
Add a button that allows users to switch themes.
```jsx
import React from 'react';
import { useTheme } from './ThemeProvider';
const ThemeToggleButton = () => {
const { theme, toggleTheme } = useTheme();
return (
<button onClick={toggleTheme}>
Switch to {theme === 'light'? 'Dark': 'Light'} Mode
</button>
);
};
export default ThemeToggleButton;
```
- Apply Themes with Styled-Components
Use styled-components
to dynamically apply styles based on the theme.
```jsx
import styled, { ThemeProvider as StyledThemeProvider } from 'styled-components';
import { useTheme } from './ThemeProvider';
const lightTheme = {
background: '#ffffff',
color: '#000000',
};
const darkTheme = {
background: '#000000',
colour: '#ffffff',
};
const AppContainer = styled.div`
background: ${(props) => props.theme.background};
color: ${(props) => props.theme.color};
min-height: 100vh;
display: flex;
justify-content: center;
align-items: center;
`;
const App = () => {
const { theme } = useTheme();
return (
<StyledThemeProvider theme={theme === 'light' ? lightTheme : darkTheme}>
<AppContainer>
<h1>Hello, Theme Switcher!</h1>
<ThemeToggleButton />
</AppContainer>
</StyledThemeProvider>
);
};
export default App;
```
Angular Implementation: Dynamic Theme Management with Services
In Angular, services are ideal for managing the application's theme state. Here’s how you can achieve this:
- Create a Theme Service
The service will hold the theme state and provide methods to toggle it.
```typescript
import { Injectable } from '@angular/core';
@Injectable({ providedIn: 'root' })
export class ThemeService {
private theme = 'light';
toggleTheme() {
this.theme = this.theme === 'light' ? 'dark': 'light';
document.body.className = this.theme; // Apply a theme to the body
}
getTheme() {
return this.theme;
}
}
```
- Add Theme Toggle Button
Create a button in your component to toggle the theme.
```typescript
import { Component } from '@angular/core';
import { ThemeService } from './theme.service';
@Component({
selector: 'app-theme-toggle',
template: <button (click)="toggleTheme()">Switch Theme</button>
,
})
export class ThemeToggleComponent {
constructor(private themeService: ThemeService) {}
toggleTheme() {
this.themeService.toggleTheme();
}
}
```
- Integrate Angular Material Theming (Optional)
Leverage Angular Material for built-in theme support.
```scss
@use '@angular/material' as mat;
$light-theme: mat.define-light-theme((
color: (primary: mat.$blue-palette, accent: mat.$pink-palette),
));
$dark-theme: mat.define-dark-theme($light-theme);
: root {
@include mat.core();
@include mat.all-component-themes($light-theme);
}
.dark {
@include mat.all-component-themes($dark-theme);
}
```
Sass/LESS Implementation: Style with Conditional Attributes
With Sass or LESS, you can dynamically update styles based on a custom data-theme
attribute.
- Set Up Theme Switching Logic
Use JavaScript to toggle a data-theme
attribute on the HTML element.
```javascript
const toggleTheme = () => {
const htmlElement = document.documentElement;
const currentTheme = htmlElement.getAttribute('data-theme');
htmlElement.setAttribute('data-theme', currentTheme === 'light' ? 'dark': 'light');
};
document.querySelector('#theme-toggle-btn').addEventListener('click', toggleTheme);
```
- Write Sass/LESS for Themes
Define styles for each theme.
```scss
[data-theme='light'] {
background: #ffffff;
color: #000000;
}
[data-theme='dark'] {
background: #000000;
color: #ffffff;
}
```
- Include a Theme Toggle Button
Add a button to trigger the theme switch.
```html
<button id="theme-toggle-btn">Toggle Theme</button>
```
By using these methods, you can implement theme switching effectively in your chosen framework or styling methodology.
Debugging Common Issues
Even with careful planning, you may encounter issues during implementation. Here’s how to debug some common challenges:
Conflicting Styles
If you notice that some elements are not switching to dark mode, inspect them using browser DevTools:
- Right-click the problematic element and select “inspect”.
- Check for specificity conflicts in CSS, such as inline styles or styles applied via JavaScript.
Solution: Use the !important
modifier sparingly to override problematic styles, or adjust your CSS selectors for better specificity.
```css
body.dark-mode .header {
background-color: #222 !important;
}
```
Incorrect State Management
Sometimes, toggling between dark and light modes may not persist or update correctly. This often results from incorrect use of state or local storage.
Example:
- Ensure that your JavaScript logic updates the classList
on the <body>
tag consistently.
- Verify that the user's preference is correctly stored and retrieved:
```javascript
const theme = localStorage.getItem('theme');
if (theme) {
document.body.classList.add(theme);
}
document.getElementById('toggle-dark-mode').addEventListener('click', () => {
const currentTheme = document.body.classList.contains('dark-mode') ? 'dark-mode' : 'light-mode';
localStorage.setItem('theme', currentTheme);
document.body.classList.toggle('dark mode);
});
```
Conclusion
Incorporating dark mode into your app or website can greatly enhance user experience, especially in low-light environments. Whether using frameworks like React and Angular or pre-processed CSS with Sass or LESS, the implementation is straightforward and flexible.
With just a few lines of code, you can give users control over their viewing preferences, making your project more modern and accessible.
Subscribe to my newsletter
Read articles from Onueze Mmasinachukwu directly inside your inbox. Subscribe to the newsletter, and don't miss out.
Written by

Onueze Mmasinachukwu
Onueze Mmasinachukwu
I'm Onueze Mmasinachukwu, a Technical writer and a frontend developer. My articles are focused on web development. I love reading, writing and sharing my ideas with people.