MACAW is installed through one door. The CLI adds the packages, the stylesheet imports and the Claude Code plugin, so the next session already knows the system.
Install
npx @macaw-ds/cli initinit installs @macaw-ds/ui, @macaw-ds/tokens and @macaw-ds/icons, drops the plugin (skills, hooks, reviewer agent, MCP config) into .claude/, and writes a short CLAUDE.md block.
Stylesheets
init adds these imports to your root CSS for you, right after your Tailwind import, between /* macaw:start */ and /* macaw:end */. It looks in the usual places (src/app/globals.css, app/globals.css, src/index.css, app/app.css and a few more); if it finds none or several, or you pass --no-css, add them yourself in this order. Tailwind v4 reads the theme from theme.css, so only token utilities exist afterwards. MACAW needs Tailwind CSS v4, and init stops on a v3 project.
If your root CSS still has a starter template's :root colours, @theme fonts or body styles (create-next-app ships them), delete them; they override the tokens.
@import 'tailwindcss';
@import '@macaw-ds/tokens/tokens.css';
@import '@macaw-ds/tokens/theme.css';
@import '@macaw-ds/ui/styles.css';Theme, density and motion
Light and dark, comfortable and compact, and reduced motion are all modes of the token layer, set with data attributes on <html> or on any region. With no data-theme the OS preference applies; with no data-motion the OS reduced-motion setting applies. Component code never branches on any of them.
<html lang="en" data-theme="dark" data-density="compact">| Attribute | Values | Changes |
|---|---|---|
data-theme | light, dark | Every semantic colour |
data-density | comfortable, compact | Control heights, TopBar height, gutters, margins, padding |
data-motion | reduced, full | Durations collapse to 0 ms and the spinner stops |
Frame a page
Products start from the system frame: AppShell with a TopBar and a SideNav, and a PageHeader at the top of every page. See Layout templates.
Fonts
The token font stacks start with Inter and Geist Mono and fall back to system fonts. Load them any way you like; with Next.js:
import { Geist_Mono, Inter } from 'next/font/google';
const inter = Inter({ subsets: ['latin'], variable: '--font-inter' });
const geistMono = Geist_Mono({ subsets: ['latin'], variable: '--font-geist-mono' });
<html className={`${inter.variable} ${geistMono.variable}`}>Use a component
import { Button, Text } from '@macaw-ds/ui';
export function Summary() {
return (
<>
<Text numeric>$12,480.00</Text>
<Button>Pay invoice</Button>
</>
);
}CLI commands
npx @macaw-ds/cli add button # wires the import, prints a starter snippet
npx @macaw-ds/cli add button --eject # copies the source in; recorded in .macaw/ejected.json
npx @macaw-ds/cli diff # (0.2) shows what ejected copies are behindThe plugin for Claude Code
init installs it. To add it to an existing Claude Code setup by hand:
claude plugin marketplace add Cristian-pineda/MACAW-Design-System
claude plugin install macawSee For agents for what the plugin contains.
Tailwind-native option
If you compile your own utilities instead of importing @macaw-ds/ui/styles.css, point Tailwind at the component sources and keep the theme import:
@import 'tailwindcss';
@import '@macaw-ds/tokens/tokens.css';
@import '@macaw-ds/tokens/theme.css';
@source '../node_modules/@macaw-ds/ui/src';The ESLint config @macaw-ds/eslint-config then rejects anything that is not a token utility: raw hex or px, arbitrary values, Tailwind's default palette, and className on a MACAW component.