1. Automatic Detection of System Theme
If no user preference is yet defined, the component automatically detects the system's preferred theme using the CSS rule:
@media (prefers-color-scheme: dark)
BrowserUX Theme Switcher is a lightweight and accessible Web Component that makes it easy to switch between light and dark themes, with system detection, persistence, and CSS customization.
The browserux-theme-switcher component dynamically applies a light or dark theme
to an element on your page (html by default, or another element using the target attribute).
It follows a three-step logic:
If no user preference is yet defined, the component automatically detects the system's preferred theme using the CSS rule:
@media (prefers-color-scheme: dark)
When the user clicks the button to toggle the theme, their preference
(light or dark) is saved in localStorage.
This preference will:
The component dynamically sets or updates the data-theme attribute
on the targeted element, for example:
<html data-theme="dark">...</html>
This allows you to:
.has-dark)theme-change)
npm install browserux-theme-switcher
Or via CDN:
<script type="module" src="https://unpkg.com/browserux-theme-switcher/dist/browserux-theme-switcher.min.js"></script>
Use the .esm.js version if you're integrating the component via a bundler (React, Vue, etc.),
and the .min.js version for direct HTML integration via CDN.
browserux-theme-switcher Web Component1. Simply import the component into your code:
import 'browserux-theme-switcher';
2. Then use it in your HTML:
<browserux-theme-switcher></browserux-theme-switcher>
1. Add this to your React component (often inside a useEffect):
import { useEffect } from 'react';
useEffect(() => {
import('browserux-theme-switcher');
}, []);
2. Then in your JSX:
<browserux-theme-switcher></browserux-theme-switcher>
Add the types/browserux-theme-switcher.d.ts file for better TypeScript support with JSX.
1. Add this in main.js or main.ts:
import 'browserux-theme-switcher';
2. Use it like a native component:
<browserux-theme-switcher></browserux-theme-switcher>
1. Import it in main.ts:
import 'browserux-theme-switcher';
2. Add CUSTOM_ELEMENTS_SCHEMA to your AppModule:
import { NgModule, CUSTOM_ELEMENTS_SCHEMA } from '@angular/core';
@NgModule({
schemas: [CUSTOM_ELEMENTS_SCHEMA]
})
export class AppModule {}
1. Add the component directly via a CDN:
<script type="module" src="https://unpkg.com/browserux-theme-switcher/dist/browserux-theme-switcher.min.js"></script>
2. Then:
<browserux-theme-switcher></browserux-theme-switcher>
To apply the light or dark theme to your page, you need to define your colors using CSS variables.
The <browserux-theme-switcher> component automatically sets a data-theme="dark" or "light"
attribute on the targeted element (default is html), which allows your interface to be styled dynamically.
:root {
--bux-page-bg: #eaeaea;
--bux-page-color: #121212;
--bux-color-primary: #f05e0e;
--bux-color-secondary: #0e93f0;
--bux-white: #fff;
}
/** Mode sombre automatique selon les préférences système */
@media (prefers-color-scheme: dark) {
:root {
--bux-page-bg: #333;
--bux-page-color: #eaeaea;
--bux-color-primary: #eb8a55;
--bux-color-secondary: #58aae3;
--bux-white: #444;
}
}
/** Mode sombre forcé via browserux-theme-switcher */
[data-theme="dark"] {
--bux-page-bg: #333;
--bux-page-color: #eaeaea;
--bux-color-primary: #eb8a55;
--bux-color-secondary: #58aae3;
--bux-white: #444;
}
:root defines the default colors (light mode).@media (prefers-color-scheme: dark) accounts for system preferences if the user hasn't selected a theme yet.[data-theme="dark"] forces dark mode when the user clicks the browserux-theme-switcher button.
The switcher applies data-theme="dark" or data-theme="light" to the targeted element
(html by default, or a container via the target attribute).
You must therefore apply your CSS variables on the same element or a common parent.
The browserux-theme-switcher component automatically supports theme-adaptive images (light or dark)
using the special has-dark class.
When you add the has-dark class to an image in your HTML:
<img src="logo.png" class="has-dark" alt="Logo">
The component will automatically replace the src attribute with a -dark version
when dark mode is active, and revert to the original image when switching back to light mode.
name.ext (e.g., logo.png).name-dark.ext (e.g., logo-dark.png).
<img src="logo.png" class="has-dark">
→ Displays logo.png
→ Automatically replaced with logo-dark.png
The change is reversible and instantaneous with each theme toggle, without page reload or additional JavaScript.
browserux-theme-switcher Parametersbrowserux-theme-switcher offers a wide range of customization options:
| Feature | Type | Name | Description |
|---|---|---|---|
| Custom Target | Attribute | target |
Applies the theme to a specific element |
| Internationalization | Attribute | lang |
Language selection |
| ARIA Accessibility | Attribute | data-label-* |
Customizable accessible labels |
| Optional Shadow DOM | Attribute | no-shadow |
Disable encapsulation |
| CSS Customization | Attribute | style |
Customization via CSS variables |
| Custom Event | Event | theme-change |
Event emitted on every theme change |
| Icon Slots | Slot | *-icon |
Icon customization |
target)
By default, the browserux-theme-switcher component applies the theme
(data-theme="light" or "dark") to the html element.
However, you can customize this target using the target attribute.
targetstring (valid CSS selector)htmldata-theme attribute to the matching element
<browserux-theme-switcher
target="#app"
></browserux-theme-switcher>
<div id="app">
<!-- The theme is applied here -->
</div>
In this example, it’s the #app element (not html) that will receive the data-theme attribute.
This allows you to scope the theme to a specific container within your application—useful for
micro-frontends, app shells, or embedded widgets.
Make sure your CSS styles rely on [data-theme="dark"] or
[data-theme="light"] applied to the correct selector:
#app[data-theme="dark"] {
--page-bg: #333;
/* etc. */
}
If the selector provided in the target attribute doesn't match any element at render time,
the fallback will be html.
lang)
The browserux-theme-switcher component supports multiple languages for its
accessible labels (e.g., “Activer sombre”, “Switch to light mode”, etc.).
langstring ("en", "fr", "es", "de",
"ja", "ru", "pt", "it", "nl")aria-label) of the switch
<browserux-theme-switcher
lang="es"
></browserux-theme-switcher>
The ARIA label of the button will automatically be in French:
aria-label="Activer le mode sombre" or aria-label="Activer le mode clair"
lang is not setIf you don’t specify the lang attribute, the component uses the following logic:
lang attribute on the browserux-theme-switcher taglang value on the html lang="..." tagen" (English)The component supports the following languages for accessible labels (aria-label):
data-label-light / data-label-dark)
The browserux-theme-switcher component is designed to be accessible for screen readers,
using dynamic aria-label attributes that describe the button’s action (e.g., switch to light or dark mode).
By default, these labels are generated automatically based on the language (via the lang attribute).
However, you can override them with your own custom text using the following attributes:
| Attribute | Purpose |
|---|---|
data-label-light |
Label when the current theme is dark and the button switches to light mode |
data-label-dark |
Label when the current theme is light and the button switches to dark mode |
<browserux-theme-switcher
data-label-light="Activate light theme"
data-label-dark="Switch to dark mode"
></browserux-theme-switcher>
Result:
aria-label="Switch to dark mode"aria-label="Activate light theme"
These attributes take precedence over automatic language detection (lang).
no-shadow)
By default, the browserux-theme-switcher component uses the Shadow DOM to encapsulate its HTML and CSS.
This ensures that its internal styles don't affect the rest of the page—and vice versa.
However, in certain cases—such as applying global styles or dealing with specific framework limitations— it may be useful to disable this encapsulation.
no-shadowboolean (presence-only)
<browserux-theme-switcher no-shadow></browserux-theme-switcher>
This component:
shadowRoot)no-shadow?Caution: Without Shadow DOM, the component becomes more sensitive to global style conflicts. Use with care in large applications.
style)
The browserux-theme-switcher component exposes several customizable CSS variables
that allow you to modify its appearance without overriding internal styles.
| Variable | Default | Description |
|---|---|---|
| --bux-switch-width | 40px |
Toggle button width |
| --bux-switch-height | 24px |
Toggle button height |
| --bux-switch-bg-color | #888 |
Switch background color |
| --bux-switch-thumb-color | #fff |
Thumb color |
| --bux-switch-emoji-size | inherit |
Emoji icon size |
<browserux-theme-switcher
style="
--bux-switch-width: 60px;
--bux-switch-height: 32px;
--bux-switch-bg-color: #222;
--bux-switch-thumb-color: orange;
--bux-switch-emoji-size: 1.5rem;"
></browserux-theme-switcher>
[data-theme="dark"]) or breakpoints (media queries).Shadow DOM is enabled, thanks to the use of CSS custom properties.theme-change)
The browserux-theme-switcher component dispatches a custom event named
theme-change every time the theme changes (e.g., due to a user click,
an initial load with localStorage, etc.).
This event allows your application to respond dynamically to theme changes (layout updates, analytics, etc.).
theme-changeCustomEvent where e.detail.theme
contains the new theme value ("light" or "dark").
const switcher = document.querySelector('browserux-theme-switcher');
switcher?.addEventListener('theme-change', (e) => {
console.log('Thème sélectionné :', e.detail.theme);
});
bodyThe event is available as soon as the component initializes and works in all contexts (framework or plain HTML).
light-icon / dark-icon)
The browserux-theme-switcher component allows you to customize the appearance of its button
by replacing the default icons using HTML slots.
| Slot | Displayed when theme is... | Example usage |
|---|---|---|
light-icon |
active = dark (icon to switch to light mode) | ☀️, sun, light.svg |
dark-icon |
active = light (icon to switch to dark mode) | 🌙, moon, moon.svg |
<browserux-theme-switcher>
<span slot="light-icon">🔆</span>
<span slot="dark-icon">🌑</span>
</browserux-theme-switcher>
Or with images:
<browserux-theme-switcher>
<img slot="light-icon" src="sun.svg" width="20" height="20" alt="Theme clair">
<img slot="dark-icon" src="moon.svg" width="20" height="20" alt="Theme sombre">
</browserux-theme-switcher>
If no slots are provided, default icons are used (☀️ / 🌙).
npm install
npm run build
Use TypeScript + Rollup to build:
dist/browserux-theme-switcher.esm.jsdist/browserux-theme-switcher.umd.jsdist/browserux-theme-switcher.d.tsMIT License, free to use, modify, and distribute.