BlockDex

Components

Registries

Free blocks

Method

BlockDex

Components

Registries

Free blocks

Method

Open API

BlockDex

Components

Registries

Free blocks

Method

Open API

Components/@nswds/ui/theme-switcher

Theme Switcher

nswds-ui/theme-switcher
FreeComponent

Light/dark toggle button with controlled and uncontrolled modes — framework-free, wire it to next-themes or any theme store.

Install it

npx shadcn@latest add https://raw.githubusercontent.com/digitalnsw/nswds-ui/main/apps/registry/public/r/theme-switcher.json

Source

src/components/theme-switcher.tsxraw.githubusercontent.com/digitalnsw/nswds-ui/main/apps/registry/public/r/theme-switcher.json
1'use client'
2
3import React from 'react'
4
5import { IconDarkMode } from '@/icons/dark-mode'
6import { IconLightMode } from '@/icons/light-mode'
7
8import { Button, type ButtonProps } from '@/components/button'
9
10/** The two colour schemes the switcher toggles between. */
11type ThemeSwitcherTheme = 'light' | 'dark'
12
13type ThemeSwitcherProps = Omit<ButtonProps, 'children'> & {
14 /**
15 * Current theme (controlled). When set, the component never updates its own
16 * state — wire `onThemeChange` back into whatever owns the theme (see the
17 * next-themes snippet on the Storybook docs page). Pick one mode per
18 * instance: don't switch between supplying and omitting `theme` across
19 * renders.
20 */
21 theme?: ThemeSwitcherTheme
22 /** Initial theme when uncontrolled. Defaults to `'light'`. */
23 defaultTheme?: ThemeSwitcherTheme
24 /**
25 * Called with the NEXT theme (the one the user asked for) on every
26 * activation, in both controlled and uncontrolled modes.
27 */
28 onThemeChange?: (theme: ThemeSwitcherTheme) => void
29}
30
31/**
32 * Light/dark theme toggle button, ported from nswds-app's `ThemeSwitcher`
33 * minus its `next-themes` dependency — a design system cannot depend on a
34 * theming framework, so this is a plain controlled/uncontrolled input
35 * (`theme` / `defaultTheme` / `onThemeChange`) and the app owns the plumbing.
36 * All other props pass through to `Button` (defaults: `variant='surface'`,
37 * `color='grey'`, `size='icon'` — the source's `color='light'` does not exist
38 * on this Button; `grey` is its nearest ink).
39 *
40 * The icon depicts the DESTINATION: a moon (`IconDarkMode`) while the theme is
41 * light, a sun (`IconLightMode`) while it is dark — matching the source and
42 * the action-phrased label below.
43 *
44 * Accessibility contract:
45 * - The `aria-label` announces the ACTION ("Switch to dark theme"), not the
46 * state, and flips after each activation so the control always names what
47 * pressing it will do (WCAG 2.2, 4.1.2 Name, Role, Value). The source
48 * duplicated the same words in an `sr-only` span AND the `aria-label`; the
49 * span is dropped here because a control with both gets its name announced
50 * twice by common screen readers (label, then descendant text).
51 * - No `aria-pressed`. This is a mode switch between two peer states, each
52 * with its own action label — not a pressed/unpressed toggle of a single
53 * action. Combining `aria-pressed` with a flipping label is actively
54// … truncated

What it pulls in

Other registry items

  • https://ui.digital.nsw.gov.au/registry/r/theme.json
  • https://ui.digital.nsw.gov.au/registry/r/button.json
  • https://ui.digital.nsw.gov.au/registry/r/icons.json

Files it writes

  • src/components/theme-switcher.tsx

Facts

Registry
@nswds/ui
Type
registry:ui
Access
Free
Files written
1
Licence
MIT
In the index
at or before 2026-08-20
Last confirmed
today

Go to the source

ui.digital.nsw.gov.au digitalnsw/nswds-ui on GitHub Raw registry item This item as JSON

More from @nswds/ui

All 46 items
Same registry, same kind — the ones you would have found next
ComponentRegistryKindAccessInstallsCommand
Aspect Ratioaspect-ratio@nswds/uiComponentsFree2 deps · 2 files
Badgebadge@nswds/uiComponentsFree4 deps · 2 files
Buttonbutton@nswds/uiComponentsFree4 deps · 2 files
Cardcard@nswds/uiComponentsFree2 deps · 2 files
Collapsiblecollapsible@nswds/uiComponentsFree1 dep
Drawerdrawer@nswds/uiComponentsFree3 deps · 2 files
Expandable Searchexpandable-search@nswds/uiComponentsFree3 deps · 2 files
Fieldfield@nswds/uiComponentsFree4 deps · 2 files

Also from Kynth Studios

Built for the same person as BlockDex

SkillWorks

Claude Code skills and plugins, scored

skillworks.kynth.studio

RuleStack

AGENTS.md gallery and agent-config comparison

rulestack.kynth.studio

KitGrade

SaaS starter kits, scored on what can be checked

kitgrade.kynth.studio

The studio list

One product, taken apart, once a month

Kynth Studios pulls one shipped product open every month — what it does, what it cost to build, what the pipeline behind it looks like, and what the numbers did. One email a month, nothing in between.

Double opt-in — we send one confirmation link and nothing else until you click it.

BlockDex

Built by

Kynth Studios

the studio behind SkillWorks, RuleStack and KitGrade

part of Toolproof, the measurement layer for AI agent tooling

Index

Components
Registries
Method
Open API

Guides

shadcn component libraries
Best shadcn registries
Free shadcn blocks

Reference

Corpus counts
Crawl health
hello@kynth.studio
Privacy
Terms

© 2026 BlockDex. A Kynth Studios product. Changelog

BlockDex

The studio list

One product, taken apart, once a month

Kynth Studios pulls one shipped product open every month — what it does, what it cost to build, what the pipeline behind it looks like, and what the numbers did. One email a month, nothing in between.

Double opt-in — we send one confirmation link and nothing else until you click it.

BlockDex

Built by

Kynth Studios

the studio behind SkillWorks, RuleStack and KitGrade

part of Toolproof, the measurement layer for AI agent tooling

Index

Components
Registries
Method
Open API

Guides

shadcn component libraries
Best shadcn registries
Free shadcn blocks

Reference

Corpus counts
Crawl health
hello@kynth.studio
Privacy
Terms

© 2026 BlockDex. A Kynth Studios product. Changelog

BlockDex

The studio list

One product, taken apart, once a month

Kynth Studios pulls one shipped product open every month — what it does, what it cost to build, what the pipeline behind it looks like, and what the numbers did. One email a month, nothing in between.

Double opt-in — we send one confirmation link and nothing else until you click it.

BlockDex

Built by

Kynth Studios

the studio behind SkillWorks, RuleStack and KitGrade

part of Toolproof, the measurement layer for AI agent tooling

Index

Components
Registries
Method
Open API

Guides

shadcn component libraries
Best shadcn registries
Free shadcn blocks

Reference

Corpus counts
Crawl health
hello@kynth.studio
Privacy
Terms

© 2026 BlockDex. A Kynth Studios product. Changelog

BlockDex