Skip to content

Storybook: single dark/light theme toggle - #646

Open
n400 wants to merge 1 commit into
mainfrom
summer/storybook-theme-toggle
Open

Storybook: single dark/light theme toggle#646
n400 wants to merge 1 commit into
mainfrom
summer/storybook-theme-toggle

Conversation

@n400

@n400 n400 commented Jul 29, 2026

Copy link
Copy Markdown
Contributor

Summary

Replaces the three-item Theme dropdown and the backgrounds-addon color picker with a single
☀/☾ toolbar button that switches the whole preview — story canvas and Docs pages — between
light and dark.

  • .storybook/manager.js (new) — the toolbar toggle button.
  • .storybook/preview.jstheme global + a decorator that emulates prefers-color-scheme
    by patching window.matchMedia (components resolve colorScheme="auto" from it), paints the
    canvas via the semantic --mdhui-background-color-1 token, and themes Docs pages through a
    custom DocsContainer fed by the decorator itself (which receives context.globals through
    the documented API) — no Storybook channel/event internals involved.
  • .storybook/main.js — disables the essentials backgrounds addon (its canvas-color picker
    duplicated/conflicted with the theme button).
  • package.json@storybook/blocks and @storybook/theming promoted from transitive to
    explicit devDependencies (they are now imported directly).

Caveats / things to know

  • Theme state is binary by design to simplify the UI. "System" (follow the OS setting) applies only until the
    first click; after that the pinned light/dark choice sticks and persists in the URL
    (&globals=theme:...), so a shared link carries the pin. A URL without that param follows
    the OS again. There is deliberately no third "System" button state.
  • The matchMedia stub does not emit change events. Components in this repo read the
    scheme at render (and the toggle re-renders every story), so nothing is affected — but a
    future component that subscribes via matchMedia(...).addEventListener('change', …) would
    not hear toolbar toggles.
  • Disabling backgrounds also removes the grid-overlay tool (it ships inside the same
    addon). No story used parameters.backgrounds.

🤖 Generated with Claude Code

@aws-amplify-us-east-1

Copy link
Copy Markdown

This pull request is automatically being deployed by Amplify Hosting (learn more).

Access this pull request here: https://pr-646.d1xp2kmk6zrv44.amplifyapp.com

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR streamlines Storybook theming by replacing the existing Theme dropdown/background controls with a single toolbar toggle that switches both the preview canvas and Docs pages between light and dark modes.

Changes:

  • Added a custom Storybook manager toolbar tool to toggle light/dark and persist the selection via globals.
  • Updated Storybook preview configuration to apply the selected theme by emulating prefers-color-scheme, setting the canvas background token, and theming Docs via a custom DocsContainer.
  • Disabled the essentials backgrounds addon to avoid conflicting/duplicated UI.

Reviewed changes

Copilot reviewed 4 out of 5 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
package.json Adds explicit Storybook deps (@storybook/blocks, @storybook/theming) now imported directly.
package-lock.json Locks dependency graph updates resulting from the new explicit Storybook deps.
.storybook/preview.js Implements theme global, matchMedia emulation, canvas background painting, and themed Docs container.
.storybook/manager.js Adds a single light/dark toolbar toggle powered by globals.theme.
.storybook/main.js Disables essentials backgrounds to avoid conflict with the new theme toggle.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread .storybook/preview.js
Comment on lines +20 to +24
if (typeof window !== "undefined" && window.location) {
const m = /[?&]globals=([^&]*)/.exec(window.location.search);
const pin = m && /(?:^|;)theme:(dark|light)/.exec(decodeURIComponent(m[1]));
if (pin) currentTheme = pin[1];
}
Comment thread .storybook/preview.js
Comment on lines +94 to +96
return {
matches: /dark/.test(query) ? wantsDark : !wantsDark,
media: query,
Comment thread .storybook/preview.js Outdated
Comment on lines +6 to +10
// Docs pages don't run story decorators for their chrome — their background comes from a
// docs theme. Rather than touching Storybook's channel/event internals, the decorator below
// (which receives `context.globals.theme` through the documented API, and re-runs on every
// toggle) publishes the theme into this tiny module-level subscription for the docs container.
let currentTheme = "system";
Replaces the three-item Theme dropdown and the backgrounds-addon color
picker with one toolbar button that switches the story canvas and Docs
pages between light and dark by emulating prefers-color-scheme.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@n400
n400 force-pushed the summer/storybook-theme-toggle branch from d18ea86 to 13d4d85 Compare July 29, 2026 15:19
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants