Skip to content

Repository files navigation

dev-console

A keyboard-triggered command palette for React apps — active during development and staging, a genuine no-op in production.

Press / anywhere in your app to open the palette. Type to filter commands. Press Enter to open a panel. Press Escape to close.

Installation

# From GitHub
yarn add git+https://github.com/<your-org>/dev-console.git

Basic usage

import{DevConsoleProvider}from'dev-console'importtype{DevCommand}from'dev-console'constcommands: DevCommand[]=[{name: 'state',description: 'Inspect current app state',panel: StatePanel,},]exportfunctionApp(){return(<DevConsoleProvidercommands={commands}><YourApp/></DevConsoleProvider>)}

Built-in commands

These are always registered — no configuration needed:

CommandDescription
/logView entries written via useDevLog()
/envInspect all import.meta.env variables

Logging from anywhere

import{useDevLog}from'dev-console'functionMyComponent(){const{ log }=useDevLog()useEffect(()=>{log('Component mounted',{id: 42})},[log])}

log(message, data?)data is optional and displayed as formatted JSON in the /log panel.

Console capture

In dev mode, console.log, console.warn, and console.error are automatically captured and forwarded to the /log panel. Each entry shows a coloured level badge (log / warn / error). The original console methods still work normally — capture is purely additive.

Persistent panels

By default panels close on Escape and backdrop click. Set persistent: true on a command to keep the panel open — the app remains fully interactive behind it, and a left/right dock toggle appears in the panel header so you can move it out of the way.

constcommands: DevCommand[]=[{name: 'state',description: 'App state',panel: StatePanel,persistent: true},]

The built-in /log command is persistent by default. /env is not.

Registering custom commands

A command is a { name, description?, panel, persistent? } object where panel is any React component that takes no props:

importtype{DevCommand}from'dev-console'constcommands: DevCommand[]=[{name: 'state',description: 'App state',panel: StatePanel},{name: 'flags',description: 'Feature flags',panel: FlagsPanel},]

Pass the array to <DevConsoleProvider commands={commands}>. Built-in commands always appear first. If you register a command with the same name as a built-in, your command is silently dropped.

CSS overrides

All visual tokens are CSS custom properties. Override any of them on :root or an ancestor element:

:root {
--dc-bg:#ffffff;
--dc-border:#e0e0e0;
--dc-text:#111111;
--dc-text-muted:#666666;
--dc-accent:#0070f3;
--dc-overlay:rgba(0,0,0,0.3);
--dc-radius:8px;
--dc-font: system-ui, sans-serif;
}

Production exclusion

DevConsoleProvider is safe to import unconditionally. The library checks the environment internally:

  • Active when import.meta.env.DEV === true (Vite dev server)
  • Active when import.meta.env.VITE_ENABLE_DEV_CONSOLE === 'true' (explicit opt-in)
  • Otherwise: renders only {children} — no listeners, no overlay, no bundle weight

Staging setup — enable in a production build without touching source code:

VITE_ENABLE_DEV_CONSOLE=true vite build

Or set the variable in your CI/staging environment.

Running the example app

cd example
yarn install
yarn dev

API

<DevConsoleProvider>

PropTypeDescription
commandsDevCommand[]Consumer-defined commands to register
childrenReactNodeYour app

DevCommand

typeDevCommand={name: string// shown in palette, used for filteringdescription?: string// shown as subtitle in palettepanel: React.ComponentType<object>// rendered when command is activated, must take no propspersistent?: boolean// if true, panel stays open; app stays interactive behind it}

useDevLog()

Returns { log: (message: string, data?: unknown) => void }. No-op in production.

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages