npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

demo-workbench

v1.0.4

Published

React demo workbench for browsing and opening project demos/screens.

Readme

logo

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-workbench
import 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 via export 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, blue and brown color presets. Users switch the mode from the header toggle and the color from the title dropdown; both choices persist in localStorage. 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 (its DemoItem.name).
  • isActive?: booleantrue only while opened. Gate expensive work on it.
  • children?: ReactNode — the host overlay from renderDemoContent, 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 (_name files are Sass partials).
  • outputDir - where minified .css is written; serve it at /workbench-css/.
  • compileForWorkbench?: boolean (default true) - scope selectors, add a DevTools sourceURL and write the reload manifest. false = plain production CSS: none of those.
  • assetUrlPrefix?: string - prefix prepended to relative url(...) assets.
  • clean?: boolean (default true) - wipe outputDir before a full compile. false if it holds files managed elsewhere.
  • logs?: boolean (default true) - 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 .js file, exporting a variable named after the final path segment). Entries are { name, load } only; demo CSS lives in export 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 from outputFile to inputDir).

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 --watch

The 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

License