burne-ui-devtools
burne-ui-devtools
Runtime theme editor for applications using BurneUIProvider.
Compatibility
burne-ui-devtools requires burne-ui >=1.5.10 <2. Earlier releases do not
provide the runtime theme API and custom-token support used by the editor.
Both stylesheets are required:
import "burne-ui/styles.css";
import "burne-ui-devtools/styles.css";
The component must be rendered inside BurneUIProvider.
Vite: lazy, development-only loading
This keeps the devtools JavaScript out of production builds. Put the required stylesheet imports in the application entry file.
import { lazy, Suspense } from "react";
import { BurneUIProvider } from "burne-ui";
import "burne-ui/styles.css";
import "burne-ui-devtools/styles.css";
import burneTheme from "./burne-theme";
const BurneThemeDevtools = import.meta.env.DEV
? lazy(() =>
import("burne-ui-devtools").then(({ BurneThemeDevtools }) => ({
default: BurneThemeDevtools,
})),
)
: null;
export function App() {
return (
<BurneUIProvider config={burneTheme}>
<YourApp />
{BurneThemeDevtools ? (
<Suspense fallback={null}>
<BurneThemeDevtools />
</Suspense>
) : null}
</BurneUIProvider>
);
}
Next.js: dynamic, development-only loading
Import the global styles from app/layout.tsx:
import "burne-ui/styles.css";
import "burne-ui-devtools/styles.css";
Create a client component such as app/BurneDevtools.tsx:
"use client";
import dynamic from "next/dynamic";
const DevelopmentDevtools =
process.env.NODE_ENV === "development"
? dynamic(
() =>
import("burne-ui-devtools").then(
({ BurneThemeDevtools }) => BurneThemeDevtools,
),
{ ssr: false },
)
: null;
export function BurneDevtools() {
return DevelopmentDevtools ? <DevelopmentDevtools /> : null;
}
Render <BurneDevtools /> anywhere below the client-side BurneUIProvider.
The production branch does not request the devtools module.
Custom tokens
All customTokens from the provider config appear in the editor. Primitive
shorthand values infer a suitable control:
import type { BurneThemeConfig } from "burne-ui";
export const burneTheme: BurneThemeConfig = {
theme: "system",
customTokens: {
"--app-sidebar-width": "18rem",
"--app-dense-mode": false,
"--app-card-opacity": 0.9,
},
};
Use metadata to control the label, group, description, input type, and range:
export const burneTheme: BurneThemeConfig = {
customTokens: {
"--app-card-opacity": {
value: 0.9,
label: "Card opacity",
group: "Application",
description: "Opacity used by elevated application cards.",
control: "slider",
min: 0.5,
max: 1,
step: 0.05,
unit: "×",
},
"--app-density": {
value: "comfortable",
label: "Density",
group: "Application",
control: "select",
options: [
{ label: "Compact", value: "compact" },
{ label: "Comfortable", value: "comfortable" },
],
},
},
};
Use values for mode-specific values. The active light or dark value is edited
without replacing the other mode:
export const burneTheme: BurneThemeConfig = {
theme: "system",
customTokens: {
"--app-hero-surface": {
values: {
light: "#f7f8ff",
dark: "#111522",
},
label: "Hero surface",
group: "Application colors",
control: "color",
},
},
};
Font presets (Google Fonts)
Choosing a sans/mono preset only writes --font-family-* tokens. The matching
Google Font file is lazy-loaded by the editor when you select the preset or
when a persisted snapshot is restored:
preconnecttofonts.googleapis.com/fonts.gstatic.com(once).- Inject a stylesheet for that family only (
data-burne-theme-font). - Skip system stacks and unknown custom CSS stacks (no network request).
Helpers you can reuse outside the panel:
import {
ensureThemeFontLoaded,
FONT_PRESETS,
THEME_SANS_FONTS_URL,
THEME_MONO_FONTS_URL,
} from "burne-ui-devtools";
ensureThemeFontLoaded(FONT_PRESETS.find((p) => p.id === "inter"));
// or preload every preset family in docs layout:
// <link rel="stylesheet" href={THEME_SANS_FONTS_URL} />
Production: do not rely on the editor to load fonts. After you pick a face,
ship it yourself (self-host, next/font, or a single Google Fonts <link> for
the families you keep in burne-theme.ts). Copy/Download config only exports
the CSS stack string — not font files.
Actions
- Reset clears the preview and persisted editor snapshot, then restores the
provider's base theme preference (including
system) and token values. - Shuffle picks a random color preset, Scale slider values, and sans/mono fonts. Motion and animation toggles are left unchanged.
- Copy CSS copies the current theme as CSS custom properties.
- Copy config copies a serializable
BurneThemeConfigsource. - Download config downloads the current configuration as
burne-theme.ts.
Control ranges (min / max / step)
Edit slider bounds in
src/BurneThemeDevtools/burneThemeDevtoolsData.ts:
SCALE_CONTROLS— spacing, size, radius, border, type scale (also used by Shuffle)SHADOW_CONTROLS— shadow / toast scrimMOTION_DURATION_CONTROLS/MOTION_SCALE_CONTROLS— motion section
Custom token sliders use min / max / step from the token metadata in your
burne-theme.ts customTokens entry.
Props
enabled?: boolean— explicit runtime switch, defaulttrue. A detectedprocess.env.NODE_ENV === "production"always disables the component.persist?: boolean— localStorage persistence, defaulttrue.storageKey?: string— persistence key, defaultburne-ui-devtools.defaultOpen?: boolean— render the editor open initially.className?: string— class added to the fixed portal root.
For browser builds that do not expose process.env.NODE_ENV, pass the
application's own development flag to enabled.