bn-dashboard
v0.10.1
Published
Reusable React dashboard component library
Readme
bn-dashboard
A React component library for building glassmorphic admin dashboards. Includes layout templates, navigation, data-display components, and a two-theme (light/dark) token system.
Installation
npm install bn-dashboardFor local development against an unpublished build, see Local development below.
Setup
Three things must happen once at the app root before any components render.
1. Import the stylesheet
// Next.js: app/layout.tsx or pages/_app.tsx
// Vite: main.tsx / index.tsx
import 'bn-dashboard/style.css';This single file contains all component styles and CSS custom-property tokens.
2. Load the fonts
The library does not bundle fonts. It expects Poppins (headings) and Inter (body) to be available.
Next.js (recommended):
// app/layout.tsx
import { Poppins, Inter } from 'next/font/google';
const poppins = Poppins({ subsets: ['latin'], weight: ['400', '600'] });
const inter = Inter({ subsets: ['latin'] });HTML <head> (any framework):
<link rel="preconnect" href="https://fonts.googleapis.com" />
<link
href="https://fonts.googleapis.com/css2?family=Inter:wght@400;600&family=Poppins:wght@400;600&display=swap"
rel="stylesheet"
/>If neither font loads the library falls back to system-ui — everything remains readable.
3. Add bn-root and a theme
bn-root activates the token layer. data-theme selects light or dark:
// Next.js app/layout.tsx
<html lang="en" data-theme="dark">
<body className="bn-root">
{children}
</body>
</html>Valid values: "light" (default) · "dark"
Quick start
'use client'; // Next.js — see note below
import { useState } from 'react';
import {
BnSidenavLayout, BnSidebar, BnBrand,
BnNavItem, BnDivider, BnHeader, BnButton,
} from 'bn-dashboard';
const IconHome = () => (
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" aria-hidden="true">
<path d="M2 7L8 2l6 5v7a1 1 0 01-1 1H3a1 1 0 01-1-1V7z" stroke="currentColor" strokeWidth="1.4"/>
</svg>
);
export default function AppShell({ children }: { children: React.ReactNode }) {
const [collapsed, setCollapsed] = useState(false);
return (
<BnSidenavLayout
sidebar={
<BnSidebar
collapsed={collapsed}
onToggle={() => setCollapsed(v => !v)}
brand={<BnBrand name="My App" logoSize={28} />}
>
<BnNavItem label="Dashboard" icon={<IconHome />} active />
<BnDivider />
</BnSidebar>
}
header={
<BnHeader
title="Dashboard"
bare
actions={<BnButton size="sm">New Report</BnButton>}
/>
}
>
{children}
</BnSidenavLayout>
);
}Next.js — server components
All components use useState, useRef, or React context and must run on the client. Keep your layout shell in a dedicated file marked 'use client' and import it from your server root layout:
// app/layout-shell.tsx
'use client';
export { AppShell } from './AppShell';// app/layout.tsx (server component)
import 'bn-dashboard/style.css';
import { AppShell } from './layout-shell';
export default function RootLayout({ children }) {
return (
<html lang="en" data-theme="dark">
<body className="bn-root">
<AppShell>{children}</AppShell>
</body>
</html>
);
}Theme switching
// Dark
document.documentElement.setAttribute('data-theme', 'dark');
// Light (remove attribute — light is the default)
document.documentElement.removeAttribute('data-theme');Follow OS preference on first load:
if (window.matchMedia('(prefers-color-scheme: dark)').matches) {
document.documentElement.setAttribute('data-theme', 'dark');
}Accent colour
The default accent is sage green. Change it for your brand using BnAccentUtils.applyToRoot:
import { BnAccentUtils } from 'bn-dashboard';
// Call once at app startup
BnAccentUtils.applyToRoot('#6366f1'); // indigoThis derives all four accent tokens (--bn-color-accent, --bn-color-accent-hover, --bn-color-accent-subtle, --bn-color-accent-contrast) and automatically selects a legible contrast colour.
To derive tokens without applying them (e.g. to store in state):
const tokens = BnAccentUtils.derive('#6366f1');
// { accent, accentHover, accentSubtle, accentContrast }Background gradient
The ambient gradient behind all glass panels is a CSS custom property. Override it in your own stylesheet after importing bn-dashboard/style.css:
:root {
--bn-bg-gradient:
radial-gradient(ellipse at 20% 40%, rgba(99, 102, 241, 0.18) 0%, transparent 50%),
radial-gradient(ellipse at 80% 80%, rgba(236, 72, 153, 0.12) 0%, transparent 45%);
}
[data-theme="dark"] {
--bn-bg-gradient:
radial-gradient(ellipse at 20% 50%, rgba(99, 102, 241, 0.25) 0%, transparent 50%),
radial-gradient(ellipse at 80% 85%, rgba(236, 72, 153, 0.20) 0%, transparent 45%);
}Component reference
| Export | Category | Description |
|---|---|---|
| BnSidenavLayout | Layout | Full-height layout: collapsible sidebar + header + scrollable main |
| BnDashboardLayout | Layout | Alias of BnSidenavLayout |
| BnTopnavLayout | Layout | Full-height layout: top navigation bar + scrollable main |
| BnSidebar | Layout | Collapsible glass sidebar with brand slot and nav items |
| BnBrand | Layout | Logo / letter-avatar + name, collapses with sidebar |
| BnPanel | Layout | Glass card container |
| BnGrid | Layout | Responsive CSS-grid wrapper |
| BnDivider | Layout | Thin rule for sidebar sections |
| BnHero | Layout | Full-width hero / banner panel |
| BnHeader | Navigation | Page header with title, actions slot; optional bare mode |
| BnNavItem | Navigation | Sidebar nav item with icon, active state, tooltip on collapse |
| BnBreadcrumb | Navigation | Breadcrumb trail |
| BnTabs | Navigation | Horizontal tab bar |
| BnButton | Actions | Button with size, variant, intent, icon slots |
| BnBadge | Data display | Inline status badge |
| BnAlert | Data display | Dismissible alert / banner |
| BnStatCard | Data display | KPI card: value, title, trend line |
| BnProgressBar | Data display | Labelled progress bar |
| BnTimeline | Data display | Vertical event timeline |
| BnDataTable | Data display | Sortable, typed data table |
| Bn | Tokens | JS token map (Bn.color.accent, Bn.radius.lg, …) |
| BnToken | Tokens | CSS custom-property name map |
| BnAccentUtils | Tokens | Derive and apply accent colour tokens |
TypeScript
Full type declarations ship with the package — no @types/ package required.
import type {
BnVariant, BnSize, BnIntent,
BnBreadcrumbItem, BnTab, BnTimelineItem, BnDataTableColumn,
} from 'bn-dashboard';Publishing a new version
# 1. Bump the version
npm version patch # or minor / major
# 2. Publish — prepublishOnly runs the build automatically
npm publish
# 3. Push the version commit and tag
git push && git push --tagsprepublishOnly runs npm run build before every publish, so dist/ is always fresh. Only the dist/ directory is shipped to the registry ("files": ["dist"] in package.json).
Use semver conventions:
patch— bug fixes, style tweaksminor— new components or props, backwards-compatiblemajor— breaking changes (renamed exports, removed props, token renames)
Local development
To work against a local unpublished build in a consuming project:
# 1. Build in this repo
npm run build
# 2. In the consuming project
# package.json → "bn-dashboard": "file:../bn-dashboard"
npm installAfter any change to this library, run npm run build here and npm install again in the consuming project.
Development
npm run dev # Storybook at http://localhost:6006
npm test # Vitest unit tests
npm run typecheck # TypeScript strict check (no emit)
npm run build # Build distributable to dist/