kineti
A React UI kit for building dashboard interfaces.
Provides Sidebar, Topbar, and DashboardShell layout primitives with light/dark theming via CSS variables. Fully typed, WCAG 2.1 AA compliant, and framework-agnostic for link rendering (works with React Router, Next.js, TanStack Router, etc.).
Install
npm install kineti
Peer dependencies: React 18+
Setup
Import the stylesheet once at your app root:
import 'kineti/style.css'
Wrap your app in ThemeProvider:
import { ThemeProvider } from 'kineti'
export default function App() {
return (
<ThemeProvider theme="light">
{/* your app */}
</ThemeProvider>
)
}
Quick start
import { DashboardShell, Sidebar, Topbar, ThemeProvider } from 'kineti'
import 'kineti/style.css'
function App() {
return (
<ThemeProvider theme="light">
<DashboardShell
sidebar={
<Sidebar>
<Sidebar.Header>
<strong>Acme</strong>
</Sidebar.Header>
<Sidebar.Section label="Main">
<Sidebar.Item href="/" label="Dashboard" active />
<Sidebar.Item href="/analytics" label="Analytics" />
<Sidebar.Item href="/settings" label="Settings" disabled />
</Sidebar.Section>
<Sidebar.Footer>
<span>User Profile</span>
</Sidebar.Footer>
</Sidebar>
}
topbar={
<Topbar>
<Topbar.Brand>Acme</Topbar.Brand>
<Topbar.Nav>
<Topbar.NavItem href="/dashboard" active>Dashboard</Topbar.NavItem>
<Topbar.NavItem href="/reports">Reports</Topbar.NavItem>
</Topbar.Nav>
<Topbar.Actions>
<button>Profile</button>
</Topbar.Actions>
</Topbar>
}
>
<main style={{ padding: '2rem' }}>
<h1>Page content</h1>
</main>
</DashboardShell>
</ThemeProvider>
)
}
Theming
Kineti uses CSS variables scoped to data-theme. ThemeProvider sets this attribute on a wrapper div and exposes useTheme for programmatic switching:
import { useTheme } from 'kineti'
function ThemeToggle() {
const { theme, setTheme } = useTheme()
return (
<button onClick={() => setTheme(theme === 'light' ? 'dark' : 'light')}>
{theme === 'light' ? 'Dark mode' : 'Light mode'}
</button>
)
}
Built-in themes: "light" and "dark". You can define custom themes by targeting [data-theme="your-theme"] and overriding the CSS variables documented in src/tokens/.
Custom link rendering
All nav items accept a renderLink prop so you can use your router's <Link> component without coupling kineti to any specific framework:
import { Link } from 'react-router-dom'
<Sidebar.Item
href="/dashboard"
label="Dashboard"
renderLink={({ href, children, ...props }) => (
<Link to={href} {...props}>{children}</Link>
)}
/>
The same prop is available on Topbar.NavItem.
Components
DashboardShell
CSS grid shell that composes sidebar, topbar, and content into a full-viewport layout.
sidebar | ReactNode | — | Sidebar slot |
topbar | ReactNode | — | Topbar slot |
children | ReactNode | required | Main content |
className | string | — | Added to root div |
style | CSSProperties | — | Inline styles on root div |
collapsed | boolean | false | Collapses to icon-only width |
onCollapse | (c: boolean) => void | — | Called when collapse state should change |
children | ReactNode | required | |
className | string | — | |
Sub-components: Sidebar.Header · Sidebar.Section · Sidebar.Item · Sidebar.Footer
label | string | Required visible label |
href | string | Renders as <a> when provided |
onClick | () => void | Renders as <button> when no href |
icon | ReactNode | Icon shown left of label |
badge | ReactNode | Badge shown right of label |
active | boolean | Sets active styles and aria-current="page" |
disabled | boolean | Disables interaction |
renderLink | (props) => ReactElement | Custom link renderer |
Topbar
Sub-components: Topbar.Brand · Topbar.Nav · Topbar.NavItem · Topbar.Actions
Renders as a <header> with a built-in skip-to-main-content link for keyboard accessibility.
Topbar.NavItem
href | string | Renders as <a> |
active | boolean | Sets active styles and aria-current="page" |
disabled | boolean | Disables interaction |
renderLink | (props) => ReactElement | Custom link renderer |
Accessibility
Sidebar renders as <nav aria-label="Main navigation">
Topbar.Nav renders as <nav aria-label="Top navigation">
Topbar includes a visually-hidden skip link targeting #main-content
DashboardShell sets id="main-content" on the <main> element
- Active items set
aria-current="page"
- Disabled anchors set
aria-disabled="true" and tabIndex={-1}
- All interactive elements have a visible focus ring (
:focus-visible)
- Color contrast meets WCAG 2.1 AA in both light and dark themes
License
MIT