DEV Community

Sai Shravan Vadla
Sai Shravan Vadla

Posted on

Automatic and manual theme changes in a simple way

The ability to change themes manually; and automatically update according to the system is a necessary requirement of any modern website or application. Here's a simple way to implement this using CSS:
Look at this repo for reference.

This project utilizes CSS variables and JavaScript to achieve theme switching functionality:

The JavaScript code toggles a class changed on the root element based on the button click. This makes the manual theme change possible.

The app responds to the system's color scheme preference using the prefers-color-scheme media query. This makes the automatic theme change possible.

The CSS variables (--base-text-clr, --base-bg-clr) define the colors for both light and dark themes.

* {
  box-sizing: border-box;
}

:root {
  --base-text-clr: black;
  --base-bg-clr: white;
}

:root.changed {
  --base-text-clr: white;
  --base-bg-clr: #212121;
}

body {
  margin: 0;
  padding: 2em;
  font-family: sans-serif;
  color: var(--base-text-clr);
  background-color: var(--base-bg-clr);
}

@media (prefers-color-scheme: dark) {
  :root {
    --base-text-clr: white;
    --base-bg-clr: #212121;
  }

  :root.changed {
    --base-text-clr: black;
    --base-bg-clr: white;
  }
}
Enter fullscreen mode Exit fullscreen mode
<body>
    <h1>You are now viewing this page in the <code></code> theme</h1>
    <p>Illo, sunt provident corrupti veniam est animi velit?</p>
    <button type="button">Toggle theme</button>
  </body>

Enter fullscreen mode Exit fullscreen mode

And here's the script that adds an event listener to the button to allow for manual theme changes:

const buttonEl = document.querySelector('button')
const rootEl = document.documentElement
const themeTextEl = document.querySelector('code')

let isThemeInverse = false
if (
  window.matchMedia &&
  window.matchMedia('(prefers-color-scheme: dark)').matches
) {
  themeTextEl.innerText = 'dark'
} else {
  themeTextEl.innerText = 'light'
}

const handleThemeChange = (e) => {
  rootEl.classList.toggle('changed')
  isThemeInverse = !isThemeInverse
  updateThemeText()
}

const updateThemeText = () => {
  if (themeTextEl.innerText === 'dark') {
    themeTextEl.innerText = 'light'
  } else if (themeTextEl.innerText === 'light') {
    themeTextEl.innerText = 'dark'
  }
}

buttonEl.addEventListener('click', handleThemeChange)
Enter fullscreen mode Exit fullscreen mode

That it! Look at the live version here.

This may not be the best way to implement theme changes. Use it with discretion. Please do tell if you have better ways in the comments.

Thank you for reading.

Top comments (0)