VOOZH about

URL: https://blog.logrocket.com/a-guide-to-theming-in-css/

โ‡ฑ A guide to theming in CSS - LogRocket Blog


2020-07-31
1044
#css
Ogundipe Samuel
22732
๐Ÿ‘ Image

See how LogRocket's Galileo AI surfaces the most severe issues for you

No signup required

Check it out

Over the years, CSS has evolved to cater to the ever-growing needs and flexibility requirements of modern UI design. The demand for highly customizable applications is rapidly increasing, and with that the need for developers who can create such websites.

๐Ÿ‘ The CSS logo over a yellow background.

Theming is the ability to style various aspects of our website differently depending on a context, while still maintaining visual appeal. It could be as simple as changing colors and backgrounds or font-sizes and icons. In CSS, we can achieve theming by piecing together various CSS variables (props) in a context (e.g, black and white) to enable better presentation of an application.

In this tutorial, weโ€™ll cover how to develop apps that are theme-aware using CSS variables. Weโ€™ll also learn how to use CSS variables and JavaScript to customize websites and applications.

๐Ÿš€ Sign up for The Replay newsletter

The Replay is a weekly newsletter for dev and engineering leaders.

Delivered once a week, it's your curated guide to the most important conversations around frontend dev, emerging AI tools, and the state of modern software.

CSS Variables

A CSS variable (also called a custom property) is a variable you assign a CSS value to and reuse throughout your application.

