Toolbar Buttons
Add one-click buttons to the Storybook manager toolbar with a declarative, React-free API
storybook-addon-toolbar-buttons
Add one-click toolbar buttons — toggles, icon buttons, or plain buttons — to the Storybook (v10+) manager toolbar, declaratively.
Consumers never need to install React themselves — Storybook's manager UI already provides it at runtime. This package's build keeps react (and Storybook's own packages) external, so it reuses that copy instead of bundling its own.
Installation
npm install --save-dev storybook-addon-toolbar-buttons
Usage
In .storybook/manager.ts:
import { registerToolbarButtonGroup } from "storybook-addon-toolbar-buttons";
registerToolbarButtonGroup({
id: "my-org/viewport-quick-switch",
title: "Viewport quick switch",
buttons: [
{
label: "D",
tooltip: "Desktop (1280×720)",
pressed: (ctx) => ctx.globals["viewport"]?.value === "desktop",
onClick: (ctx) => ctx.updateGlobals({ viewport: { value: "desktop", isRotated: false } }),
},
// ...
],
});
Each button's callbacks receive ctx = { globals, storyGlobals, updateGlobals }. To disable a button when a story has locked its globals, use something like disabled: (ctx) => ctx.storyGlobals['viewport'] !== undefined.
label, tooltip, disabled, icon, className, style, and pressed all accept either a plain value or a function of ctx that computes one — e.g. label: (ctx) => (ctx.globals['viewport']?.value === 'desktop' ? 'D ✓' : 'D').
Each button also accepts a variant to pick which Storybook component it renders as:
'toggle'(default) — highlights whilepressedis true. Requirespressed.'icon'— a plain button with no pressed state, intended for icon-only content.'button'— a plain button with no pressed state, intended for text content.
Other optional fields:
icon— name of a@storybook/iconsexport (e.g.'EyeIcon') to show instead oflabel. Falls back tolabelif the name doesn't match an icon export.className/style— extra styling for the button element.stylekeys are DOM style properties in camelCase (e.g.backgroundColor), not CSS property names.
See index.d.ts for the full API.
Development
bun install
bun run check # tsc --noEmit — also checks that the implementation matches the index.d.ts signature
bun run build # bundles src/index.tsx to dist/index.js via `bun build`
The public API's source of truth is the hand-written index.d.ts. The implementation (src/index.tsx) is annotated with typeof import('../index'), which catches a renamed/removed field the implementation reads or an incompatible return type — but not every kind of drift (e.g. a new parameter or an unused new required field compiles fine either side).
dist/ is what's published to npm (see exports and files in package.json); src/ is not. prepublishOnly runs check and build automatically before npm publish.
License
MIT