Skip to content
Devix Open Source

Customize

Styling

import '@devix-labs/theme-toggle/styles.css';        // plain
import '@devix-labs/theme-toggle/styles.layer.css';  // the same, inside @layer devix

Variables

.dxm {
  --dxm-radius: 9px;
  --dxm-size: 28px;
  --dxm-gap: 2px;
  --dxm-padding: 2px;
  --dxm-font-size: 12.5px;

  --dxm-bg: #f4f4f5;
  --dxm-fg: #71717a;
  --dxm-border: #e4e4e7;
  --dxm-active-bg: #fff;
  --dxm-active-fg: #18181b;
  --dxm-accent: #ea4b71;
  --dxm-shadow: 0 1px 2px rgb(17 17 28 / 0.08);
}

The control styles itself for dark under .dark or [data-theme="dark"] — the same attribute it sets — so it follows the theme it controls without being told which one that is.

Your classes

createThemeToggle(el, {
  classNames: { root: 'rounded-full shadow-sm', option: 'px-3', icon: 'opacity-80' },
});

Parts: root, option, button, icon, label.

Your icons

createThemeToggle(el, {
  icons: {
    light: '<svg viewBox="0 0 24 24">…</svg>',
    dark: '<i class="fa-solid fa-moon"></i>',
    system: '<i class="fa-solid fa-desktop"></i>',
  },
});

Anything you leave out keeps ours. The markup is yours, so an icon font is as welcome as an SVG.

State

Selector When
.dxm[data-theme='dark'] The choice is dark — system stays system.
.dxm-option:has(.dxm-input:checked) The selected option.
.dxm-option:has(.dxm-input:focus-visible) Keyboard focus.

The choice is kept on <html data-theme-choice> as well, so a stylesheet can style "system was picked" differently from "it resolved to dark" — which a two-state switch has no way to express.

A round button instead

createThemeToggle(el, { variant: 'button' });
.dxm-button { border-radius: 999px; }

It cycles light → dark → system, and its aria-label names what it will do next rather than what it currently is — because a button's label should describe its action.

Updated 15 Sep 2026