Base components
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 forThemeToggle 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 forThemeToggle 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.
| Key | Action |
|---|---|
| Tab | Moves focus to the next button. |
| Shift + Tab | Moves focus to the previous button. |
| Enter or Space | Switches 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:
| Variant | Light | Dark |
|---|---|---|
ghost | 16.1:1 | 14.2:1 |
secondary | 11.9:1 | 7.3:1 |
| Focus outline | 5.2:1 | 6.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-labelwhen 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
Put it at the end of the app's header, where people look for it.
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.