![]() |
VOOZH | about |
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.
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.
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 callvar(--variable-name)on the property we wish to assign it to.
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.
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.
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:
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.
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.
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 BannerLogRocket 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.
Learn how next-browser gives AI agents runtime context for debugging Next.js apps, including React props, hydration, PPR, forms, and performance.
Build dynamic LLM routing in Next.js with OpenRouter, TanStack AI, task classification, model fallbacks, and cost-aware routing.
TSRX adds first-class control flow, conditional hooks, and scoped styles to React via a TypeScript compiler extension โ no new framework required.
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.
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