Skip to main content

Theme Toggle

BetaSince 0.2.0

Switches the app between its light and dark theme in one click.

import { ThemeToggle } from "@anantya/uix";

Overview

Use a theme toggle in your app's header to switch between the light and dark theme in one click. It shows a sun in the light theme and a moon in the dark one, right from the first paint, and works with the ThemeProvider above it.

Pressing it saves the reader's pick, so the app stops following the device's setting. To let the reader go back to following the device, add a Match my device Switch on your settings page, as on the Theme Provider page.

Playground

Note

The playground for ThemeToggle is coming soon.

Examples

At the end of an app's header, in ghost, the default. Each toggle on this page switches this whole page.

Mehta Textiles

Code
import { Bell } from "@anantya/icons";
import { IconButton, ThemeToggle } from "@anantya/uix";

export default function InHeader() {
return (
<header className="flex w-full max-w-md items-center gap-1 rounded-xl border border-border bg-surface py-2 pr-2 pl-4">
<p className="mr-auto text-sm font-semibold">Mehta Textiles</p>
<IconButton variant="ghost" aria-label="Notifications">
<Bell />
</IconButton>
<ThemeToggle />
</header>
);
}

ghost suits a header or toolbar. secondary gives it an edge, such as on a settings page.

Code
import { ThemeToggle } from "@anantya/uix";

export default function Variants() {
return (
<>
<ThemeToggle />
<ThemeToggle variant="secondary" />
</>
);
}

Two sizes: md, 36px, is the default, and sm, 32px, fits a dense toolbar.

Code
import { ThemeToggle } from "@anantya/uix";

export default function Sizes() {
return (
<>
<ThemeToggle size="sm" variant="secondary" />
<ThemeToggle variant="secondary" />
</>
);
}

Props

Note

The props table for ThemeToggle is coming soon.

Accessibility

It follows the WAI-ARIA button pattern for a toggle button: a <button type="button"> with aria-pressed, pressed while the theme is dark.

KeyAction
TabMoves focus to the next button.
Shift + TabMoves focus to the previous button.
Enter or SpaceSwitches to the other theme. Focus stays on the toggle.

Screen readers

  • A screen reader announces it as a toggle button named "Dark theme", pressed or not, such as "Dark theme, toggle button, not pressed". Its icon is hidden from screen readers
  • Its name stays the same in both themes, since pressed or not says which is on

Contrast

Its icon needs 3:1, as does the focus outline. The lowest contrast at rest, on hover and while pressed, on the page and in a dialog:

VariantLightDark
ghost16.1:114.2:1
secondary11.9:17.3:1
Focus outline5.2:16.7:1

The page cross-fades once when the theme changes, and switches at once when the reader prefers reduced motion. With forced colors on, such as Windows high contrast, it draws in system colors.

WCAG 2.2

  • 1.4.11 Non-text Contrast, in light and dark
  • 2.1.1 Keyboard: Enter and Space switch the theme
  • 2.4.7 Focus Visible: a focus outline shows on keyboard focus
  • 2.5.8 Target Size (Minimum): it is at least 32 by 32px
  • 4.1.2 Name, Role, Value: a native button with its pressed state

axe checks every example on this page in CI, in light and dark, in Chromium, Firefox and WebKit.

What your app still has to do

  • Mount ThemeProvider above it, in the root layout
  • Translate its name with aria-label when your app isn't in English, such as "Dunkles Design" in German
  • Show one theme toggle per screen, in the same place on every screen

Do / Don't

Mehta Textiles

Put it at the end of the app's header, where people look for it.

Invoice total ₹48,500

Don't put it in the middle of a page's content. It changes the whole app, not that content.

Keep its name, Dark theme, the same in both themes.

Don't name it after the change, such as Switch to light. A screen reader user hears the name and pressed or not, which then contradict each other.

Changelog

Every change to Theme Toggle since 0.2.0 is in the release notes.

© Anantya TechLabs. All rights reserved.