@hex-core/components
59 Radix + CVA components incl. layout primitives + ColorPicker, Tailwind v4 entry.
Install
1.4.0Runtime dependencypnpm add @hex-core/componentsWhat it does
`@hex-core/components` is the runtime React component library. It ships 59 Radix + CVA components, including six layout primitives and an HSL ColorPicker.
The package owns the visual contract. `@hex-core/tokens` decides what colors mean; `@hex-core/components` decides how a Button looks when it's `variant="outline" size="sm"`. Consumers wire the two together via Tailwind v4's `@theme` block in their globals.css.
In Tailwind v4, utility classes inside published bundles are not auto-scanned. A `tailwind.css` entry (since 1.2.1) ships that adds the right `@source` directive — one `@import "@hex-core/components/tailwind.css"` and you're done.
Public API
Button
import { Button, type ButtonProps } from "@hex-core/components";
interface ButtonProps {
variant?: "default" | "outline" | "secondary" | "ghost" | "link" | "destructive";
size?: "default" | "sm" | "lg" | "icon";
asChild?: boolean;
}Polymorphic button with six variants and four sizes. `asChild` swaps the rendered element for the child component while preserving the variant classes — useful for wrapping `<Link>` or anchor tags without losing the visual contract.
import { Button } from "@hex-core/components";
export function ConfirmRow() {
return (
<div className="flex gap-2">
<Button variant="outline">Cancel</Button>
<Button>Confirm</Button>
</div>
);
}Stack / Cluster / Grid / Container / Spacer / AspectRatio
import {
Stack, Cluster, Grid, Container, Spacer, AspectRatio,
} from "@hex-core/components";
interface StackProps {
gap?: "0" | "1" | "2" | "3" | "4" | "6" | "8";
align?: "start" | "center" | "end" | "stretch";
justify?: "start" | "center" | "end" | "between";
asChild?: boolean;
}Layout primitives shipped in 1.2.1. Stack = vertical flex; Cluster = horizontal flex with wrap; Grid = 1/2/3/4/6 columns or `auto-fit` with `minColWidth`; Container = max-width + padding; Spacer = declarative whitespace; AspectRatio = Radix re-export. They all share the same `gap` scale (drawn from `--space-*` tokens), so mixing them never produces uneven seams.
<Stack gap="4">
<h2>Account</h2>
<Cluster gap="2" wrap>
<Button variant="outline">Edit</Button>
<Button variant="outline">Reset</Button>
</Cluster>
</Stack>ColorPicker
import { ColorPicker, type ColorPickerProps } from "@hex-core/components";
interface ColorPickerProps {
mode: "hsl";
value: string; // "240 5.9% 10%" — same triplet @hex-core/tokens emits
onChange: (next: string) => void;
}HSL color picker. Round-trips losslessly through the same `<H> <S>% <L>%` triplet `@hex-core/tokens` exports, so binding it to a token override doesn't introduce float drift.
import { ColorPicker } from "@hex-core/components";
import { useState } from "react";
export function PrimaryEditor() {
const [hsl, setHsl] = useState("240 5.9% 10%");
return <ColorPicker mode="hsl" value={hsl} onChange={setHsl} />;
}Color utilities
import {
parseHslTriplet, formatHslTriplet,
hslToRgb, rgbToHsl,
hslTripletToHex, hexToHslTriplet,
type HslTriplet, type RgbColor,
} from "@hex-core/components";Pure conversions between the four canonical color formats the design system speaks: HSL triplets, HSL objects, RGB objects, and hex. Use these instead of hand-rolled regex — they handle the percent-vs-decimal lightness format that bites every consumer.
import { hexToHslTriplet, hslTripletToHex } from "@hex-core/components";
const triplet = hexToHslTriplet("#FF5733"); // "11 100% 60%"
const hex = hslTripletToHex("240 5.9% 10%"); // "#18181B"tailwind.css entry
/* @hex-core/components/tailwind.css — exported entry, not a TS API */
@source "./dist/*.js";Single-line replacement for the manual `@source "../../node_modules/@hex-core/components/dist/*.js"` Tailwind v4 directive. Required for utility classes inside the published bundle to compile in your app. Add the import to your globals.css after `@import "tailwindcss";`.
@import "tailwindcss";
@import "@hex-core/components/tailwind.css";
@theme {
--color-background: hsl(0 0% 100%);
--color-foreground: hsl(240 10% 3.9%);
/* ... */
}Workflows
Add the package to a fresh Next.js + Tailwind v4 app
Three commands and one CSS import. Works the same on Vite, Remix, or any Tailwind v4 host.
pnpm add @hex-core/components @hex-core/tokens
# ensure tailwindcss + @tailwindcss/postcss are already installedCompose a settings card with layout primitives
Showcases Stack + Cluster + Grid sharing the same gap scale. No hand-rolled flex utilities.
import {
Stack, Cluster, Grid, Card, CardHeader, CardContent,
Button, Input, Label, Switch,
} from "@hex-core/components";
export function NotificationSettings() {
return (
<Card>
<CardHeader><h2>Notifications</h2></CardHeader>
<CardContent>
<Stack gap="4">
<Grid cols={2} gap="3">
<Stack gap="1">
<Label>Email</Label>
<Input type="email" />
</Stack>
<Stack gap="1">
<Label>Push</Label>
<Switch />
</Stack>
</Grid>
<Cluster gap="2" justify="end">
<Button variant="outline">Cancel</Button>
<Button>Save</Button>
</Cluster>
</Stack>
</CardContent>
</Card>
);
}Compatibility
- Peer deps: React 18 or 19, Tailwind CSS v4.
- Optional peers: `@tanstack/react-table` 8 or 9 (only for the DataTable component); `react-hook-form` 7 (only for the Form helpers).
- Bundles `@hex-core/registry@^0.2.1` as a transitive dep — no `workspace:^` republish bug.
- All components ship as ESM only.