Getting started
Beautiful UI story charts and components are source files you own. The shadcn CLI copies them into your project, together with a small foundation of design tokens and motion presets. There is no runtime package to keep up to date.
Requirements and compatibility
- React 19. Components take
refas a plain prop (noforwardRef), which React 18 doesn't support. - Tailwind CSS v4 only. The installed CSS uses v4's cascade layers and theme variables; Tailwind v3 projects are not supported.
- A
components.json(runnpx shadcn@latest initif you don't have one) and the@/*import alias pointing at your source root. Tested with shadcn CLI 4.21.0. - Bundler or ESM module resolution (
"moduleResolution": "bundler"intsconfig.json, the Next.js and Vite default): some dependencies, such as @tanstack/react-table v9, are ESM-only. - Tested in Next.js (Base UI and Radix projects) and Vite (Radix). Other React 19 setups with Tailwind v4, such as React Router or Astro with React, should work but are untested.
- Current browsers: Lumen uses
color-mix(),:has()and cascade layers (Chrome and Edge 111+, Safari 16.4+, Firefox 121+).
A few items are written against a current major of a library. If your app is on an older major (check package.json), it has to move to this one to use them, so check that the rest of your app works with it first:
@tanstack/react-tablev9 (upgrade from v8 or older; ESM-only, so the project needs bundler or ESM module resolution): Data Explorer, Customer Intelligence, SaaS Analytics.react-day-pickerv10 (upgrade from v9 or older): Calendar, Date Picker, Filter Bar, Data Explorer, Date Compare, Customer Intelligence, SaaS Analytics.react-resizable-panelsv4 (upgrade from v3 or older): Resizable, Split View.
1. Add the registries
Add both registries to components.json. The Pro one only works with a token, but adding it now means you never have to touch this file again. With them, @beautiful-ui/<name> and @beautiful-ui-pro/<name> install the build that matches your style: radix-*, new-york and default get Radix, base-* gets Base UI.
{
"registries": {
"@beautiful-ui": "https://beautiful-ui.dev/r/{style}/{name}.json",
"@beautiful-ui-pro": {
"url": "https://beautiful-ui.dev/r/pro/{style}/{name}.json",
"headers": { "Authorization": "Bearer ${BEAUTIFUL_UI_TOKEN}" }
}
}
}2. Install a component
Free components also install by URL with no setup. The URL names the build, so use the one for your project's primitives (the style in components.json):
npx shadcn@latest add https://beautiful-ui.dev/r/lumen-button.json https://beautiful-ui.dev/r/lumen-switch.jsonnpx shadcn@latest add https://beautiful-ui.dev/r/radix-nova/lumen-button.json https://beautiful-ui.dev/r/radix-nova/lumen-switch.jsonnpx shadcn@latest add @beautiful-ui-pro/lumen-commandThe bare URL always installs the Base UI build, of the item and of its dependencies, so a Radix project needs the /r/radix-nova/ URL or the registries. Pro items need your key in BEAUTIFUL_UI_TOKEN (see Pro setup).
Components land in components/ui/lumen/ as source you own, with shared code in lib/beautiful-ui/lumen/. The first one also adds Lumen's foundation (its --lumen-* tokens, keyframes and motion levels) to your global stylesheet. Each component's styles install into @layer components, so your Tailwind classes always win. Component installs don't change your shadcn tokens.
3. Add the Lumen theme (optional)
The theme is global. It replaces your app's shadcn tokens (--background, --primary, --border and the rest, in light and dark) with Lumen's and adds Geist and Geist Mono, so every shadcn component in the app changes, not just Lumen ones. Skip it to keep your palette: components look right without it. Commit first so you can review the diff.
npx shadcn@latest add https://beautiful-ui.dev/r/lumen.json4. Use it
import { Button } from "@/components/ui/lumen/button";
export default function Page() {
return <Button>Create workspace</Button>;
}5. Sound (optional)
Lumen components mark their moments (a press, a toggle, a success) but ship no audio code: installing them is silent. To hear them, install the sound provider and mount it once. The audio engine loads only when a provider is mounted and sound is on, and nothing plays before the first click or key press.
npx shadcn@latest add https://beautiful-ui.dev/r/glass-sound.jsonimport { GlassSoundProvider, GlassSoundToggle } from "@/components/beautiful-ui/glass-sound";
export default function RootLayout({ children }: { children: React.ReactNode }) {
return (
<html lang="en">
<body>
{/* clicks="components": only Lumen components answer. The default, "all", adds a tap to every button and link. */}
<GlassSoundProvider clicks="components">
<header>
{/* The mute control. The choice is saved in localStorage ("beautiful-ui-sound"). */}
<GlassSoundToggle />
</header>
{children}
</GlassSoundProvider>
</body>
</html>
);
}defaultMuted starts silent until the visitor turns sound on; sound={false} silences one component, and data-sound="off" silences everything inside an element. See Sound for every option.
Theming
Lumen keeps its own colours by default, so it looks like the demos even in a stock shadcn app. Your --foreground, --border and --font-sans always carry through. To use your app's palette instead, add the lumen-inherit class to any ancestor (your <html>, or one section): the accent becomes your --chart-1, series your --chart-N, errors your --destructive. To set Lumen explicitly, override its tokens on :root (for example --lumen-accent or --lumen-radius-k). To re-theme one part of a page, add the lumen-scope class to its container and set the tokens there.
/* Your shadcn palette: add class="lumen-inherit" to <html> (or any section). */
/* Or set Lumen's own tokens: */
:root { --lumen-accent: #0e9f8e; }
.brand-area.lumen-scope { --lumen-accent: #db3f74; }Keep overrides in your own CSS. Each add (and every --overwrite update) writes the registry's CSS into your global stylesheet again, so edits inside the installed Lumen rules are lost. Put your overrides in rules of your own, after them or in a separate file.
Dark and light
Lumen ships both, with separate art direction rather than inverted colours. It follows a .dark class on an ancestor (the shadcn and next-themes convention). Set that class before the first paint (next-themes does) and there is no flash on load.
If your app switches themes with a data-theme attribute instead, set the .dark class as well (with next-themes, attribute={["class", "data-theme"]}). Lumen's own tokens also read [data-theme="dark"], but the Lumen theme's shadcn tokens and Tailwind's dark: variant, as shadcn sets it up, follow .dark only.
Phones and overlays
Components are responsive; Sidebar becomes a sheet below 768px. Overlays (dialogs, menus, popovers) portal to document.body. If you render Lumen inside a scoped container or a shadow root, wrap it in LumenPortalContext so overlays keep its tokens.
Updating
Re-run the add command with --overwrite to pull the latest version of an item. Because the files are yours, review the diff before committing if you changed them. The item's CSS is re-applied too; your own override rules are untouched.
Next
- Set up Pro to install premium items.
- Connect your AI tools so they use Beautiful UI automatically.