@horizech/next_ui
v0.1.1
Published
Horizech design system — Tailwind v4 tokens and React components shared across every Horizech app
Readme
@horizech/next_ui
The Horizech design system: Tailwind v4 design tokens plus the React component library shared by every Horizech app (Workspace, Accounts, Captain Password, AlgoGraphia).
Install
npm install @horizech/next_uiPeer dependencies: react and react-dom (18 or 19). Tailwind CSS v4 is
required in the consuming app.
Setup
1. Import the theme in your global stylesheet, after Tailwind:
@import "tailwindcss";
@import "@horizech/next_ui/styles/theme.css";That single import brings in the tokens, maps them onto Tailwind theme values
(bg-background, text-muted-foreground, border-border, …), and tells
Tailwind to scan this package's components.
⚠️ The scanning part matters more than it looks. Tailwind v4 excludes
node_modulesfrom automatic class detection, so without it every component renders with class names that have no CSS behind them — they look broken and nothing errors.theme.csscarries its own@sourceso you don't have to think about it.
2. Transpile the package in next.config.ts:
const nextConfig = {
transpilePackages: ["@horizech/next_ui"],
};This package ships raw TypeScript/TSX, not a compiled bundle. That is
deliberate — it keeps every "use client" boundary exactly as written, which a
bundler-produced ESM build tends to strip and quietly break under React Server
Components. The trade-off is that consumers must be able to compile TS from
node_modules; Next.js does this with the one line above.
3. Dark mode is the .dark class on a root element — pair it with
next-themes (attribute="class") or set it yourself.
Usage
import { Button, Card, StatusPill, cn } from "@horizech/next_ui";
export function Example() {
return (
<Card className={cn("p-4")}>
<StatusPill status="active" />
<Button variant="default">Save</Button>
</Card>
);
}Individual components can also be imported directly:
import { Button } from "@horizech/next_ui/components/button";Making it your app's brand
Every app shares one token skeleton and overrides only the accent, in its own
globals.css after the theme import:
:root { --primary: #2563eb; --ring: #2563eb; }
.dark { --primary: #3b82f6; --ring: #3b82f6; }The default is indigo (#4f46e5 light / #6366f1 dark). Status colours
(success, warning, destructive, info) are separate tokens and deliberately do
not move with the accent — they mean the same thing in every app.
What's in it
Layout and shell: AppShell, Sidebar, Topbar, PageLayout, ThemeProvider,
SplashScreen.
Controls: Button, Input, SearchInput, Textarea, Select, Checkbox,
RadioGroup, Switch, TagInput, FormField, Label.
Surfaces and overlays: Card, Dialog, Sheet, Popover, DropdownMenu,
Tooltip, Toast.
Display: Badge, StatusPill, Chip, Avatar, Table/DataTable, Tabs,
Breadcrumb, Progress, Rating, Skeleton, Loading, Separator,
SvgIcon.
Plus the cn() class-merging helper.
StatusPill is the domain-specific one: it maps licence and instance statuses
(active, trial, past_due, running, provisioning, failed, …) to a
coloured dot and label, and pulses the in-progress states.
Versioning
Pre-1.0, so treat minor bumps as potentially breaking. The tokens are the stable part of the contract; component props are still settling.
Licence
UNLICENSED — © Horizech LTD. Published to npm for use by Horizech's own applications.
