How to implement dark mode with CSS custom properties

· Category: HTML & CSS

Short answer

Define your color palette as CSS custom properties on :root, then override them inside a @media (prefers-color-scheme: dark) block or a [data-theme="dark"] attribute selector. Use JavaScript to toggle the attribute and persist the choice in localStorage.

Details

Start by defining semantic variable names like --color-background and --color-text rather than literal color names. This makes swapping themes trivial. For automatic OS-level support, wrap dark overrides in prefers-color-scheme: dark. For manual toggling, add a data-theme attribute to the <html> element and override variables there.

JavaScript is needed to read the toggle state and write it to localStorage. If you want to learn more about client-side storage mechanisms, check out How to use the Storage API for client-side data. You may also want to understand how to use async/await when loading the user's saved theme preference on app startup.

Tips

  • Always define a default theme before overrides so the page works without JavaScript.
  • Test contrast ratios in both themes to meet WCAG guidelines.
  • Consider adding a color-scheme: dark CSS property to ensure native form controls respect the theme.
  • For more on writing robust theme logic, see what are JavaScript closures to keep your toggle state encapsulated.