BrowserUX Theme Switcher

Welcome to the BrowserUX Theme Switcher Documentation

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.

I. How It Works

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:

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)

2. Storing the User Preference

When the user clicks the button to toggle the theme, their preference (light or dark) is saved in localStorage.
This preference will:

  • be automatically applied on the next visit
  • take precedence over system detection

3. Applying the Theme in the DOM

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:

  • style the page using conditional CSS variables
  • adapt images (with .has-dark)
  • respond to events (like theme-change)

II. Installation


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.

III. Usage

1. The browserux-theme-switcher Web Component

Modern project with a bundler (Vite, Webpack, etc.)

1. Simply import the component into your code:


import 'browserux-theme-switcher';

2. Then use it in your HTML:


<browserux-theme-switcher></browserux-theme-switcher>

React / Next.js

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.

Vue 3

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>

Angular

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 {}

Without bundler / Global script

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>

2. Managing CSS Styles

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.

Full Example


: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;
}

Explanation

  • :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.

3. Managing Images Based on Theme (Dark Mode)

The browserux-theme-switcher component automatically supports theme-adaptive images (light or dark) using the special has-dark class.

How Does It Work?

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.

Requirements

  • The original image must be named name.ext (e.g., logo.png).
  • The dark version must be named exactly name-dark.ext (e.g., logo-dark.png).
  • Both images must be located in the same directory.

Example

☀️ In Light Mode:

<img src="logo.png" class="has-dark">
                        

→ Displays logo.png

🌙 In Dark Mode:

→ Automatically replaced with logo-dark.png

The change is reversible and instantaneous with each theme toggle, without page reload or additional JavaScript.

IV. browserux-theme-switcher Parameters

browserux-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

1. Attributes

Custom Targeting (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.

Attribute: target
  • Type: string (valid CSS selector)
  • Default value: html
  • Effect: applies the data-theme attribute to the matching element
Example

<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.

Tip

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.

Internationalization (lang)

The browserux-theme-switcher component supports multiple languages for its accessible labels (e.g., “Activer sombre”, “Switch to light mode”, etc.).

Attribute: lang
  • Type: string ("en", "fr", "es", "de", "ja", "ru", "pt", "it", "nl")
  • Default value: auto-detection
  • Effect: forces the language used for ARIA labels (aria-label) of the switch
Example

<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"

Automatic detection if lang is not set

If you don’t specify the lang attribute, the component uses the following logic:

  • 1. Uses the lang attribute on the browserux-theme-switcher tag
  • 2. Otherwise, checks the lang value on the html lang="..." tag
  • 3. Otherwise, defaults to "en" (English)
Supported Languages

The component supports the following languages for accessible labels (aria-label):

  • 🇬🇧 en – English (default)
  • 🇫🇷 fr – French
  • 🇪🇸 es – Spanish
  • 🇩🇪 de – German
  • 🇯🇵 ja – Japanese
  • 🇷🇺 ru – Russian
  • 🇵🇹 pt – Portuguese
  • 🇮🇹 it – Italian
  • 🇳🇱 nl – Dutch

ARIA Accessibility (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:

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
Example

<browserux-theme-switcher
    data-label-light="Activate light theme"
    data-label-dark="Switch to dark mode"
></browserux-theme-switcher>

Result:

  • In light mode → aria-label="Switch to dark mode"
  • In dark mode → aria-label="Activate light theme"

These attributes take precedence over automatic language detection (lang).

Optional Shadow DOM (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.

Attribute: no-shadow
  • Type: boolean (presence-only)
  • Default value: not present → Shadow DOM enabled
  • Effect: if present, the component is rendered in the global DOM without encapsulation
Example

<browserux-theme-switcher no-shadow></browserux-theme-switcher>
                    

This component:

  • Will be rendered in the regular DOM (not inside a shadowRoot)
  • Can be styled using your global CSS
  • Will more easily inherit external styles
When to use no-shadow?
  • When you want to easily override the component’s styles using global CSS
  • If you need to theme the switcher using the page’s CSS variables
  • In integration contexts where Shadow DOM causes issues (e.g., Angular)
  • To simplify DOM rendering debugging

Caution: Without Shadow DOM, the component becomes more sensitive to global style conflicts. Use with care in large applications.

CSS Customization (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
Example

<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>
  • These variables can be dynamically modified based on the theme ([data-theme="dark"]) or breakpoints (media queries).
  • They work even if Shadow DOM is enabled, thanks to the use of CSS custom properties.

2. Events

Custom Event (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.).

Event
  • Name: theme-change
  • Payload: the emitted event is a CustomEvent where e.detail.theme contains the new theme value ("light" or "dark").
Example JavaScript Listener

const switcher = document.querySelector('browserux-theme-switcher');

switcher?.addEventListener('theme-change', (e) => {
  console.log('Thème sélectionné :', e.detail.theme);
});
Possible Use Cases
  • Dynamically modify a CSS class on the body
  • Trigger an animation or transition
  • Store the theme in a global context or JS service
  • Track interactions with an analytics tool

The event is available as soon as the component initializes and works in all contexts (framework or plain HTML).

3. Slots

Customizing Icons (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.

Available 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
Exemples

<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>
How It Works
  • Each slot is dynamically shown or hidden based on the active theme
  • Slots are accessible (with aria-label) and can contain:
    • emoji
    • SVG icons
    • raster images
    • custom elements

If no slots are provided, default icons are used (☀️ / 🌙).

V. Build & Development


npm install
npm run build

Use TypeScript + Rollup to build:

  • dist/browserux-theme-switcher.esm.js
  • dist/browserux-theme-switcher.umd.js
  • dist/browserux-theme-switcher.d.ts

VI. License

MIT License, free to use, modify, and distribute.