# AGENTS.md
Instructions for AI agents working with the HeroUI v3 repository.
## Repository Overview
HeroUI v3 is a modern React UI library built with **Tailwind CSS v4**, organized as a **pnpm monorepo** managed by **Turborepo**. Components are built on top of [React Aria Components](https://react-spectrum.adobe.com/react-aria/) and follow a compound component pattern similar to Radix UI.
### Tech Stack
| Technology | Version | Purpose |
|---|---|---|
| Node.js | 22+ | Runtime |
| pnpm | 10.26.2 | Package manager (via corepack) |
| React | 19+ | UI framework |
| Tailwind CSS | 4.x | Styling |
| TypeScript | 5.x | Type safety |
| Turborepo | 2.x | Build orchestration |
| Storybook | Latest | Component development |
| Vitest | 4.x | Testing |
| React Aria Components | Latest | Accessibility primitives |
| tailwind-variants | Latest | Variant-based styling (includes twMerge) |
### Monorepo Structure
```
/
βββ apps/
β βββ docs/ # Documentation site (Next.js + Fumadocs)
βββ packages/
β βββ react/ # Main UI library (@heroui/react)
β β βββ src/components/ # All components
β β βββ src/utils/ # Shared utilities
β β βββ scripts/ # Build & codegen scripts
β βββ styles/ # CSS styles & variants (@heroui/styles)
β β βββ src/components/ # Per-component .css files
β βββ standard/ # Shared ESLint, Prettier, TS configs
β βββ storybook/ # Storybook configuration
β βββ testing/ # Shared test harness (@heroui/testing)
βββ turbo.json
βββ pnpm-workspace.yaml
```
## Commands
| Action | Command |
|---|---|
| Install dependencies | `pnpm i --hoist` |
| Build all packages | `pnpm build` |
| Build specific package | `pnpm build --filter=@heroui/react` |
| Dev (Storybook, port 6006) | `pnpm dev` |
| Dev (Docs site, port 3000) | `pnpm dev:docs` |
| Lint | `pnpm lint` |
| Typecheck | `pnpm typecheck` |
| Test all (jsdom + browser) | `pnpm test` |
| Test one file (filter) | `pnpm --filter @heroui/react exec vitest run button` |
| Test with coverage | `pnpm test:coverage` (jsdom floors only β not βdoneβ) |
| Test changed files (local) | `pnpm --filter @heroui/react test:changed` (jsdom only; not a gate) |
| Format | `pnpm run format` |
| Bump version | `pnpm version:bump` |
| Scaffold a new component | `cd packages/react && pnpm add:component ComponentName` |
## Behavioral tests (`@heroui/react`)
- Suites live in `packages/react/tests/components/<name>/`:
- `*.test.tsx` β jsdom (~90% of contracts)
- `*.ssr.test.tsx` β Client SSR smoke via `ssrSmoke()` (not RSC)
- `*.browser.test.tsx` β Playwright (overlays + high-risk portals; not every component)
- optional `fixtures.tsx` β shared JSX across layers
- Import harness from `@heroui/testing/helpers` (`render`, `setupUser`, `runAllTimers`, `ssrSmoke`, `User`). Browser suites: `render` from `@heroui/testing/browser` (wraps `vitest-browser-react`; owned by `@heroui/testing`). Prefer `@/` for sources. Pattern testers: `const user = new User(...); user.createTester(...)` β not a top-level export.
- Query: `getByRole` / label / text first; `data-testid` when needed; avoid class-primary queries.
- Assert: roles/names, HeroUI `data-*` hooks, callbacks, focus, light BEM + documented `data-slot` on compound parts β not colors, full class lists, or RAC internals.
- Fake timers: per-suite only; wire `advanceTimers` into `setupUser` + `User`; use `runAllTimers()`.
- Pattern testers for groups / overlays / collections; skip for Button / Checkbox / Switch / TextField.
- Naming: `describe("Component")`; nested concern; `it` as `supportsβ¦` / `callsβ¦` / `exposesβ¦` / `rendersβ¦`. SSR: `"Component SSR"`; browser: `"Component (browser)"`.
- Intentional skips (no dedicated suite required): internals (`rac`, `icons`), non-exported helpers (`color-input-group`, `date-input-group`), in-progress `calendar-year-picker`, parent-covered parts (`list-box-item`, `menu-item`, `menu-section`, `list-box-section`), Toast SSR (client portal only β covered by jsdom + browser). Public `input-group` has its own suite. SSR and browser are risk-based, not universal.
- Browser setup (once locally): `pnpm --filter @heroui/testing exec playwright install chromium` before `pnpm test`. CI uses `playwright install --with-deps chromium`, then `test:browser` + `test:coverage` (not a single `pnpm test`).
- Commands: `pnpm test` (jsdom + browser, needs Chromium); filter with `pnpm --filter @heroui/react exec vitest run <name>`.
- Coverage (`pnpm test:coverage`): jsdom only; `src/components/**` minus barrels. Thresholds are **CI floors** (statements/lines can pass with thin smoke). Green coverage β sufficient depth β still require role/callback/focus (and browser for high-risk portals).
- `test:changed`: local jsdom-only shortcut (`vitest related --changed`). Does **not** run browser suites; never use it as the merge gate β use `pnpm test` / CI.
## Git Commit Convention
All commits must follow [Conventional Commits](https://www.conventionalcommits.org/) and are validated by Husky + commitlint. Pre-commit also runs `lint-staged`.
```
<type>(<scope>): <message>
```
**Allowed types:** `feat`, `feature`, `fix`, `refactor`, `docs`, `build`, `test`, `ci`, `chore`
Examples:
```
feat(components): add select component
fix(button): resolve disabled state not applying
docs: update installation guide
```
## Component Architecture
### File Structure
Each component lives in `packages/react/src/components/<component-name>/`:
```
component-name/
βββ component-name.tsx # Component implementation (uses React Aria)
βββ component-name.styles.ts # Tailwind Variants styling
βββ component-name.stories.tsx # Storybook stories
βββ index.ts # Barrel exports
```
CSS styles live in `packages/styles/src/components/<component-name>/`.
### Creating a New Component
Always use the scaffold script:
```bash
cd packages/react
pnpm add:component ComponentName
```
Then build to update package.json exports:
```bash
pnpm build
```
### Compound Component Pattern
HeroUI uses a compound component pattern. Each component exports its sub-parts so users can compose and style them independently.
```tsx
// Context shares state/styles across parts
const ComponentContext = createContext<{slots?: ReturnType<typeof componentVariants>}>({});
// Root wraps children with context
const ComponentRoot = forwardRef(({children, className, ...props}, ref) => {
const slots = useMemo(() => componentVariants({...}), [...]);
return (
<ComponentContext value={{slots}}>
<ReactAriaPrimitive ref={ref} className={composeTwRenderProps(className, slots.base())}>
{children}
</ReactAriaPrimitive>
</ComponentContext>
);
});
// Child parts consume context
const ComponentItem = forwardRef(({className, ...props}, ref) => {
const {slots} = useContext(ComponentContext);
return (
<ReactAriaPrimitive ref={ref} className={composeTwRenderProps(className, slots?.item())}>
{props.children}
</ReactAriaPrimitive>
);
});
```
Compound components are exported via `Object.assign` as the default export:
```tsx
const CompoundComponent = Object.assign(ComponentRoot, {
Item: ComponentItem,
Trigger: ComponentTrigger,
});
export default CompoundComponent;
```
### Export Strategy
```tsx
// Named exports for compound components
export * as ComponentName from "./component-name";
// Direct exports for simple components
export {Component, type ComponentProps} from "./component";
// Always export variants
export {componentVariants, type ComponentVariants} from "./component.styles";
```
### Styling Rules
1. **Styles go in `.styles.ts` files**, never in `.tsx` files. Use `tv()` from `tailwind-variants`.
2. **Import from `tailwind-variants`**, never from `@heroui/standard`.
3. **Never use `twMerge` manually** β `tailwind-variants` already includes it.
4. **Add `"use client"` directive** at the top of every component `.tsx` file.
5. **Display names** follow: `HeroUI.ComponentName` or `HeroUI.Component.SubPart`.
### CSS / BEM Naming
Components use BEM-style CSS class names:
- **Block**: `button`, `card`, `alert`
- **Element**: `card__header`, `alert__icon`
- **Modifier**: `button--primary`, `button--lg`, `button--icon-only`
### Default Size Pattern (Critical)
All components must include default sizes in base classes so they work without explicit size props:
```css
.avatar {
@apply relative flex size-10 shrink-0 overflow-hidden rounded-full;
/* size-10 is the default (equivalent to --md) */
}
.avatar--sm { @apply size-8; }
.avatar--md { /* empty β this IS the default */ }
.avatar--lg { @apply size-12; }
```
### Interactive State Pattern
All interactive components must support both pseudo-classes and data attributes:
```css
.component {
&:hover,
&[data-hovered="true"] { @apply ...; }
&:active,
&[data-pressed="true"] { @apply ...; }
&:focus-visible,
&[data-focus-visible="true"] {
outline: 2px solid var(--focus);
outline-offset: 2px;
}
}
```
### React Aria className Patterns
React Aria components differ in how they accept `className`:
- **Render-prop components** (Button, Checkbox, Switch, Popover, Tooltip, Tabs, Link, Menu, etc.) β use `composeTwRenderProps(className, slots.foo())`.
- **String-only components** (Label, Text, Input, TextArea, Heading, Dialog) β pass `className` directly: `slots?.label({className})`.
### Composition Over Duplication
Do **not** create component-specific Label/Description/FieldError sub-components. Instead, compose with the existing shared primitives:
```tsx
import {Label} from "@/components/label";
import {Description} from "@/components/description";
<div className="flex items-center gap-3">
<Checkbox id="terms"><Checkbox.Indicator /></Checkbox>
<Label htmlFor="terms">Accept terms</Label>
</div>
```
### Tailwind Class Detection
Tailwind CSS scans files as plain text. **Never construct class names dynamically**:
```tsx
// BAD β Tailwind won't detect this
<div className={`text-${color}-600`} />
<span className={`button--${size}`} />
// GOOD β use complete class name mappings
const colorClasses = {
blue: "text-blue-600",
red: "text-red-600",
};
```
### Storybook
All stories must use the `"Components"` group in their title:
```tsx
export default { title: "Components/Button" };
```
Storybook is the primary dev workflow β run with `pnpm dev` (port 6006).
### Icon Library
HeroUI uses **Iconify** with **gravity-ui** as the default icon set.
## Current Components
### Completed
accordion, alert, alert-dialog, autocomplete, avatar, badge, breadcrumbs, button, button-group, calendar, card, checkbox, checkbox-group, chip, close-button, color-area, color-field, color-picker, color-slider, color-swatch, color-swatch-picker, combo-box, date-field, date-picker, date-range-picker, description, disclosure, disclosure-group, drawer, dropdown, empty-state, error-message, field-error, fieldset, form, header, input, input-group, input-otp, kbd, label, link, list-box, list-box-item, list-box-section, menu, menu-item, menu-section, meter, modal, number-field, pagination, popover, progress-bar, progress-circle, radio, radio-group, range-calendar, scroll-shadow, search-field, select, separator, skeleton, slider, spinner, surface, switch, switch-group, table, tabs, tag, tag-group, textarea, textfield, time-field, toast, toggle-button, toggle-button-group, toolbar, tooltip, typography
### In Progress
calendar-year-picker
## Non-obvious Gotchas
1. **`pnpm i` triggers builds** β The `postinstall` hook builds `@heroui/styles` and runs `typegen:docs` and `typegen:docs-cn`. If it fails, run `pnpm --filter @heroui/styles build` manually.
2. **Build order matters** β `@heroui/styles` must build before `@heroui/react`. Running `pnpm build` from root handles this via Turbo's `^build` dependency.
3. **Native addons allowlist** β `onlyBuiltDependencies` in root `pnpm-workspace.yaml` allows native compilation for `esbuild`, `@swc/core`, `@parcel/watcher`, etc. If this list is missing, you'll see "Ignored build scripts" warnings.
4. **Behavioral tests** β see [Behavioral tests](#behavioral-tests-herouireact) above. Harness lives in `@heroui/testing`; suites in `packages/react/tests/`.
5. **Commit hooks** β Husky runs `lint-staged` on pre-commit and `commitlint` on commit-msg. Non-conforming commits are rejected.
6. **Run checks before committing** β `pnpm lint && pnpm typecheck && pnpm test`
## Cursor Cloud Specific
- **Node.js v22+** is installed via binary tarball to `/usr/local/`.
- **pnpm** is activated via `corepack` β the `packageManager` field in root `package.json` declares `[email protected]`.
- Full command reference and component architecture details are also in `CLAUDE.md`.
# CLAUDE.md
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
## Repository Overview
HeroUI v3 is a modern React UI library built with Tailwind CSS v4, using a pnpm monorepo structure managed by Turborepo.
### Key Technical Stack
- **Node.js**: v22+ required
- **pnpm**: v10.26.2 (package manager)
- **React**: v19+
- **Tailwind CSS**: v4.1.18
- **TypeScript**: v5.9.3
- **Turborepo**: Build orchestration
- **Storybook**: Component development
- **Vitest**: Testing framework
## Development Commands
### Core Development Commands
```bash
# Install dependencies (use --hoist flag)
pnpm i --hoist
# Start Storybook for component development
pnpm dev
# Start documentation site
pnpm dev:docs
# Build all packages
pnpm build
# Build specific package
pnpm build --filter=@heroui/react
# Run linting
pnpm lint
# Run tests (turbo β packages with a test script; jsdom + browser)
pnpm test
# Filter by file name (e.g. button.test.tsx)
pnpm --filter @heroui/react exec vitest run button
# Coverage (jsdom floors only β not a depth bar)
pnpm test:coverage
# Changed-set (local jsdom only; not a merge gate)
pnpm --filter @heroui/react test:changed
# Run formatting
pnpm run format
# Run type checking
pnpm typecheck
```
### Behavioral tests (`@heroui/react`)
- Suites: `packages/react/tests/components/<name>/` β `*.test.tsx` (jsdom), `*.ssr.test.tsx` (Client SSR via `ssrSmoke()`, not RSC), `*.browser.test.tsx` (Playwright for high-risk portals/overlays; not universal), optional `fixtures.tsx`
- Harness: `@heroui/testing/helpers` (`render`, `setupUser`, `runAllTimers`, `ssrSmoke`, `User`); browser `render` from `@heroui/testing/browser`. Sources via `@/`. Pattern testers: `user.createTester(...)` β do not import `createTester` directly
- Query/assert: role/label/text first; HeroUI `data-*` + light BEM + documented `data-slot` on compound parts; no colors, full class lists, or RAC internals
- Timers: fake timers per-suite only; wire `advanceTimers` into `setupUser` + `User`
- Naming: `describe("Component")`; nested concern; `it` as `supportsβ¦` / `callsβ¦` / `exposesβ¦` / `rendersβ¦`. SSR: `"Component SSR"`; browser: `"Component (browser)"`
- Intentional skips: internals (`rac`, `icons`), non-exported helpers (`color-input-group`, `date-input-group`), in-progress `calendar-year-picker`, parent-covered parts (`list-box-item`, `menu-item`, β¦), Toast SSR (client portal β jsdom + browser). Public `input-group` has its own suite. SSR/browser are risk-based
- Browser setup (once locally): `playwright install chromium` before `pnpm test`. CI: `--with-deps`, then `test:browser` + `test:coverage`
- Commands: `pnpm test` (jsdom + browser, needs Chromium); filter with `pnpm --filter @heroui/react exec vitest run <name>`
- Coverage: jsdom-only floors β green β depth. `test:changed`: local jsdom shortcut only, not a merge gate
### Package-Specific Commands
- Use `--filter` flag with package name: `pnpm build --filter=@heroui/react`
- Main packages: `@heroui/react`, `@heroui/styles`, `@heroui/docs`, `@heroui/storybook`
## Git Commit Convention
**IMPORTANT**: This repository uses conventional commits with strict validation. All commits must follow this format:
```
<type>(<scope>): <message>
```
### Allowed Types:
- `feat` / `feature`: New features
- `fix`: Bug fixes
- `refactor`: Code refactoring
- `docs`: Documentation changes
- `build`: Build system changes
- `test`: Test changes
- `ci`: CI configuration changes
- `chore`: Other changes
### Examples:
```bash
git commit -m "feat(components): add new prop to avatar component"
git commit -m "fix(button): resolve click handler issue"
git commit -m "docs: update installation guide"
git commit -m "ci: add Claude Code GitHub Action workflow"
```
**Note**: Commits without proper format will be rejected by git hooks.
## Repository Architecture
### Monorepo Structure
```
/
βββ apps/
β βββ docs/ # Documentation site (Next.js + Fumadocs)
βββ packages/
β βββ react/ # Main UI component library (@heroui/react)
β βββ styles/ # CSS styles & variants (@heroui/styles)
β βββ standard/ # Shared ESLint, Prettier, TypeScript configs
β βββ storybook/ # Storybook configuration
β βββ testing/ # Shared test harness (@heroui/testing)
βββ turbo.json # Turborepo configuration
βββ pnpm-workspace.yaml # Workspace definition
```
### Component Architecture Pattern
Each component in `packages/react/src/components/` follows this structure:
```
component-name/
βββ component-name.tsx # Main component (uses React Aria)
βββ component-name.styles.ts # Tailwind Variants styling
βββ component-name.stories.tsx # Storybook stories (title: "Components/ComponentName")
βββ index.ts # Barrel exports
```
**IMPORTANT**: All Storybook stories must use the "Components" group in their title. For example: `title: "Components/Card"`, `title: "Components/Button"`, etc.
### CSS Class Naming Convention
**IMPORTANT**: HeroUI v3 uses BEM (Block Element Modifier) style for CSS classes to ensure predictable and maintainable styling:
- **Block**: The main component class (e.g., `button`, `card`, `alert`)
- **Modifier**: Variations of the component using double dashes (e.g., `button--primary`, `button--lg`, `button--icon-only`)
- **Element**: Child elements within a component (e.g., `card__header`, `alert__icon`)
**Migration to CSS-based Styling**:
- The `button` component has been migrated to use CSS styles from `@heroui/styles/src/components/button.css`
- This approach allows for better customization through CSS utilities and `@utility` directives
- Other components will gradually be migrated to follow this CSS-based pattern
- Components use `tv()` from `tailwind-variants` to map variant props to BEM class names
**Default Size Pattern**:
**CRITICAL**: All components MUST include default sizes in their base classes to prevent broken appearances when no size modifier is specified. Following the following pattern:
- **Base classes** include default dimensions (equivalent to the `--md` variant)
- **Medium variants** (`--md`) are empty with explanatory comments
- **Size modifiers** override the defaults when specified
Example implementation:
```css
/* Base component with default size */
.avatar {
@apply relative flex size-10 shrink-0 overflow-hidden rounded-full;
/* size-10 is the default, equivalent to --md */
}
/* Size variants */
.avatar--sm {
@apply size-8; /* Override default */
}
.avatar--md {
/* No styles as this is the default size */
}
.avatar--lg {
@apply size-12; /* Override default */
}
```
This ensures components work properly without explicit size classes:
- `<div className="avatar">` β Works perfectly (size-10)
- `<div className="avatar avatar--lg">` β Override to large (size-12)
### Core Component Design Principles
**IMPORTANT**: HeroUI v3 follows a compound component pattern similar to Radix UI, built on top of React Aria Components primitives. This enables maximum flexibility and customization for users.
### React Aria Components Integration
**CRITICAL**: Before implementing any component, you MUST:
1. Visit React Aria Components docs: https://react-spectrum.adobe.com/react-aria/
2. Study the specific component's API and examples
3. Understand its accessibility features and ARIA patterns
4. Plan the transformation from React Aria's prop-based API to Radix UI's composition-based API
React Aria provides the accessibility foundation, but we transform their API to match Radix UI's compound component pattern for better customization.
#### 1. **Compound Component Pattern**:
- Export all internal component pieces (Root, Item, Trigger, Content, etc.)
- Each piece can be styled and composed independently
- Users can customize render logic without accessing internal code
- Examples: Accordion (Root, Item, Heading, Trigger, Panel, Indicator, Body), Alert (Root, Icon, Title, Description, Action, Close)
#### 2. **Export Strategy**:
```typescript
// Named exports for compound components
export * as ComponentName from "./component-name";
// Direct exports for simple components
export {Component, type ComponentProps} from "./component";
// Always export variants
export {componentVariants, type ComponentVariants} from "./component.styles";
```
#### 3. **Component Structure for Compound Components**:
```typescript
// Context for sharing state/styles
const ComponentContext = createContext<{slots?: ReturnType<typeof componentVariants>}>({});
// Root component wraps with context
const ComponentRoot = React.forwardRef<...>(({children, className, ...props}, ref) => {
const slots = React.useMemo(() => componentVariants({...}), [...]);
return (
<ComponentContext value={{slots}}>
<ReactAriaComponent ref={ref} className={composeTwRenderProps(className, slots.base())}>
{children}
</ReactAriaComponent>
</ComponentContext>
);
});
// Child components consume context
const ComponentItem = React.forwardRef<...>(({className, ...props}, ref) => {
const {slots} = useContext(ComponentContext);
return (
<ReactAriaComponent ref={ref} className={composeTwRenderProps(className, slots?.item())}>
{props.children}
</ReactAriaComponent>
);
});
// Export pattern
export {ComponentRoot as Root, ComponentItem as Item, ...};
```
#### 4. **Key Implementation Details**:
1. **Styling with Tailwind Variants**:
- Styles defined in `.styles.ts` files using `tv()` function from `tailwind-variants`
- **IMPORTANT**: Always import from `tailwind-variants`, never from `@heroui/standard` (which doesn't exist)
- **CRITICAL**: tailwind-variants already includes `twMerge` functionality, so NEVER manually use `twMerge`
- **RULE**: All component styles MUST be defined in separate `.styles.ts` files, NOT in the component implementation files
- Component implementation files (`.tsx`) should only contain logic and React Aria primitives
- Example imports:
```typescript
import type {VariantProps} from "tailwind-variants";
import {tv} from "tailwind-variants";
```
- Support for variants (primary, secondary, etc.)
- Compound variants for conditional styling
- Slot system for complex components
2. **Component Features**:
- Built on React Aria Components for accessibility
- Use `forwardRef` for all components
- Display names follow: `HeroUI.ComponentName` or `HeroUI.Component.SubPart`
- Support render props from React Aria when available
3. **Type Exports**:
```typescript
// Export props for each component part
export type ComponentRootProps = {...}
export type ComponentItemProps = {...}
export type ComponentVariants = VariantProps<typeof componentVariants>
```
4. **Utilities** (`packages/react/src/utils/`):
- `composeTwRenderProps`: Merge Tailwind classes with render props
- `focusRingClasses`: Consistent focus styling
- `disabledClasses`: Disabled state styling
- `mapPropsVariants`: Separate variant props from component props
5. **React Aria Components className Patterns**:
**CRITICAL**: React Aria components have different className prop behaviors:
**Components that support render props** (use `composeTwRenderProps`):
- Button, TextField, FieldError, Checkbox, CheckboxGroup
- Switch, RadioGroup, Radio, Slider (and Track, Thumb, Output)
- Popover, Tooltip, Tabs (and Tab, TabList, TabPanel)
- Link, Menu, MenuItem, Accordion (DisclosureGroup)
**Components that ONLY accept string className** (pass className directly):
- Label, Text, Input, TextArea
- Heading, Dialog, OverlayArrow
**Usage examples**:
```typescript
// For render prop components - use composeTwRenderProps
<ButtonPrimitive
className={composeTwRenderProps(className, slots?.button())}
/>
// For string-only components - pass className directly
<LabelPrimitive
className={slots?.label({className})}
/>
// OR
<LabelPrimitive
className={labelVariants({size, variant, className})}
/>
```
**How to check**: If unsure, check the React Aria docs or try both approaches - TypeScript will error if a component doesn't support render props
6. **Composition Pattern with Existing Components**:
**CRITICAL**: HeroUI follows a composition-based approach. Components should reuse existing primitives rather than creating component-specific versions.
**Key Principles**:
- **DO NOT** create component-specific Label, Description, or FieldError components
- **DO** reuse the existing `Label`, `Description`, and `FieldError` components
- **DO** use standard HTML composition patterns with `htmlFor`/`id` attributes
**Example Pattern**:
```typescript
// β WRONG - Component-specific label
export const Checkbox = {
Root: CheckboxRoot,
Label: CheckboxLabel, // Don't create this!
};
// β
CORRECT - Compose with existing components
import { Label } from "@/components/label";
import { Description } from "@/components/description";
// Usage:
<div className="flex items-center gap-3">
<Checkbox id="terms">
<Checkbox.Indicator />
</Checkbox>
<Label htmlFor="terms">Accept terms</Label>
</div>
// With description:
<div className="flex gap-3">
<Checkbox className="mt-0.5" id="notifications">
<Checkbox.Indicator />
</Checkbox>
<div className="flex flex-col gap-1">
<Label htmlFor="notifications">Email notifications</Label>
<Description>Get notified when someone mentions you</Description>
</div>
</div>
```
**Components that follow this pattern**:
- Checkbox - uses external Label/Description
- Radio - uses external Label/Description
- Switch - uses external Label/Description
- TextField - provides slots for Label/Description/FieldError
### Current Components
**Completed**: accordion, alert, alert-dialog, autocomplete, avatar, badge, breadcrumbs, button, button-group, calendar, card, checkbox, checkbox-group, chip, close-button, color-area, color-field, color-picker, color-slider, color-swatch, color-swatch-picker, combo-box, date-field, date-picker, date-range-picker, description, disclosure, disclosure-group, drawer, dropdown, empty-state, error-message, field-error, fieldset, form, header, input, input-group, input-otp, kbd, label, link, list-box, list-box-item, list-box-section, menu, menu-item, menu-section, meter, modal, number-field, pagination, popover, progress-bar, progress-circle, radio, radio-group, range-calendar, scroll-shadow, search-field, select, separator, skeleton, slider, spinner, surface, switch, switch-group, table, tabs, tag, tag-group, textarea, textfield, time-field, toast, toggle-button, toggle-button-group, toolbar, tooltip, typography
**In Progress**: calendar-year-picker
> Source of truth: `packages/react/src/components/index.ts`.
## Development Workflow
### Standard Feature Development Process
**IMPORTANT**: When working on any feature or improvement, Claude Code MUST follow this systematic workflow to ensure accuracy and code quality:
1. **Research Phase**:
- Thoroughly research the feature/component requirements
- Study relevant documentation (React Aria, Tailwind CSS, etc.)
- Analyze existing similar implementations in the codebase
- Identify all dependencies and integration points
2. **Planning Phase**:
- Create a detailed implementation plan with a comprehensive checklist
- Break down the task into specific, measurable steps
- Include testing and verification steps in the plan
- Present the plan for review before proceeding
3. **Review & Correction Phase**:
- Review the plan for completeness and accuracy
- Make necessary corrections or adjustments
- Ensure all edge cases are considered
- Confirm the plan aligns with HeroUI patterns and conventions
4. **Execution Phase**:
- Start executing the plan step by step
- Use the TodoWrite tool to track progress automatically
- Mark todos as in_progress when starting a task
- Mark todos as completed immediately after finishing each step
- Never batch completions - update status in real-time
5. **Verification Phase**:
- Manually verify all changes work as expected
- Test API calls if backend changes were made
- Check frontend rendering and interactions
- Run lint and type checks: `pnpm lint && pnpm typecheck`
- Ensure all tests pass: `pnpm test`
**Example Workflow**:
```
User: "Add a new Select component"
Claude:
1. Research: Studies React Aria Select, existing patterns
2. Plan: Creates detailed checklist with 15+ items
3. Review: Presents plan for feedback
4. Execute: Implements step-by-step with todo updates
5. Verify: Tests component, runs checks, confirms functionality
```
This workflow ensures thorough understanding, proper planning, and high-quality implementation with full transparency throughout the process.
### Component Development Workflow
1. **Creating New Components**:
**CRITICAL: Research & Design Phase**:
- **FIRST**: Check the Figma design for the component breakdown (e.g., Menu Container, Menu Item, etc.)
- **SECOND**: Research the React Aria Components documentation at https://react-spectrum.adobe.com/react-aria/
- Find the appropriate React Aria primitive (e.g., CheckboxGroup, Dialog, Select, etc.)
- Understand the React Aria API, props, and accessibility features
- Map Figma component pieces to React Aria components and plan the compound structure
- Plan how to adapt it to follow Radix UI's compound component pattern
**Component Creation - ALWAYS USE THE SCRIPT**:
```bash
# Navigate to packages/react directory
cd packages/react
# Use the add:component script
pnpm add:component ComponentName
# Examples:
pnpm add:component Menu
pnpm add:component Select
pnpm add:component DatePicker
```
This script will:
- Create all necessary files with proper structure
- Add the export to `src/components/index.ts`
- Generate boilerplate following HeroUI patterns
- Set up the component with TypeScript and proper exports
After creating the component:
```bash
# Build to update package.json exports automatically
pnpm build
```
**Implementation Steps**:
- Study existing HeroUI components (accordion, alert) to understand the compound pattern
- Use React Aria Components as the foundation for accessibility
- Transform React Aria's API to match Radix UI patterns:
- Single component β Multiple exported parts (Item, Trigger, Content, etc.)
- Props-based API β Composition-based API
- Internal state β Context-based state sharing
- Create Context for sharing styles across component parts
- Export ALL component parts for maximum customization
- Define styles in separate `.styles.ts` file with slot system
- Add "use client" directive at the top of component file
- Create comprehensive Storybook stories showing all variants and compositions
- Follow the export pattern: `export * as ComponentName from "./component-name"`
**Example Transformation**:
```typescript
// React Aria: Single component with props
<CheckboxGroup label="Options" value={selected} onChange={setSelected}>
<Checkbox value="1">Option 1</Checkbox>
</CheckboxGroup>
// HeroUI: Compound pattern
<CheckboxGroup value={selected} onValueChange={setSelected}>
<CheckboxGroup.Label>Options</CheckboxGroup.Label>
<CheckboxGroup.Item value="1">
<CheckboxGroup.Indicator />
<CheckboxGroup.Label>Option 1</CheckboxGroup.Label>
</CheckboxGroup.Item>
</CheckboxGroup>
```
**Example of a compound component exports**
```typescript
const CompoundAccordion = Object.assign(Accordion, {
Item: AccordionItem,
Heading: AccordionHeading,
Trigger: AccordionTrigger,
Panel: AccordionPanel,
Indicator: AccordionIndicator,
Body: AccordionBody,
});
export type {
AccordionProps,
AccordionItemProps,
AccordionTriggerProps,
AccordionPanelProps,
AccordionIndicatorProps,
AccordionBodyProps,
};
export default CompoundAccordion;
```
**IMPORTANT**: The compound component should be exported as the default export.
2. **Testing**:
- Follow Behavioral tests conventions above (semantics-first, `setupUser`, `data-*` state hooks)
- Run `pnpm test` for jsdom + browser; filter with `pnpm --filter @heroui/react exec vitest run <name>`
- Place tests under `packages/react/tests/components/<name>/` (`*.test.tsx` / `*.ssr.test.tsx` / `*.browser.test.tsx`, optional `fixtures.tsx`)
- Prefer arrow functions for harness helpers and test fixtures
3. **Documentation**:
- Docs live in `apps/docs/content/`
- Uses MDX format
- HeroUI components are pre-imported
4. **Version Management**:
- Uses [bumpp](https://github.com/antfu/bumpp) for version bumping
- Run `pnpm version:bump` to interactively bump the version, commit, and tag
- Pushing a `v*` tag triggers the release CI workflow
- Follow semantic versioning
## Icon Library
**IMPORTANT**: HeroUI uses Iconify with gravity-ui as the default icon set.
## Important Notes
- Always prefer editing existing files over creating new ones
- **NEVER** create documentation files (_.md, _.mdx, README files) unless explicitly requested by the user
- Follow the established component patterns and conventions
- Ensure accessibility with React Aria Components
- Maintain TypeScript type safety
- Use the commit convention to avoid git hook failures
- Run lint and type checks before committing: `pnpm lint && pnpm typecheck`
## Tailwind CSS Class Detection Rules
**CRITICAL**: Tailwind CSS scans files as plain text and requires complete class names to be statically detectable.
### Key Rules:
1. **Never construct class names dynamically**
β **BAD** - Dynamic string concatenation:
```jsx
// These patterns will NOT work:
<div className={`text-${color}-600`} />
<button className={`bg-${variant}-500`} />
<span className={`button--${size}`} />
```
β
**GOOD** - Complete class names:
```jsx
// Use complete strings or object mappings:
<div className={error ? "text-red-600" : "text-green-600"} />
```
2. **Use object mappings for dynamic classes**
β **BAD** - Props in template literals:
```jsx
function Button({color}) {
return <button className={`bg-${color}-600 hover:bg-${color}-500`} />;
}
```
β
**GOOD** - Map props to complete classes:
```jsx
function Button({color}) {
const colorVariants = {
blue: "bg-blue-600 hover:bg-blue-500",
red: "bg-red-600 hover:bg-red-500",
};
return <button className={colorVariants[color]} />;
}
```
3. **For BEM-style classes, use complete mappings**
β
**GOOD** - Complete class name mappings:
```jsx
const sizeClasses = {
sm: "button--sm",
md: "button--md",
lg: "button--lg",
};
// Use the mapping:
className={sizeClasses[size]}
```
### Why This Matters:
- Tailwind generates CSS only for classes it can detect in your source files
- Dynamic concatenation prevents Tailwind from finding the complete class names
- Missing classes = missing styles in production
## Figma Integration & MCP Server Rules
### Figma Dev Mode MCP Server
**IMPORTANT**: When creating components with Figma designs:
1. **Component Breakdown**: Figma designs are already broken down into component pieces (e.g., Menu Container, Menu Item, etc.). Use these as reference for:
- Component structure and naming (adapt to code conventions)
- Visual styling and spacing
- Component composition patterns
2. **MCP Server Rules**:
- The Figma Dev Mode MCP Server provides an assets endpoint for images and SVG assets
- **CRITICAL**: If the Figma MCP Server returns a localhost source for an image or SVG, use that source directly
- **DO NOT** import or add new icon packages - all assets should come from the Figma payload
- **DO NOT** use or create placeholders if a localhost source is provided
- Always use the actual assets from Figma MCP Server
3. **Workflow**:
- Check Figma for component visual design and breakdown
- Map Figma component names to appropriate React Aria primitives
- Use Figma assets (icons, images) directly from the MCP Server
- Implement styles based on Figma design tokens and specifications
## Library Documentation with Context7 MCP
**IMPORTANT**: We have the Context7 MCP server available (https://github.com/upstash/context7) for accessing up-to-date library documentation.
### When to Use Context7
Use Context7 MCP when working with external libraries, especially:
- **Tailwind CSS v4**: When working with Tailwind CSS v4 features, use Context7 to get the latest documentation at https://context7.com/context7/tailwindcss
- **Fumadocs**: When working on the documentation site in `apps/docs/`, use Context7 to get the latest Fumadocs framework documentation
- **Next.js**: For Next.js specific features and APIs used in the docs app
- Any other third-party libraries where up-to-date documentation is needed
### How to Use Context7
1. First, resolve the library ID using `mcp__context7__resolve-library-id`
2. Then fetch documentation using `mcp__context7__get-library-docs` with the resolved ID
3. This ensures you're always working with the latest documentation rather than outdated information
### Example Usage Areas
- Implementing new documentation features in `apps/docs/`
- Configuring Fumadocs settings in `source.config.ts`
- Working with MDX components and layouts
- Setting up search functionality
- Implementing documentation navigation and structure
## GitHub Repository Search with Grep MCP
**IMPORTANT**: We have the Grep MCP server available for searching over a million public GitHub repositories to find real-world code examples and patterns.
### When to Use Grep MCP
Use the Grep MCP (`mcp__grep__searchGitHub`) when tackling complex problems that require:
- **Real-world implementation examples**: Finding how other developers solve similar problems
- **Best practices and patterns**: Discovering production-ready code patterns
- **Library usage examples**: Understanding how specific APIs or libraries are used in practice
- **Complex integrations**: Seeing how different libraries work together
- **Error handling patterns**: Learning from battle-tested error handling approaches
### How to Use Grep MCP
The Grep MCP searches for **literal code patterns**, not keywords. Use actual code syntax:
**Good examples**:
- `'useState('` - Find React hooks usage
- `'import { tv } from "tailwind-variants"'` - Find tailwind-variants imports
- `'forwardRef<'` - Find forwardRef usage patterns
- `'(?s)useEffect\\(\\(\\) => {.*return.*}'` - Find useEffect with cleanup (regex)
**Bad examples**:
- `'react best practices'` - This is a keyword, not code
- `'how to use tailwind'` - Use actual import statements instead
### Example Use Cases
1. **Complex Component Patterns**:
- Search: `'compound.*component'` with language=['TypeScript', 'TSX']
- Find how others implement compound component patterns
2. **Accessibility Implementations**:
- Search: `'AriaProps'` or `'useAriaLabel'`
- Discover accessibility patterns in React apps
3. **Monorepo Configurations**:
- Search: `'pnpm-workspace.yaml'` with path='pnpm-workspace.yaml'
- Study monorepo setups similar to HeroUI
4. **Tailwind CSS v4 Patterns**:
- Search: `'@import "tailwindcss"'` with language=['CSS']
- Find Tailwind CSS v4 usage patterns
5. **React Aria Components Usage**:
- Search: `'from "react-aria-components"'`
- See how others integrate React Aria Components
### Best Practices
- Use language filters to narrow results (e.g., `language=['TypeScript', 'TSX']`)
- Use regex patterns with `useRegexp=true` for flexible matching
- Filter by well-known repositories for quality examples (e.g., `repo='vercel/'`)
- Combine with file path filters for specific file types
## Agent-Specific Guidelines
### For style-migrator and tailwind-v4-css-expert Agents
When working with HeroUI CSS components, follow these critical patterns:
#### Default Size Implementation
**REQUIRED**: All CSS components MUST follow the default size pattern:
1. **Base classes** include default dimensions equivalent to `--md` variant
2. **Medium variant** (`--md`) is an empty class with explanatory comment
3. **Size variants** override the base defaults
**Template for CSS components with size variants:**
```css
/* Base component styles */
.component {
/* Base styling */
@apply [base-styles];
/* Default size - matches component--md variant */
@apply [default-size-classes];
}
/* Size variants */
.component--sm {
@apply [small-size-overrides];
}
.component--md {
/* No styles as this is the default size */
}
.component--lg {
@apply [large-size-overrides];
}
```
#### Pseudo-Class Fallback Pattern
**REQUIRED**: All interactive components MUST include both pseudo-class and data-attribute support:
```css
/* Interactive states - both approaches */
.component {
/* Hover states */
&:hover,
&[data-hovered="true"] {
@apply [hover-styles];
}
/* Active/pressed states */
&:active,
&[data-pressed="true"] {
@apply [active-styles];
}
/* Focus states */
&:focus-visible,
&:focus:not(:focus-visible),
&[data-focus-visible="true"] {
outline: 2px solid var(--focus);
outline-offset: 2px;
}
}
```
#### Component Examples
- **button.css**: Base has `h-10 md:h-9`, empty `.button--md` variant
- **avatar.css**: Base has `size-10`, empty `.avatar--md` variant
- **spinner.css**: Base has `size-6`, empty `.spinner--md` variant
These patterns ensure components never appear broken and maintain consistency across the design system.
---
name: heroui-native
description: "HeroUI Native component library for React Native (Tailwind v4 via Uniwind). Use when building mobile UIs with HeroUI Native β creating Buttons, Cards, TextFields, Dialogs; installing heroui-native; configuring dark/light themes; or fetching component docs. Keywords: HeroUI Native, heroui-native, React Native UI, Uniwind, mobile components."
metadata:
author: heroui
version: "2.0.1"
---
# HeroUI Native Development Guide
HeroUI Native is a component library built on **Uniwind (Tailwind CSS for React Native)** and **React Native**, providing accessible, customizable UI components for mobile applications.
---
## Installation
```bash
curl -fsSL https://heroui.com/install | bash -s heroui-native
```
---
## CRITICAL: Native Only - Do Not Use Web Patterns
**This guide is for HeroUI Native ONLY.** Do NOT apply HeroUI React (web) patterns β the package, styling engine, and color format all differ:
| Feature | React (Web) | Native (Mobile) |
| ------------ | -------------------- | ----------------------------------- |
| **Styling** | Tailwind CSS v4 | Uniwind (Tailwind for React Native) |
| **Colors** | oklch format | HSL format |
| **Package** | `@heroui/react` | `heroui-native` |
| **Platform** | Web browsers | iOS & Android |
```tsx
// CORRECT β Native pattern
import { Button } from "heroui-native";
<Button variant="primary" onPress={() => console.log("Pressed!")}>
Click me
</Button>;
```
**Always fetch Native docs before implementing.**
---
## Core Principles
- Semantic variants (`primary`, `secondary`, `tertiary`) over visual descriptions
- Composition over configuration (compound components)
- Theme variables with HSL color format
- React Native StyleSheet patterns with Uniwind utilities
---
## Accessing Documentation & Component Information
**For component details, examples, props, and implementation patterns, always fetch documentation:**
### Using Scripts
```bash
# List all available components
node scripts/list_components.mjs
# Get component documentation (MDX)
node scripts/get_component_docs.mjs Button
node scripts/get_component_docs.mjs Button Card TextField
# Get theme variables
node scripts/get_theme.mjs
# Get non-component docs (guides, releases)
node scripts/get_docs.mjs /docs/native/getting-started/theming
```
### Direct MDX URLs
Component docs: fetch `.mdx` with a concrete kebab-case slug. Run `node scripts/list_components.mjs` when the slug is unknown, and never fetch a URL that still contains a placeholder.
Examples:
- Button: `https://heroui.com/docs/native/components/button.mdx`
- Dialog: `https://heroui.com/docs/native/components/dialog.mdx`
- TextField: `https://heroui.com/docs/native/components/text-field.mdx`
Getting started guides: use a concrete topic URL such as `https://heroui.com/docs/native/getting-started/quick-start.mdx`.
**Important:** Always fetch component docs before implementing. The MDX docs include complete examples, props, anatomy, and API references.
---
## Installation Essentials
### Quick Install
```bash
npm i heroui-native react-native-reanimated react-native-gesture-handler react-native-safe-area-context @gorhom/bottom-sheet react-native-svg react-native-worklets tailwind-merge tailwind-variants
```
### Framework Setup (Expo - Recommended)
1. **Install dependencies:**
```bash
npx create-expo-app MyApp
cd MyApp
npm i heroui-native uniwind tailwindcss
npm i react-native-reanimated react-native-gesture-handler react-native-safe-area-context @gorhom/bottom-sheet react-native-svg react-native-worklets tailwind-merge tailwind-variants
```
2. **Create `global.css`:**
```css
@import "tailwindcss";
@import "uniwind";
@import "heroui-native/styles";
@source "./node_modules/heroui-native/lib";
```
3. **Wrap app with providers:**
```tsx
import { GestureHandlerRootView } from "react-native-gesture-handler";
import { HeroUINativeProvider } from "heroui-native";
import "./global.css";
export default function Layout() {
return (
<GestureHandlerRootView style={{ flex: 1 }}>
<HeroUINativeProvider>
<App />
</HeroUINativeProvider>
</GestureHandlerRootView>
);
}
```
### Critical Setup Requirements
1. **Uniwind is Required** - HeroUI Native uses Uniwind (Tailwind CSS for React Native)
2. **HeroUINativeProvider Required** - Wrap your app with `HeroUINativeProvider`
3. **GestureHandlerRootView Required** - Wrap with `GestureHandlerRootView` from react-native-gesture-handler
4. **Use Compound Components** - Components use compound structure (e.g., `Card.Header`, `Card.Body`)
5. **Use onPress, not onClick** - React Native uses `onPress` event handlers
6. **Platform-Specific Code** - Use `Platform.OS` for iOS/Android differences
---
## Component Patterns
HeroUI Native uses **compound component patterns**. Each component has subcomponents accessed via dot notation.
**Example - Card:**
```tsx
<Card>
<Card.Header>{/* Icons, badges */}</Card.Header>
<Card.Body>
<Card.Title>Title</Card.Title>
<Card.Description>Description</Card.Description>
</Card.Body>
<Card.Footer>{/* Actions */}</Card.Footer>
</Card>
```
**Key Points:**
- Always use compound structure - don't flatten to props
- Subcomponents are accessed via dot notation (e.g., `Card.Header`)
- Native Card uses `Card.Body` (not `Card.Content`); Title and Description go inside Body
- **Fetch component docs for complete anatomy and examples**
---
## Semantic Variants
HeroUI uses semantic naming to communicate functional intent:
| Variant | Purpose | Usage |
| ------------- | --------------------------------- | -------------- |
| `primary` | Main action to move forward | 1 per context |
| `secondary` | Alternative actions | Multiple |
| `tertiary` | Dismissive actions (cancel, skip) | Sparingly |
| `danger` | Destructive actions | When needed |
| `danger-soft` | Soft destructive actions | Less prominent |
| `ghost` | Low-emphasis actions | Minimal weight |
| `outline` | Secondary actions | Bordered style |
**Don't use raw colors** - semantic variants adapt to themes and accessibility.
---
## Theming
HeroUI Native uses CSS variables via Tailwind/Uniwind for theming. Theme colors are defined in `global.css`:
```css
@theme {
--color-accent: hsl(260, 100%, 70%);
--color-accent-foreground: hsl(0, 0%, 100%);
}
```
**Get current theme variables:**
```bash
node scripts/get_theme.mjs
```
**Access theme colors programmatically:**
```tsx
import { useThemeColor } from "heroui-native";
const accentColor = useThemeColor("accent");
```
**Theme switching (Light/Dark Mode):**
```tsx
import { Uniwind, useUniwind } from "uniwind";
const { theme } = useUniwind();
Uniwind.setTheme(theme === "light" ? "dark" : "light");
```
For detailed theming, fetch: `https://heroui.com/docs/native/getting-started/theming.mdx`
---
name: heroui-react
description: "HeroUI v3 React component library (Tailwind CSS v4 + React Aria). Use when building UIs with HeroUI β creating Buttons, Modals, Forms, Cards; installing @heroui/react; configuring dark/light themes with oklch variables; or fetching component docs. Keywords: HeroUI, Hero UI, heroui, @heroui/react, @heroui/styles."
metadata:
author: heroui
version: "3.0.1"
---
# HeroUI v3 React Development Guide
HeroUI v3 is a component library built on **Tailwind CSS v4** and **React Aria Components**, providing accessible, customizable UI components for React applications.
---
## Installation
```bash
curl -fsSL https://heroui.com/install | bash -s heroui-react
```
---
## CRITICAL: v3 Only - Ignore v2 Knowledge
**This guide is for HeroUI v3 ONLY.** Do NOT apply v2 patterns β the provider, styling, and component API all changed:
| Feature | v2 (DO NOT USE) | v3 (USE THIS) |
| ------------- | --------------------------------- | ------------------------------------------- |
| Provider | `<HeroUIProvider>` required | **No Provider needed** |
| Animations | `framer-motion` package | CSS-based, no extra deps |
| Component API | Flat props: `<Card title="x">` | Compound: `<Card><Card.Header>` |
| Styling | Tailwind v3 + `@heroui/theme` | Tailwind v4 + `@heroui/styles` |
| Packages | `@heroui/system`, `@heroui/theme` | `@heroui/react`, `@heroui/styles` |
```tsx
// DO NOT DO THIS - v2 pattern
import { HeroUIProvider } from "@heroui/react";
import { motion } from "framer-motion";
<HeroUIProvider>
<Card title="Product" description="A great product" />
</HeroUIProvider>;
```
### CORRECT (v3 patterns)
```tsx
// DO THIS - v3 pattern (no provider, compound components)
import { Card } from "@heroui/react";
<Card>
<Card.Header>
<Card.Title>Product</Card.Title>
<Card.Description>A great product</Card.Description>
</Card.Header>
</Card>;
```
**Always fetch v3 docs before implementing.**
---
## Core Principles
- Semantic variants (`primary`, `secondary`, `tertiary`) over visual descriptions
- Composition over configuration (compound components)
- CSS variable-based theming with `oklch` color space
- BEM naming convention for predictable styling
---
## Accessing Documentation & Component Information
**For component details, examples, props, and implementation patterns, always fetch documentation:**
### Using Scripts
```bash
# List all available components
node scripts/list_components.mjs
# Get component documentation (MDX)
node scripts/get_component_docs.mjs Button
node scripts/get_component_docs.mjs Button Card TextField
# Get component source code
node scripts/get_source.mjs Button
# Get component CSS styles (BEM classes)
node scripts/get_styles.mjs Button
# Get theme variables
node scripts/get_theme.mjs
# Get non-component docs (guides, releases)
node scripts/get_docs.mjs /docs/react/getting-started/theming
```
### Direct MDX URLs
Component docs: fetch `.mdx` with a concrete kebab-case slug. Run `node scripts/list_components.mjs` when the slug is unknown, and never fetch a URL that still contains a placeholder.
Examples:
- Button: `https://heroui.com/docs/react/components/button.mdx`
- Modal: `https://heroui.com/docs/react/components/modal.mdx`
- Form: `https://heroui.com/docs/react/components/form.mdx`
Getting started guides: use a concrete topic URL such as `https://heroui.com/docs/react/getting-started/quick-start.mdx`.
**Important:** Always fetch component docs before implementing. The MDX docs include complete examples, props, anatomy, and API references.
---
## Installation Essentials
### Quick Install
```bash
npm i @heroui/styles @heroui/react tailwind-variants
```
### Framework Setup (Next.js App Router - Recommended)
1. **Install dependencies:**
```bash
npm i @heroui/styles @heroui/react tailwind-variants tailwindcss @tailwindcss/postcss postcss
```
2. **Create/update `app/globals.css`:**
```css
/* Tailwind CSS v4 - Must be first */
@import "tailwindcss";
/* HeroUI v3 styles - Must be after Tailwind */
@import "@heroui/styles";
```
3. **Import in `app/layout.tsx`:**
```tsx
import "./globals.css";
export default function RootLayout({
children,
}: {
children: React.ReactNode;
}) {
return (
<html lang="en" suppressHydrationWarning>
<body>
{/* No Provider needed in HeroUI v3! */}
{children}
</body>
</html>
);
}
```
4. **Configure PostCSS (`postcss.config.mjs`):**
```js
export default {
plugins: {
"@tailwindcss/postcss": {},
},
};
```
### Critical Setup Requirements
1. **Tailwind CSS v4 is MANDATORY** - HeroUI v3 will NOT work with Tailwind CSS v3
2. **Use Compound Components** - Components use compound structure (e.g., `Card.Header`, `Card.Content`)
3. **Use onPress, not onClick** - For better accessibility, use `onPress` event handlers
4. **Import Order Matters** - Always import Tailwind CSS before HeroUI styles
---
## Component Patterns
All components use the **compound pattern** shown above (dot-notation subcomponents like `Card.Header`, `Card.Content`). Don't flatten to props β always compose with subcomponents. Fetch component docs for complete anatomy and examples.
---
## Semantic Variants
HeroUI uses semantic naming to communicate functional intent:
| Variant | Purpose | Usage |
| ----------- | --------------------------------- | -------------- |
| `primary` | Main action to move forward | 1 per context |
| `secondary` | Alternative actions | Multiple |
| `tertiary` | Dismissive actions (cancel, skip) | Sparingly |
| `danger` | Destructive actions | When needed |
| `ghost` | Low-emphasis actions | Minimal weight |
| `outline` | Secondary actions | Bordered style |
**Don't use raw colors** - semantic variants adapt to themes and accessibility.
---
## Theming
HeroUI v3 uses CSS variables with `oklch` color space:
```css
:root {
--accent: oklch(0.6204 0.195 253.83);
--accent-foreground: var(--snow);
--background: oklch(0.9702 0 0);
--foreground: var(--eclipse);
}
```
**Get current theme variables:**
```bash
node scripts/get_theme.mjs
```
**Color naming:**
- Without suffix = background (e.g., `--accent`)
- With `-foreground` = text color (e.g., `--accent-foreground`)
**Theme switching:**
```html
<html class="dark" data-theme="dark"></html>
```
For detailed theming, fetch: `https://heroui.com/docs/react/getting-started/theming.mdx`