Zen
React components in dark glass: translucent surfaces, hairline borders that catch a pointer light, and one accent colour carrying the UI. 89 components, dark and light, built on native platform features (<dialog>, the Popover API, radio inputs) with no runtime dependencies.
Installation
pnpm add @rinzai/zenUsing Tailwind CSS v4? Add Zen's theme after Tailwind in your stylesheet. Your one Tailwind build then generates everything Zen's components use.
@import 'tailwindcss';
@import '@rinzai/zen/tailwind.css';Not using Tailwind? Import the complete stylesheet once, near the root of your app. It includes the default theme.
import '@rinzai/zen/css';Zen never styles your own elements. For its page setup (the background showing through), heading scale, inline code and quiet scrollbars, also add the optional base:
@import '@rinzai/zen/base.css';The look is set in Geist. Load it however you like, for example with @fontsource-variable/geist.
Usage
import { Backdrop, Button, Card } from '@rinzai/zen';
export default function App() {
return (
<>
<Backdrop />
<Card><CardHeader><CardTitle>Budget</CardTitle></CardHeader>
<Button>Save changes</Button>
</Card>
</>
);
}Background
Backdrop draws the page background and lights up card edges near the pointer. It sits at z-index: -1, so <html> needs the background colour and <body> must stay transparent. The optional base does this; without it:
html {
background: oklch(var(--background));
}
body {
background: transparent;
}Theming
Dark is the default. Add the light class (or data-theme="light") to an element for the light palette, and dark to switch back inside it. Try the switch in the header.
Colours are OKLCH L C H triplets, used as oklch(var(--primary)) or oklch(var(--primary) / 0.5). Lightness is fixed per role, so changing only the hue keeps contrast intact. The defaults sit in a cascade layer, so your own values always win:
:root {
--primary: 0.72 0.13 200; /* teal instead of violet */
--glow: 0.7 0.13 200;
--glow-strength: 1; /* 0 turns every glow off */
}Browser support
Chrome and Edge 114+, Safari 17+ and Firefox 128+: the versions with the native Popover API that popups, menus and toasts are built on, and with what Tailwind v4 needs.
- Popups are placed with CSS anchor positioning where the browser has it (Chrome 129+, Safari 26+, recent Firefox). Elsewhere Zen places them itself, the same way.
- Glass is blurred live where there’s a GPU and a mouse. On touch screens, without hardware acceleration, and with the OS’s “reduce transparency”, surfaces are solid instead.
- Motion such as entry animations is left out where a browser lacks it, and for anyone who prefers reduced motion.
Components
Accordion
Sections under headings that open one at a time, or several: questions and answers, or groups of settings.
Alert
A notice, warning or failure beside what it is about: a tinted box, or a plain line in a form or card.
Animated Number
Numbers and amounts that count smoothly to each new value.
Avatar
A round picture, or the name's initial on the glowing accent. With an in-browser crop for uploads.
Backdrop
The page background: aurora glows over contours or dots, and a light that follows the pointer and catches card edges, or drifts round them by itself on pages with no pointer.
Badge
A small label for status, counts and tags.
Breadcrumbs
Where a page sits: its parents as links, then the page itself. Works with any router.
Button
Actions, from the one glowing primary action to quiet ghost buttons.
Button Group
Buttons joined into one, rounded only at the ends: a split button, or Previous, Today and Next.
Calendar
A month grid to pick a date or a range, fully keyboard-driven, with limits, blocked days and a year view to jump far.
Calendar Heatmap
A month of days shaded by their value, like spending per day.
Canvas
A fixed-size surface where items sit anywhere, like the cards of a stream overlay: drag, resize and select several, by pointer, touch or keyboard, with snapping, a grid, undo and a fit-to-width scale.
Card
Glass panels for grouping content, and stats for single figures.
Carousel
Slides in a row that snap as you swipe or scroll, with glass buttons and dots that light the current one beneath, and the arrow keys. Native scrolling, so it follows the finger exactly.
Chart
Areas, lines and bars on one axis, a donut and an allocation bar: plain SVG that draws itself in, with a crosshair tooltip, keyboard reading, a legend and a table for screen readers.
Checkbox
A native checkbox whose tick draws itself in, with a label, a description and a mixed state.
Chip
Small pressable buttons for quick picks beside a field, like common tenures.
Code Block
Code with a copy button; bring your own highlighter for colours. The copy button runs on useCopyToClipboard, which you can use for copy buttons anywhere.
Code Input
A one-time code, a box per character, that types, pastes and autofills from a text message like any field.
Collapse
Shows as many items as fit on one line, and the rest behind "+N".
Color Picker
Pick a colour by eye or by hex: a saturation and brightness area, hue and opacity, and your own swatches. With hexToOklch to give a colour to the theme engine.
Combobox
Search and pick one or several items of any shape, composed from parts: field, panel, search, a virtualized list, empty and create rows.
Command Palette
Search everything and act on it from the keyboard: a field over a list that narrows as you type, opened with ⌘K.
Date Picker
A field that opens a calendar: one date, or a range previewed as you point. Dates are "YYYY-MM-DD" strings, so they never shift with time zones.
Dialog
Modal dialogs on the native <dialog> element, sheets that slide in from an edge, and a confirmation for destructive actions.
Disclosure
A button that shows and hides a section, like finished goals under a list.
Editable Cell
A value edited in place: shows the value, swaps in any editor on click or Enter.
Empty State
What a list or page shows when there's nothing in it yet, and the action that fills it.
Field
A label, hint and error wired to their control for screen readers, and messages for a whole form.
File Drop
Somewhere to drop files, or click to choose them, that lights up as files are dragged over it.
Filter Bar
The filters in effect, each removed with its ×, and Clear all.
Header
A sticky glass bar across the top of the page.
Hover Card
A preview of what a link points to, like a person or an account: a glass card once the pointer rests on the link, or while it has keyboard focus.
Icon Picker
An icon and a colour for something, like a spending category, from a grid in a popover.
Input
Text fields in faint glass that glow on focus.
Input Group
A field with slots: put symbols, icons, units, buttons or menus before and after the input.
Inset
A faint box set into a card: a tile for one figure, or a bordered panel for a result, tinted for good or bad news.
Kbd
Keys on the keyboard, for shortcuts in hints and tooltips.
Keypad
A number pad for typing an amount on a phone.
Load More
The end of a long list that has more: loads the next page when it scrolls into view, or on a press.
Locale Provider
The language for everything inside: how dates, numbers and money read, and every word components show or announce. Without it, "en-US" and English.
Marquee
One line of text cut off with an ellipsis, that scrolls to show the rest on hover or focus (of itself or of its row), or all the time. Only text that doesn't fit moves.
Menu
A button that opens a menu, or a context menu from a right-click or long press, with your own trigger, a header, icons, groups, destructive items, checkbox and radio items, submenus, a bottom sheet on phones, and a menubar of menus.
Meter
A measure against a limit, like spend against a budget: warm near it, red past it.
Money Input
Amounts in any currency and locale, with shorthand like 1.5L or 10k and sums like 120+45.50, exact to the paisa, and typed in other currencies, converted at your rates. Built on Input Group.
Month Picker
A field showing a month that opens a year and a 12-month grid, with optional limits and clearing.
Navigation Menu
A site’s navigation: links, and labels that open glass panels of links on hover or click, switching at once between them; works with any router.
Number Field
A number to type or step with − and +, the arrow keys and Page Up and Down: shown the locale’s way, as a percentage or a unit, and kept within bounds. Each change says whether it was a step (and by how much) or typed, and onValueCommit fires once it’s finished.
Page Header
Eyebrow, aurora title and lead paragraph for the top of a page.
Page Transition
The old page fades out as the new one rises in, when your router changes page in a view transition.
Pagination
The pages a long list is split into, as buttons or links for your router.
Pills
A glass track with a glowing pill that slides to the current page. In a nav, it is site navigation; works with any router.
Player Bar
What's playing, along the bottom of the screen, sitting on a TabBar on phones. useMediaPlayer drives your own <audio> or <video>; useMediaSession puts it on the lock screen and the media keys.
Popover
A glass panel that opens from a button, on the native Popover API: small forms, cards and settings. For hints use Tooltip; for actions, Menu.
Progress Ring
Circular progress with room for a label in the middle.
Radio Cards
Choose one of a few cards that each show their option, like a colour palette.
Radio Group
Choose one of a list, each option with a label and a description; native radios, so arrow keys work.
Range Slider
Two thumbs on one track, for a span like an amount from $50 to $500.
Repeat Picker
How often something recurs, like a bill, said in words, with the next dates it falls on.
Resizable
Panels with handles between them to drag, or to move with the arrow keys, within limits you set; groups nest, and the layout is reported to keep.
Seek Bar
Where playback is in a track, and the way to move it: played and loaded on one track, the time played and the length beside it or under its ends.
Segmented
A pill row for a few mutually exclusive options.
Select
Pick one value from a short list, fully keyboard-driven. For long or searchable lists, use Combobox.
Separator
A hairline between groups of content, across or upright.
Side Nav
Vertical navigation in titled groups, for docs and settings sidebars. Works with any router.
Skeleton & Spinner
Placeholders for content on its way.
Slider
A native range input with a glowing thumb and any track you like, at full size or small.
Sortable List
Put a list in order, or a tree of groups (a table’s rows, say), by dragging items by a grip or with the keyboard, each step announced: into other groups, open sub-items, or under another item. Also a virtualized list of hundreds.
Sparkline
A small line of how a number has moved, with no axes, for beside a figure. It draws itself in.
Spinner
A small loading spinner in the current text colour, announced to screen readers when labelled.
Status Pill
A small status that changes in place, such as Saving…, Saved or Not saved with a Retry, and fades back once the news is old.
Stepper
The steps of a flow and where you are in it; the line between them fills in as you go.
Tab Bar
Phone navigation fixed to the bottom of the screen. Works with any router.
Table
Composable tables: a glass panel that scrolls, sticky headers, first column and totals, sortable columns, rows reordered by drag and drop (into groups and under other rows), and virtual rows for long lists.
Table of Contents
An "On this page" list that highlights the section being read.
Tabs
Switch between panels in place, with an underline or a glowing pill that slides to the active tab. To go to another page, use Pills.
Tag Input
A field of short values (tags, emails): Enter or a comma adds one, Backspace takes the last back.
Textarea
Multi-line text, styled like Input.
Theme Toggle
Switches between the dark and light themes, remembering the choice itself or leaving it to your app.
Theming & styling
Your own colours from a few settings, readable in dark and light for any hue; and className overrides that always win.
Time Field
A time of day, typed or stepped a part at a time, in the locale’s order, digits and 12- or 24-hour clock.
Timeline
Events in order, each on a dot joined by a line: an activity feed or a history.
Toast
Short messages that confirm an action or report a problem, with an optional action like Undo. They stack into a deck that fans out when pointed at, and swipe away.
Toggle
An on/off switch.
Toggle Group
Buttons that stay pressed, in a row: any number of them, like filters, or at most one. One stop in the tab order; the arrow keys go through them.
Toolbar
A row of controls for one thing, like a table’s: one stop for Tab, and the arrow keys through its buttons, toggles and fields.
Tooltip
A short glass hint on hover or keyboard focus, describing its trigger to screen readers; below its trigger or beside it.
Tree Table
Rows that open into child rows, animated, built from useTree and the Table parts. With virtual rows and editable cells, enough for a budget planner.
Trend
A change, like +12% with an arrow, coloured by whether it is good news.