
Research
/Security News
Critical Vulnerability in NestJS Devtools: Localhost RCE via Sandbox Escape
A flawed sandbox in @nestjs/devtools-integration lets attackers run code on your machine via CSRF, leading to full Remote Code Execution (RCE).
browserux-theme-switcher
Advanced tools
Lightweight and customizable Web Component for theme toggling (light/dark), with i18n, accessibility, and full framework compatibility.
EN | FR
A lightweight and customizable Web Component that allows users to toggle between light and dark themes. Accessible, internationalized, and compatible with all modern frameworks.
🎚 Theme Switching
Toggles between data-theme="light"
and "dark"
on a target element (default is <html>
)
💾 Automatic Persistence
Stores user preference in localStorage
and restores it on each visit
🕶 System Detection
Automatically applies the theme based on prefers-color-scheme
if no user preference is set
📢 theme-change
Event
Fires a custom event on each theme change (e.detail.theme = "light" | "dark"
)
🧠 Dynamic ARIA Labels
Multilingual accessible labels generated automatically or customizable (data-label-*
)
🌐 Internationalization (lang
)
Supports multiple languages (auto-detection or manual setting via the lang
attribute)
🎯 CSS Targeting (target
)
Allows applying the theme to a specific element (e.g., <main>
, #app
, etc.)
🎨 Customizable CSS Variables
Extensive visual customization via CSS properties (--bux-switch-*
)
🌗 Custom Icon Slots
Customize icons using SVGs, emojis, or images (light-icon
, dark-icon
)
🖼 Adaptive Images (.has-dark
)
Automatically switch images based on the theme (e.g., logo.png
→ logo-dark.png
)
no-shadow
)The <browserux-theme-switcher>
component dynamically applies a light or dark theme to an element on your page (<html>
by default, or another element via the target
attribute).
It follows a three-step logic:
If no user preference is set, 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 switch themes, 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
)The component works without dependencies, requires no complex configuration, and is compatible with all modern frameworks (React, Vue, Angular) as well as plain HTML.
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 this component via a bundler (React, Vue, etc.), and the.min.js
version for direct HTML integration via CDN.
<browserux-theme-switcher>
Web Componentimport 'browserux-theme-switcher';
<browserux-theme-switcher></browserux-theme-switcher>
useEffect
):import { useEffect } from 'react';
useEffect(() => {
import('browserux-theme-switcher');
}, []);
<browserux-theme-switcher></browserux-theme-switcher>
Add the
types/browserux-theme-switcher.d.ts
file for better TypeScript support with JSX.
main.js
or main.ts
:import 'browserux-theme-switcher';
<browserux-theme-switcher lang="fr"></browserux-theme-switcher>
main.ts
:import 'browserux-theme-switcher';
CUSTOM_ELEMENTS_SCHEMA
to AppModule
:import { NgModule, CUSTOM_ELEMENTS_SCHEMA } from '@angular/core';
@NgModule({
schemas: [CUSTOM_ELEMENTS_SCHEMA]
})
export class AppModule {}
<script type="module" src="https://unpkg.com/browserux-theme-switcher/dist/browserux-theme-switcher.min.js"></script>
<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 applies a data-theme="dark"
or "light"
attribute
to the targeted element (by default <html>
), which enables dynamic styling of your interface.
:root {
--bux-page-bg: #eaeaea;
--bux-page-color: #121212;
--bux-color-primary: #f05e0e;
--bux-color-secondary: #0e93f0;
--bux-white: #fff;
}
/** Automatic dark mode based on system preferences */
@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;
}
}
/** Dark mode forced 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)
takes system preferences into account 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"
ordata-theme="light"
to the targeted element (html
by default, or a container via thetarget
attribute).
You should apply CSS variables to that same element or a shared parent.
The <browserux-theme-switcher>
component automatically handles theme-adaptive image display (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
).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 instant every time the theme switches, with no page reload or extra JavaScript required.
<browserux-theme-switcher>
<browserux-theme-switcher>
offers many customization options:
Parameter | Type | Name | Description |
---|---|---|---|
Custom Targeting | 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 triggered 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.
target
string
(valid CSS selector)html
data-theme
attribute to the specified element<browserux-theme-switcher
target="#app"
></browserux-theme-switcher>
<div id="app">
<!-- The theme is applied here -->
</div>
In this example, the #app
element (and not <html>
) will receive the data-theme
attribute.
This allows you to scope the theme to a specific container in your application—useful for micro-frontends, app shells, or embedded widgets.
Make sure your CSS styles are based on [data-theme="dark"]
or [data-theme="light"]
applied to the correct selector:
#app[data-theme="dark"] {
--bux-page-bg: #333;
/* etc. */
}
If the selector passed to
target
does not 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., "Switch to dark mode", "Activer sombre", etc.).
lang
string
("en"
, "fr"
, "es"
, "de"
, "ja"
, "ru"
, "pt"
, "it"
, "nl"
)aria-label
)<browserux-theme-switcher
lang="fr"
></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 DefinedIf you don’t specify the lang
attribute, the component follows this logic:
lang
value on the <browserux-theme-switcher>
taglang
value on the <html lang="...">
tag"en"
(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 screen reader–friendly,
thanks to dynamic aria-label
s that describe the button's action (e.g., switch to light or dark mode).
By default, these labels are automatically generated based on the selected language (lang
attribute).
However, you can override them with your own custom labels using two attributes:
Attribute | Role |
---|---|
data-label-light | Label when dark theme is active and the button allows switching to light mode |
data-label-dark | Label when light theme is active and the button allows switching to dark mode |
<browserux-theme-switcher
data-label-light="Activer le thème clair"
data-label-dark="Passer en mode sombre">
</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 Shadow DOM to encapsulate its HTML and CSS.
This ensures that its internal styles don’t interfere with the rest of the page—and vice versa.
However, in some cases—such as applying global styles or addressing specific framework constraints—it may be helpful to disable this encapsulation.
no-shadow
boolean
(presence-only)<browserux-theme-switcher no-shadow></browserux-theme-switcher>
This component:
no-shadow
?⚠️ Without Shadow DOM, the component is more vulnerable to global style conflicts. Use with caution in large-scale applications.
style
)The <browserux-theme-switcher>
component exposes several customizable CSS variables
to let you tweak its appearance without overriding internal styles.
Variable | Default | Description |
---|---|---|
--bux-switch-width | 40px | Width of the toggle button |
--bux-switch-height | 24px | Height of the toggle button |
--bux-switch-bg-color | #888 | Background color of the switch |
--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
whenever the theme changes
(e.g., after a user click, or an initial load using localStorage
, etc.).
This event allows your application to dynamically respond to theme changes (layout updates, analytics, etc.).
theme-change
CustomEvent
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);
});
body
The event is available as soon as the component is initialized and works in all contexts (frameworks or plain HTML).
light-icon
/ dark-icon
)The <browserux-theme-switcher>
component allows customization of its toggle button appearance
by replacing default icons using HTML slots.
Slot | Displayed when the current 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 SVG images:
<browserux-theme-switcher>
<img slot="light-icon" src="sun.svg" width="20" height="20" alt="Light mode">
<img slot="dark-icon" src="moon.svg" width="20" height="20" alt="Dark mode">
</browserux-theme-switcher>
aria-label
) and can contain:
If no slot is provided, default icons are used (☀️ / 🌙).
npm install
npm run build
The project uses TypeScript and Rollup to generate build outputs:
dist/browserux-theme-switcher.esm.js
dist/browserux-theme-switcher.umd.js
dist/browserux-theme-switcher.d.ts
These builds are ready to be used in both module-based environments and traditional script loading contexts.
MIT License, Free to use, modify, and distribute.
[1.0.3] – 2025-06-25
:host(.dark)
selector with a dynamic CSS variable (--toggle-shift
)
to control the toggle thumb position.FAQs
Lightweight and customizable Web Component for theme toggling (light/dark), with i18n, accessibility, and full framework compatibility.
The npm package browserux-theme-switcher receives a total of 5 weekly downloads. As such, browserux-theme-switcher popularity was classified as not popular.
We found that browserux-theme-switcher demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?
Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.
Research
/Security News
A flawed sandbox in @nestjs/devtools-integration lets attackers run code on your machine via CSRF, leading to full Remote Code Execution (RCE).
Product
Customize license detection with Socket’s new license overlays: gain control, reduce noise, and handle edge cases with precision.
Product
Socket now supports Rust and Cargo, offering package search for all users and experimental SBOM generation for enterprise projects.