demo-workbench
v1.0.4
Published
React demo workbench for browsing and opening project demos/screens.
Maintainers
Readme

Table of contents
About
demo-workbench is a small React shell for browsing and opening project demos/screens.
Use it for component libraries, visual experiments, scroll demos, style systems and project UI sandboxes. It is not a docs system or Storybook replacement. It gives you a reusable grid/search/theme/opened-demo shell plus a small compile step. The package owns the shell. Your project owns the demos, styles and generated manifest file.
Installation
npm install demo-workbenchimport DemoWorkbench from "demo-workbench";Workbench shell styles are injected by the package automatically when DemoWorkbench is imported.
✦ Note:
- Supports both ESM (
import) and CommonJS (require) builds.- Written with React and ships TypeScript declaration files.
- The package injects reusable shell styles automatically from its main JS bundle.
- Project CSS is loaded through
styleLoader; demos only declare CSS names viaexport const cssFiles.- React and React DOM are peer dependencies, so the host app keeps one React instance.
- Ships a flat light/dark UI with
grey,blueandbrowncolor presets. Users switch the mode from the header toggle and the color from the title dropdown; both choices persist inlocalStorage. No configuration is required.
Quick start
1. Compile — generate the demo manifest and compile your CSS into scoped, workbench-ready files:
// scripts/workbenchCompile.js
import { runWorkbenchCompile } from "demo-workbench/node";
runWorkbenchCompile({
styles: { inputDir: "src/styles/scss", outputDir: "src/styles/workbench-css" },
demos: { inputDir: "src/screens", outputFile: "src/screens/demos" },
});Run node scripts/workbenchCompile.js (add --watch for hot style reload) and serve styles.outputDir at /workbench-css/.
2. Render the shell with the generated manifest:
import DemoWorkbench from "demo-workbench";
import demos from "./screens/demos.js";
export default function App() {
return (
<DemoWorkbench
demos={demos}
styleLoader="/workbench-css/"
baseStyles={["reset", "ui-elements"]}
/>
);
}Each demo is a normal React component that declares its scoped CSS with export const cssFiles = [...]. See the API for every prop, both styleLoader forms, demo component props and all compile options.
API
— REACT —
Usage:
import DemoWorkbench from "demo-workbench";
import projectDemos from "./workbench/projectDemos.js";
export default function App() {
return (
<DemoWorkbench
title="My Project Demos"
demos={projectDemos}
styleLoader="/workbench-css/"
baseStyles={["output", "theme"]}
/>
);
}Description: Renders the header, search, theme controls, demo grid, opened-demo modal and persisted workbench state. Pass the generated manifest and an optional styleLoader.
Props:
title?: string- shell title shown in the workbench header and document title.demos: DemoItem[]- generated host-owned demo manifest.styleLoader?: string | ((name: string) => unknown | Promise<unknown>)- URL prefix for static CSS files, or a custom CSS text loader.baseStyles?: string[]- host-level CSS atoms loaded by the shell.autoScale?: false | { width?: number | null; height?: number | null }- optional opened-demo auto scale reference.renderDemoContent?: (pageName: string) => ReactNode- project layer rendered inside opened demos.bodyBg?: string- background value for the opened demo body.
The workbench renders its own empty/search placeholders.
Use styleLoader="/workbench-css/" when styles.outputDir is served as static files. Use a function only for custom loading or CSS-as-text bundler imports.
Use autoScale only for demos designed around a known canvas or screen size. Omit it to test native responsive behavior.
Return: Returns a React element containing the complete reusable workbench shell.
URL prefix (recommended). Serve styles.outputDir as static files and pass its public URL prefix; "/workbench-css/" loads reset from /workbench-css/reset.css. It is a public URL prefix, not a filesystem path:
<DemoWorkbench demos={demos} styleLoader="/workbench-css/" />Custom function (advanced). For a CDN, auth, or a bundler that imports CSS as text:
<DemoWorkbench
demos={demos}
styleLoader={(name) => import(`./workbench-css/${name}.css?raw`)}
/>A demo declares its scoped CSS by exporting cssFiles next to the component. Values are compiled file names from styles.outputDir, without .css:
// src/screens/ProfileCardDemo.tsx
export const cssFiles = ["profile-card", "shared-layout"];
export default function ProfileCardDemo() {
return /* ... */;
}Use baseStyles for shell-wide CSS such as reset, tokens or keyframes. Omit cssFiles when a demo needs no scoped CSS.
A demo's default export is a normal React component. The workbench renders it in grid and opened modes, and passes:
pageName?: string— the demo's stable name (itsDemoItem.name).isActive?: boolean—trueonly while opened. Gate expensive work on it.children?: ReactNode— the host overlay fromrenderDemoContent, provided only when opened. Render it wherever the demo wants the project layer.
export default function ProfileCardDemo({ isActive, children }) {
return (
<div className="screen">
{isActive ? <HeavyAnimation /> : <StaticPreview />}
{children}
</div>
);
}— NODE —
Usage:
import { runWorkbenchCompile } from "demo-workbench/node";
runWorkbenchCompile({
styles: {
inputDir: "src/styles/scss",
outputDir: "src/styles/workbench-css",
assetUrlPrefix: "http://localhost:3000/img/",
},
demos: {
inputDir: "src/demos",
outputFile: "src/workbench/projectDemos",
},
});Both sections are optional and can be used independently.
styles options — compile .css/.scss/.sass into workbench CSS:
inputDir- source dir of top-level style files (_namefiles are Sass partials).outputDir- where minified.cssis written; serve it at/workbench-css/.compileForWorkbench?: boolean(defaulttrue) - scope selectors, add a DevToolssourceURLand write the reload manifest.false= plain production CSS: none of those.assetUrlPrefix?: string- prefix prepended to relativeurl(...)assets.clean?: boolean(defaulttrue) - wipeoutputDirbefore a full compile.falseif it holds files managed elsewhere.logs?: boolean(defaulttrue) - Sass/CSS compiler warnings/output. CLI progress is always printed.
demos options — discover demos and write the manifest:
inputDir- dir of demo modules; file basenames become demo names.outputFile- manifest path without extension (writes a.jsfile, exporting a variable named after the final path segment). Entries are{ name, load }only; demo CSS lives inexport const cssFiles.extensions?: string[](default[".jsx", ".tsx", ".js", ".ts"]) - scanned file extensions.exclude?: string[]- demo basenames to skip.importPathPrefix?: string- import prefix used inside the manifest (defaults to the relative path fromoutputFiletoinputDir).
Import the generated manifest:
import projectDemos from "./workbench/projectDemos.js";Run it as a command:
— one launch —
node src/scripts/workbenchCompile.js— watch mode —
node src/scripts/workbenchCompile.js --watchThe host builder/dev-server must expose styles.outputDir at /workbench-css/:
// webpack-dev-server example
static: [
{
directory: path.join("src", "styles", "workbench-css"),
publicPath: "/workbench-css/",
watch: false,
},
];Description: Main Node entry for host scripts. It runs one compile by default and switches to watch mode for --watch or watch.
📋 demo-workbench
— preparing...
✓ styles compiled (12)
✓ demos discovered (54)
✓ style reload enabled