In older versions of CSS, itโ€™s common to define different values for CSS properties and apply them repeatedly whereever they are needed. In the example below, the a element is set to black (#000), and although other elements (p) will also need to use the same color value (#000), you need to explicitly type out the color value (#000) every time you want to use it on another element.

a {
 color: #000;
}

p {
 color: #000;
}

With CSS variables, we only need to define the value once and then reference it wherever needed. It is identical to defining a variable in any programming language. In the example below, we declare a variable black at the top level of our CSS document and then reference it wherever it is needed.

:root {
 --black: #000;
}

a {
 color: var(--black);
}

p {
 color: var(--black);
}

N/B: When declaring CSS variables, the syntax is **--**, followed by the name of the variable. To reference it, we call var(--variable-name) on the property we wish to assign it to.

Inheritance

CSS variables can be scoped to certain components in an application and can be overridden in inner components when necessary.

This is one feature that makes CSS variables stand out, and itโ€™s also what makes it perfect for creating theme0aware websites. In the example below, the inner div and outer div have been defined with two different background colors. First, we define --some-color at .outer-div by setting its value to black. Then we redefine it at .inner-div by setting itโ€™s value to white, causing it to override its value under this element.

The first .text-color gets the value that was defined at .outer-div because that is its parent, while the second .text-color div gets it from .inner-div as that is the direct child of that div.

Switching themes

With the illustrations above, all thatโ€™s left to make a theme-able website is to figure out a way to swap the property values of various elements based on the current context.


Over 200k developers use LogRocket to create better digital experiences

๐Ÿ‘ Image
Learn more โ†’

To better understand the concept, letโ€™s talk about black and white themes. At a very basic level, to support black and white themes on a website, the background and text color will have to alternate to maintain readability. So, when we are viewing the black theme, the text color should be white, and when we are viewing the white theme, the text color should be black.

The following pen shows what the website looks like on a white theme:

The following pen shows what the website looks like on a black theme:

Typically, on a website, we may have a toggle that enables us to switch between the available themes. To change the CSS variables in real-time, we need to add a little bit of JavaScript to control the process.

Letโ€™s create a page with dark and light themes and add some JavaScript so that it switches whenever the checkbox is clicked:

In the CSS above, we define two site-wide color sets:

:root {
 --primary-color: #302AE6;
 --secondary-color: #536390;
 --font-color: #424242;
 --bg-color: #fff;
 --heading-color: #292922;
}

AND 

[data-theme="dark"] {
 --primary-color: #9A97F3;
 --secondary-color: #818cab;
 --font-color: #e1e1ff;
 --bg-color: #161625;
 --heading-color: #818cab;
}

The root contains the default colors needed for the light theme, and โ€œdata-theme=darkโ€ contains all the colors needed for a dark theme on various parts of our website.

Weโ€™ve also added a toggle box to be used to swap out themes whenever a user clicks.

Next, we add some JavaScript to make the swap possible:

const toggleSwitch = document.querySelector('.theme-switch input[type="checkbox"]');

function switchTheme(e) {
 if (e.target.checked) {
 document.documentElement.setAttribute('data-theme', 'dark');
 }
 else {
 document.documentElement.setAttribute('data-theme', 'light');
 } 
}

toggleSwitch.addEventListener('change', switchTheme, false);

Hereโ€™s how we achieved this:

  • We select the checkbox with the query selector
  • We create a function to change the context of the application to dark when checked or light when unchecked
  • Finally, we add an event listener to listen for the actions

A good thing to have on a themeable website is the ability to store the user preference, so the next time the user visits the website it automatically loads up in that context. To achieve that, we will make use of local storage.

Add the following lines to the snippet above:

if (e.target.checked) {
 document.documentElement.setAttribute('data-theme', 'dark');
 localStorage.setItem('theme', 'dark'); //this will be set to dark
 }
else {
 document.documentElement.setAttribute('data-theme', 'light');
 localStorage.setItem('theme', 'light'); //this will be set to light
}

Now that we are saving the user preference, we need to check for it every time a site loads so we know which version to display to the user. Add this snippet at the top level in the Javascript document:

const currentTheme = localStorage.getItem('theme') ? localStorage.getItem('theme') : null;

if (currentTheme) {
 document.documentElement.setAttribute('data-theme', currentTheme);

 if (currentTheme === 'dark') {
 toggleSwitch.checked = true;
 }
}

Here, we check if a theme preference has been stored in local storage. Based on the value stored, we toggle the box (by setting it to true or false) to swap the needed variables.

Conclusion

In this tutorial, we learned about theming and how to create a basic version of a theme-able website using CSS variables. We also learned about variable inheritance and local scoping alongside how to make it all come together using basic JavaScript. To learn more about CSS theming check out the official docs here.

Is your frontend hogging your users' CPU?

As web frontends get increasingly complex, resource-greedy features demand more and more from the browser. If youโ€™re interested in monitoring and tracking client-side CPU usage, memory usage, and more for all of your users in production, try LogRocket.

๐Ÿ‘ LogRocket Dashboard Free Trial Banner

LogRocket lets you replay user sessions, eliminating guesswork around why bugs happen by showing exactly what users experienced. It captures console logs, errors, network requests, and pixel-perfect DOM recordings โ€” compatible with all frameworks.

LogRocket's Galileo AI watches sessions for you, instantly identifying and explaining user struggles with automated monitoring of your entire product experience.

Modernize how you debug web and mobile apps โ€” start monitoring for free.

๐Ÿ‘ Image
๐Ÿ‘ Image
๐Ÿ‘ Image

Stop guessing about your digital experience with LogRocket

Get started for free

Recent posts:

Debug Next.js apps with AI agents and next-browser

Learn how next-browser gives AI agents runtime context for debugging Next.js apps, including React props, hydration, PPR, forms, and performance.

๐Ÿ‘ Image
Emmanuel John
Jun 17, 2026 โ‹… 9 min read

Stop hardcoding LLM SDKs: Dynamic LLM routing with OpenRouter and Next.js

Build dynamic LLM routing in Next.js with OpenRouter, TanStack AI, task classification, model fallbacks, and cost-aware routing.

๐Ÿ‘ Image
Chizaram Ken
Jun 16, 2026 โ‹… 13 min read

What is TSRX?: What JSX would look like if it were designed today

TSRX adds first-class control flow, conditional hooks, and scoped styles to React via a TypeScript compiler extension โ€” no new framework required.

๐Ÿ‘ Image
Ikeh Akinyemi
Jun 12, 2026 โ‹… 6 min read

How to add authentication to a React Native app with Better Auth

Learn how to build a full React Native auth system using Better Auth and Expo โ€” with email/password login, Google OAuth, session persistence, and protected routes.

๐Ÿ‘ Image
Chinwike Maduabuchi
Jun 9, 2026 โ‹… 13 min read
View all posts

Would you be interested in joining LogRocket's developer community?

Join LogRocketโ€™s Content Advisory Board. Youโ€™ll help inform the type of content we create and get access to exclusive meetups, social accreditation, and swag.

Sign up now