Hewn

Getting started

Install from npm, then wire providers and Tailwind CSS v4.

stablefree

Hewn is a motion-native React component library built on React Aria, Tailwind CSS v4, and Motion. Install the packages from npm, copy components into your project with the CLI, or fetch component JSON from the live registry.

Install

Option A — use the npm package

Snippet
pnpm add @hewnui/ui @hewnui/themes react react-dom react-aria-components "motion@^12.42.2"

@hewnui/ui requires React ^19.2.7 and react-dom ^19.2.7 (peerDependencies in its package.json). Pinning Motion to ^12.42.2 matches the same peers — unpinned motion can resolve to a newer major.

PeerSupported range
react^19.2.7
react-dom^19.2.7
react-aria-components^1.19.0
motion^12.42.2

Or pull a component's source straight from the registry:

Snippet
curl -s https://hewnui.dev/r/button.json

Option B — copy the source into your project (you own the code)

Snippet
npx hewnui@latest init
npx hewnui@latest add button

See the CLI reference. Install the same peers (including the Motion pin and React ^19.2.7) when you go this path.

Tailwind CSS v4

Hewn targets Tailwind v4, which is configured in CSS rather than a tailwind.config.js. Import Tailwind and the theme layers in your global stylesheet. These resolve from the @hewnui/themes package installed above.

Snippet
@import "tailwindcss";

@import "@hewnui/themes/tokens.css";
@import "@hewnui/themes/radius.css";
@import "@hewnui/themes/glass.css";
@import "@hewnui/themes/glass-buttons.css";

tokens.css is required — it defines the semantic theme tokens every component reads. The rest are opt-in: radius.css powers the global radius scale, and the two glass layers are only needed if you use the tinted glass material.

Tailwind v4 only generates classes it can see, so point @source at the installed package or it will strip the component styles:

Snippet
@source "../node_modules/@hewnui/ui/dist/**/*.js";

If you copied source instead, point @source at your component root (for example components/hewn) — or omit it entirely when the files already sit inside your default content paths.

Use Tailwind CSS v4. In Next.js (and other PostCSS setups) install @tailwindcss/postcss. In Vite, use @tailwindcss/vite instead. Do not configure the legacy Tailwind v3 PostCSS plugin — it will not resolve the @import layers above.

Providers

Wrap your app once, as high as possible. Each provider owns one global concern and writes a data-* attribute on <html> that the token layers respond to.

TSX
"use client";

import {
  MaterialProvider,
  MotionProvider,
  RadiusProvider,
  ThemeProvider,
  ToastProvider,
} from "@hewnui/ui";
import type { ReactNode } from "react";

export function Providers({ children }: { children: ReactNode }) {
  return (
    <ThemeProvider defaultTheme="forest" defaultMode="light">
      <MaterialProvider defaultMaterial="solid">
        <RadiusProvider defaultRadius="soft">
          <MotionProvider defaultMotion="full">
            <ToastProvider>{children}</ToastProvider>
          </MotionProvider>
        </RadiusProvider>
      </MaterialProvider>
    </ThemeProvider>
  );
}
ProviderControlsValues
ThemeProviderActive pack and modeforest, tide, graphite, dune, clay, ember
MaterialProviderGlobal surface materialsolid, glass
RadiusProviderGlobal radius scalesharp, soft, rounded, pill
MotionProviderGlobal motion modefull, reduced, off
ToastProviderToast queue and region—

Only ThemeProvider is strictly required. Add the others when you want global control over material, radius, motion, or toasts.

Not every pack supports both modes — Dune and Clay are light-only, Ember is dark-only, and Forest, Tide, and Graphite support both. Requesting an unsupported mode falls back to the pack's first allowed mode. See Themes for the full matrix.

MotionProvider never overrides the OS. prefers-reduced-motion: reduce caps the effective mode at reduced — a full preference cannot win. See Motion for tokens and the transform-only contract.

First component

TSX
import { Button } from "@hewnui/ui";

export function Example() {
  return <Button variant="primary">Save changes</Button>;
}

Next steps

On this page