# 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.9.0 (package manager) - **React**: v19+ - **Tailwind CSS**: v4.1.4 - **TypeScript**: v5.8.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 pnpm test # Test specific component pnpm test button # Run formatting pnpm run format # Run type checking pnpm typecheck ``` ### Package-Specific Commands - Use `--filter` flag with package name: `pnpm build --filter=@heroui/react` - Main packages: `@heroui/react`, `@heroui/docs`, `@heroui/storybook` ## Git Commit Convention **IMPORTANT**: This repository uses conventional commits with strict validation. All commits must follow this format: ``` (): ``` ### 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 │ ├── standard/ # Shared ESLint, Prettier, TypeScript configs │ ├── storybook/ # Storybook configuration │ └── vitest/ # Shared Vitest configurations ├── 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: - `
` → Works perfectly (size-10) - `
` → 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}>({}); // Root component wraps with context const ComponentRoot = React.forwardRef<...>(({children, className, ...props}, ref) => { const slots = React.useMemo(() => componentVariants({...}), [...]); return ( {children} ); }); // Child components consume context const ComponentItem = React.forwardRef<...>(({className, ...props}, ref) => { const {slots} = useContext(ComponentContext); return ( {props.children} ); }); // 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 ``` 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 // For string-only components - pass className directly // OR ``` **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:
// With description:
Get notified when someone mentions you
``` **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 - `accordion`: Collapsible content sections - `alert`: Alert messages with compound components - `avatar`: User avatars with Radix UI - `button`: Button with variants and sizes - `checkbox`: Checkbox with compound components (uses external Label/Description) - `chip`: Small informational badges - `description`: Description text for form fields - `field-error`: Error messages for form fields - `fieldset`: Form field grouping components (Fieldset, Legend, FieldGroup, Field, CheckboxField) - `label`: Label text for form fields - `link`: Styled anchor links - `menu`: Dropdown menu system - `popover`: Popover overlays - `spinner`: Loading indicators - `tabs`: Tab navigation - `typography`: Typography component for headings, body copy, and prose - `textfield`: Text input field with compound components - `tooltip`: Hover tooltips ## 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 Option 1 // HeroUI: Compound pattern Options Option 1 ``` **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**: - Run `pnpm test` for all tests - Run `pnpm test ` for specific component - Ensure all new features have tests 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: