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.
CRITICAL: v3 Only - Ignore v2 Knowledge
This guide is for HeroUI v3 ONLY. Do NOT use any prior knowledge of HeroUI v2.
What Changed in v3
| 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> |
| Event handlers | onClick |
onPress (React Aria) |
| Styling | Tailwind v3 + @heroui/theme |
Tailwind v4 + @heroui/styles@beta |
| Packages | @heroui/system, @heroui/theme |
@heroui/react@beta, @heroui/styles@beta |
WRONG (v2 patterns)
// 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)
// DO THIS - v3 pattern (no provider, compound components)
import { Card } from '@heroui/react@beta';
<Card>
<Card.Header>
<Card.Title>Product</Card.Title>
<Card.Description>A great product</Card.Description>
</Card.Header>
</Card>
Always fetch v3 docs before implementing. Do not assume v2 patterns work.
Core Principles
- Accessibility-first (WCAG 2.1 AA, keyboard navigation, screen readers)
- Semantic variants (
primary,secondary,tertiary) over visual descriptions - Composition over configuration (compound components)
- CSS variable-based theming with
oklchcolor space - BEM naming convention for predictable styling
Accessing Documentation
Fetch component documentation via MDX routes:
https://v3.heroui.com/docs/react/components/{component-name}.mdx
Examples:
- Button:
https://v3.heroui.com/docs/react/components/button.mdx - Modal:
https://v3.heroui.com/docs/react/components/modal.mdx - Form:
https://v3.heroui.com/docs/react/components/form.mdx - Tabs:
https://v3.heroui.com/docs/react/components/tabs.mdx
Getting Started Guides:
- Design Principles:
https://v3.heroui.com/docs/react/getting-started/design-principles.mdx - Styling:
https://v3.heroui.com/docs/react/getting-started/styling.mdx - Theming:
https://v3.heroui.com/docs/react/getting-started/theming.mdx - Colors:
https://v3.heroui.com/docs/react/getting-started/colors.mdx
LLMs.txt Documentation:
- Quick index:
https://v3.heroui.com/react/llms.txt - Full docs:
https://v3.heroui.com/react/llms-full.txt
Available Scripts
Execute these scripts for reliable, up-to-date component information directly from the HeroUI API:
List Components
node scripts/list_components.mjs
Returns all available HeroUI v3 components with version info in JSON format.
Get Component Documentation
node scripts/get_component_docs.mjs Button
node scripts/get_component_docs.mjs Button Card TextField
Returns complete MDX documentation including imports, usage, variants, props, and examples.
Get Source Code
node scripts/get_source.mjs Accordion
node scripts/get_source.mjs Button Card
Returns the React/TypeScript implementation source with GitHub links. Useful for understanding component internals.
Get CSS Styles
node scripts/get_styles.mjs Button
node scripts/get_styles.mjs Button Card Chip
Returns BEM CSS classes for styling with GitHub links. Shows all variants and states.
Get Theme Variables
node scripts/get_theme.mjs
Returns theme CSS variables and design tokens (oklch format) organized by common/light/dark modes.
Get Documentation
node scripts/get_docs.mjs /docs/react/getting-started/theming
node scripts/get_docs.mjs /docs/react/releases/v3-0-0-beta-3
Returns non-component MDX documentation (guides, releases, principles).
Note: For component docs, use get_component_docs.mjs instead.
Installation Guide
CRITICAL: HeroUI v3 is currently in BETA. Always use @beta tag when installing packages.
Quick Install
npm i @heroui/styles@beta @heroui/react@beta tailwind-variants
Or with other package managers:
pnpm add @heroui/styles@beta @heroui/react@beta tailwind-variantsyarn add @heroui/styles@beta @heroui/react@beta tailwind-variantsbun add @heroui/styles@beta @heroui/react@beta tailwind-variants
Framework-Specific Setup
Next.js App Router (Recommended)
- Install dependencies:
npm i @heroui/styles@beta @heroui/react@beta tailwind-variants tailwindcss @tailwindcss/postcss postcss
- Create/update
app/globals.css:
/* Tailwind CSS v4 - Must be first */
@import "tailwindcss";
/* HeroUI v3 styles - Must be after Tailwind */
@import "@heroui/styles";
- Import in
app/layout.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>
);
}
- Configure PostCSS (
postcss.config.mjs):
export default {
plugins: {
"@tailwindcss/postcss": {},
},
};
Important Notes:
- Use
"use client"directive for components with event handlers (onPress,onClick) - Server components can use HeroUI components without event handlers
- Use Next.js
Linkcomponent withclassName="link"for HeroUI styled links - HeroUI v3 uses compound components (e.g.,
Card.Header,Card.Content)
Next.js Pages Router
- Install dependencies:
npm i @heroui/styles@beta @heroui/react@beta tailwind-variants tailwindcss @tailwindcss/postcss postcss
- Create/update
styles/globals.css:
/* Tailwind CSS v4 - Must be first */
@import "tailwindcss";
/* HeroUI v3 styles - Must be after Tailwind */
@import "@heroui/styles";
- Import in
pages/_app.tsx:
import type { AppProps } from "next/app";
import "../styles/globals.css";
export default function MyApp({ Component, pageProps }: AppProps) {
return (
// No Provider needed in HeroUI v3!
<Component {...pageProps} />
);
}
- Configure PostCSS (
postcss.config.mjs):
export default {
plugins: {
"@tailwindcss/postcss": {},
},
};
Vite
- Install dependencies:
npm i @heroui/styles@beta @heroui/react@beta tailwind-variants tailwindcss @tailwindcss/vite @vitejs/plugin-react
- Create/update
src/index.css:
/* Tailwind CSS v4 - Must be first */
@import "tailwindcss";
/* HeroUI v3 styles - Must be after Tailwind */
@import "@heroui/styles";
- Import in
src/main.tsx:
import React from "react";
import ReactDOM from "react-dom/client";
import App from "./App";
import "./index.css";
ReactDOM.createRoot(document.getElementById("root")!).render(
<React.StrictMode>
{/* No Provider needed in HeroUI v3! */}
<App />
</React.StrictMode>
);
- Configure Vite (
vite.config.ts):
import { defineConfig } from "vite";
import react from "@vitejs/plugin-react";
import tailwindcss from "@tailwindcss/vite";
export default defineConfig({
plugins: [react(), tailwindcss()],
});
Astro
- Install dependencies:
npm i @heroui/styles@beta @heroui/react@beta tailwind-variants tailwindcss @tailwindcss/vite @astrojs/react
- Create/update
src/styles/global.css:
/* Tailwind CSS v4 - Must be first */
@import "tailwindcss";
/* HeroUI v3 styles - Must be after Tailwind */
@import "@heroui/styles";
- Configure Astro (
astro.config.mjs):
import { defineConfig } from "astro/config";
import tailwindcss from "@tailwindcss/vite";
import react from "@astrojs/react";
export default defineConfig({
integrations: [react()],
vite: {
plugins: [tailwindcss()],
},
});
- Import in
src/layouts/Layout.astro:
---
import "../styles/global.css";
---
Important Notes:
- React components with HeroUI need client directives (
client:load,client:visible, etc.) - Import global CSS in your Layout.astro or individual pages
General React Setup
- Install dependencies:
npm i @heroui/styles@beta @heroui/react@beta tailwind-variants tailwindcss @tailwindcss/postcss postcss
- Create/update CSS file:
/* Tailwind CSS v4 - Must be first */
@import "tailwindcss";
/* HeroUI v3 styles - Must be after Tailwind */
@import "@heroui/styles";
- Import CSS in your app entry point:
import "./styles/globals.css";
import { createRoot } from "react-dom/client";
import App from "./App";
const container = document.getElementById("root");
const root = createRoot(container!);
root.render(
// No Provider needed in HeroUI v3!
<App />
);
- Configure PostCSS (
postcss.config.js):
module.exports = {
plugins: {
"@tailwindcss/postcss": {},
},
};
Critical Reminders
- Tailwind CSS v4 is MANDATORY - HeroUI v3 will NOT work with Tailwind CSS v3
- No Provider Required - Unlike HeroUI v2, v3 components work directly without a Provider
- Use Compound Components - Components like Card use
Card.Header,Card.Contentpattern - Use onPress, not onClick - For better accessibility, use
onPressevent handlers - Import Order Matters - Always import Tailwind CSS before HeroUI styles
Component Discovery & Information
Checking Available Components
Before using any component, verify it exists in HeroUI v3:
Check component documentation:
- Visit:
https://v3.heroui.com/docs/react/components/{component-name}.mdx - Example:
https://v3.heroui.com/docs/react/components/button.mdx
- Visit:
View component list:
- Check:
https://v3.heroui.com/react/llms.txtfor available components
- Check:
Component naming:
- Components use PascalCase (e.g.,
Button,Card,TextField) - Always verify exact component name before importing
- Components use PascalCase (e.g.,
Understanding Component Anatomy
HeroUI v3 uses compound component patterns. Each component has subcomponents:
Example - Card Component:
<Card> {/* Root component */}
<Card.Header> {/* Subcomponent */}
<Card.Title> {/* Subcomponent */}
<Card.Description> {/* Subcomponent */}
</Card.Header>
<Card.Content> {/* Subcomponent */}
<Card.Footer> {/* Subcomponent */}
</Card>
Key Points:
- Always use compound structure - don't flatten to props
- Subcomponents are accessed via dot notation (e.g.,
Card.Header) - Each subcomponent may have its own props
- Study component anatomy before implementation
Accessing Component Information
Component Documentation:
- Full docs:
https://v3.heroui.com/docs/react/components/{name}.mdx - Includes: description, anatomy, props, examples, API reference
Component Examples:
- Examples are included in component docs
- Show real-world usage patterns
- Demonstrate compound component structure
Component Props:
- Check component docs for complete prop list
- Props are TypeScript-typed
- Use semantic variants (
primary,secondary,danger) not raw colors
Component Source Code:
- React/TS source:
https://raw.githubusercontent.com/heroui-inc/heroui/refs/heads/v3/packages/react/src/components/{component}/{component}.tsx - CSS styles:
https://raw.githubusercontent.com/heroui-inc/heroui/refs/heads/v3/packages/styles/components/{component}.css
Component Selection Guide
Buttons & Actions
- Button - Primary actions, form submissions (
primary,secondary,tertiary,danger,ghost,outline) - ButtonGroup - Group related buttons
- CloseButton - Dismiss actions for modals, alerts
Form Inputs
- Input / TextField - Single-line text entry
- TextArea - Multi-line text entry
- SearchField - Search with clear button
- Select - Dropdown selection
- ComboBox / Autocomplete - Searchable dropdown
- Checkbox / CheckboxGroup - Multi-select options
- RadioGroup - Single-select options
- Switch - Binary toggles
- Slider - Numeric ranges
- DateField / TimeField - Date and time entry
- NumberField - Numeric entry with increment/decrement
- InputOTP - Verification codes
Form Structure
- Form - Form container with validation
- Label - Field labels
- Fieldset - Group related fields
- Description - Helper text
- FieldError / ErrorMessage - Validation errors
Layout & Display
- Card - Content containers
- Surface - Generic styled container
- Separator - Visual dividers
- Avatar - User/entity representation
- Chip - Tags, status indicators
- Alert - Status messages
- Skeleton / Spinner - Loading states
- Kbd - Keyboard shortcut display
Navigation
- Accordion / Disclosure / DisclosureGroup - Collapsible sections
- Tabs - Tabbed content
- Link - Navigation links
- Breadcrumbs - Navigation path
- ScrollShadow - Scroll indicators
Overlays
- Modal - Dialogs requiring attention
- AlertDialog - Confirmation dialogs
- Popover - Contextual floating content
- Tooltip - Hover/focus hints
- Dropdown - Menus and context actions
Collections
- ListBox - Selectable lists
- TagGroup - Removable tags
Semantic Variants
HeroUI uses semantic naming to communicate functional intent and hierarchy:
| Variant | Functional Purpose | Usage |
|---|---|---|
primary |
Main action to move forward | 1 per context |
secondary |
Alternative actions | Multiple allowed |
tertiary |
Dismissive actions (cancel, skip) | Sparingly |
danger |
Destructive actions | When needed |
ghost |
Low-emphasis actions | When visual weight should be minimal |
outline |
Secondary actions | When bordered style is needed |
<Button variant="primary">Save</Button>
<Button variant="secondary">Edit</Button>
<Button variant="tertiary">Cancel</Button>
<Button variant="danger">Delete</Button>
Quick Implementation Patterns
Basic Usage
import { Button } from '@heroui/react@beta';
function MyComponent() {
return (
<Button variant="primary" => console.log('Pressed!')}>
Click me
</Button>
);
}
Render Props for Dynamic Styling
<Button>
{({ isPressed, isHovered }) => (
<span className={isPressed ? 'scale-95' : ''}>
{isHovered ? 'Go!' : 'Click'}
</span>
)}
</Button>
Data Attributes for CSS Styling
.button[data-hovered="true"] { background: var(--accent-hover); }
.button[data-pressed="true"] { transform: scale(0.97); }
.button[data-focus-visible="true"] { outline: 2px solid var(--focus); }
.button[data-disabled="true"] { opacity: var(--disabled-opacity); }
BEM Class Customization
@layer components {
.button {
@apply font-semibold uppercase;
}
.button--primary {
@apply bg-gradient-to-r from-purple-500 to-pink-500;
}
}
Form with Validation
import { Form, TextField, Input, Label, FieldError, Button } from '@heroui/react@beta';
<Form
<TextField name="email" type="email" isRequired>
<Label>Email</Label>
<Input />
<FieldError />
</TextField>
<Button type="submit" variant="primary">Submit</Button>
</Form>
For detailed patterns, see component-patterns.md.
Theming Quick Reference
HeroUI uses CSS variables with oklch color space:
:root {
--accent: oklch(0.6204 0.195 253.83);
--accent-foreground: var(--snow);
--background: oklch(0.9702 0 0);
--foreground: var(--eclipse);
--success: oklch(0.7329 0.1935 150.81);
--warning: oklch(0.7819 0.1585 72.33);
--danger: oklch(0.6532 0.2328 25.74);
}
Color naming:
- Without suffix = background (e.g.,
--accent) - With
-foreground= text color (e.g.,--accent-foreground)
Theme switching:
<html class="dark" data-theme="dark">
Accessing Theme Variables
HeroUI v3 uses CSS custom properties organized by category:
Theme Variables Source:
- Default theme:
https://raw.githubusercontent.com/heroui-inc/heroui/refs/heads/v3/packages/styles/themes/default/variables.css
Theme Categories:
- Colors:
--accent,--success,--danger,--background,--foreground - Typography: Font sizes, weights, line heights
- Spacing: Margin, padding, gap values
- Borders: Border radius, widths, colors
- Shadows: Box shadows and elevations
- Animations: Durations, timing functions
Customizing Theme Variables:
:root {
/* Override accent color */
--accent: oklch(0.7 0.25 260);
--accent-foreground: var(--snow);
/* Override border radius */
--radius: 0.75rem;
/* Custom spacing */
--spacing-4: 1rem;
}
Dark Mode Variables:
[data-theme="dark"],
.dark {
--background: oklch(0.1 0 0);
--foreground: oklch(0.95 0 0);
--accent: oklch(0.65 0.2 260);
}
Theme Variable Naming:
- Without suffix = background (e.g.,
--accent) - With
-foreground= text color (e.g.,--accent-foreground) - Use
oklch()color space for better color manipulation
For detailed theming, see theming-customization.md.
Documentation Access Patterns
Component Documentation
Fetch component documentation from v3.heroui.com:
Pattern:
https://v3.heroui.com/docs/react/components/{component-name}.mdx
Examples:
- Button:
https://v3.heroui.com/docs/react/components/button.mdx - Modal:
https://v3.heroui.com/docs/react/components/modal.mdx - Form:
https://v3.heroui.com/docs/react/components/form.mdx - Tabs:
https://v3.heroui.com/docs/react/components/tabs.mdx
What's Included:
- Component description and use cases
- Complete anatomy (compound component structure)
- All available props with types and descriptions
- Working code examples
- API reference
- Accessibility features
Getting Started Guides
Pattern:
https://v3.heroui.com/docs/react/getting-started/{topic}.mdx
Available Guides:
- Design Principles:
https://v3.heroui.com/docs/react/getting-started/design-principles.mdx - Styling:
https://v3.heroui.com/docs/react/getting-started/styling.mdx - Theming:
https://v3.heroui.com/docs/react/getting-started/theming.mdx - Colors:
https://v3.heroui.com/docs/react/getting-started/colors.mdx - Quick Start:
https://v3.heroui.com/docs/react/getting-started/quick-start.mdx
LLMs.txt Documentation
For programmatic access:
- Quick index:
https://v3.heroui.com/react/llms.txt - Full docs:
https://v3.heroui.com/react/llms-full.txt
Usage:
- Parse these files to discover available components
- Extract component names and paths
- Build component discovery tools
Source Code Access Patterns
Component React/TypeScript Source
Access component implementation source code:
Pattern:
https://raw.githubusercontent.com/heroui-inc/heroui/refs/heads/v3/packages/react/src/components/{component}/{component}.tsx
Examples:
- Button:
https://raw.githubusercontent.com/heroui-inc/heroui/refs/heads/v3/packages/react/src/components/button/button.tsx - Card:
https://raw.githubusercontent.com/heroui-inc/heroui/refs/heads/v3/packages/react/src/components/card/card.tsx
Use Cases:
- Understanding component internals
- Learning React Aria patterns
- Debugging component behavior
- Customizing component logic
Note: Do NOT copy source code directly - use components via @heroui/react@beta imports.
Component CSS Styles
Access component CSS styles and BEM classes:
Pattern:
https://raw.githubusercontent.com/heroui-inc/heroui/refs/heads/v3/packages/styles/components/{component}.css
Examples:
- Button:
https://raw.githubusercontent.com/heroui-inc/heroui/refs/heads/v3/packages/styles/components/button.css - Modal:
https://raw.githubusercontent.com/heroui-inc/heroui/refs/heads/v3/packages/styles/components/modal.css
Use Cases:
- Understanding BEM class structure
- Customizing component styles
- CSS-only styling (without React components)
- Learning styling patterns
Important: These are framework-agnostic styles from @heroui/styles package. Choose one approach:
- Use
@heroui/reactfor full React components with accessibility - Use
@heroui/stylesfor CSS-only styling without JavaScript
Theme Source Files
Theme Variables:
https://raw.githubusercontent.com/heroui-inc/heroui/refs/heads/v3/packages/styles/themes/default/variables.css
Use Cases:
- Understanding theme variable structure
- Customizing theme variables
- Learning oklch color space usage
- Building custom themes
Accessibility Quick Reference
Built on React Aria for WCAG 2.1 AA compliance:
- Keyboard Navigation - Full support out of the box
- ARIA Attributes - Automatic roles, labels, relationships
- Focus Management - Logical focus order and visible indicators
- Screen Reader Support - Meaningful announcements
Key Practices:
- Always provide visible labels or
aria-labelfor interactive elements - Use semantic HTML structure
- Ensure sufficient color contrast
- Test with keyboard-only navigation
For comprehensive guidance, see accessibility-guide.md.
Web Interface Guidelines Integration
Accessibility (WCAG 2.1 AA)
HeroUI components are built on React Aria for accessibility, but ensure:
- ✅ DO: Use semantic HTML (
<button>,<a>,<label>,<table>) before ARIA - ✅ DO: Icon-only buttons need
aria-label - ✅ DO: Form controls need
<label>oraria-label - ✅ DO: Interactive elements need keyboard handlers
- ✅ DO: Images need
alt(oralt=""if decorative) - ✅ DO: Decorative icons need
aria-hidden="true" - ✅ DO: Async updates (toasts, validation) need
aria-live="polite" - ✅ DO: Headings hierarchical
<h1>–<h6> - ✅ DO: Include skip link for main content
- ✅ DO: Ensure sufficient color contrast
Focus States
- ✅ DO: Interactive elements need visible focus:
focus-visible:ring-*or equivalent - ✅ DO: Use
:focus-visibleover:focus(avoid focus ring on click) - ✅ DO: Group focus with
:focus-withinfor compound controls - ❌ AVOID:
outline-none/outline: nonewithout focus replacement
Example:
.button:focus-visible {
outline: 2px solid var(--accent);
outline-offset: 2px;
}
Forms
- ✅ DO: Inputs need
autocompleteand meaningfulname - ✅ DO: Use correct
type(email,tel,url,number) andinputmode - ✅ DO: Labels clickable (
htmlForor wrapping control) - ✅ DO: Disable spellcheck on emails, codes, usernames (
spellCheck={false}) - ✅ DO: Checkboxes/radios: label + control share single hit target
- ✅ DO: Submit button stays enabled until request starts; spinner during request
- ✅ DO: Errors inline next to fields; focus first error on submit
- ✅ DO: Placeholders end with
…and show example pattern - ❌ AVOID: Never block paste (
onPaste+preventDefault) - ❌ AVOID:
autocomplete="off"on non-auth fields (triggers password managers)
Content Handling
- ✅ DO: Text containers handle long content:
truncate,line-clamp-*, orbreak-words - ✅ DO: Flex children need
min-w-0to allow text truncation - ✅ DO: Handle empty states—don't render broken UI for empty strings/arrays
- ✅ DO: Anticipate short, average, and very long user-generated content
Example:
<div className="min-w-0">
<p className="truncate">{longText}</p>
</div>
{items.length === 0 && (
<EmptyState message="No items found" />
)}
Images
- ✅ DO:
<img>needs explicitwidthandheight(prevents CLS) - ✅ DO: Below-fold images:
loading="lazy" - ✅ DO: Above-fold critical images:
priorityorfetchpriority="high"
Performance
- ✅ DO: Large lists (>50 items): virtualize (
virtua,content-visibility: auto) - ✅ DO: Batch DOM reads/writes; avoid interleaving
- ✅ DO: Prefer uncontrolled inputs; controlled inputs must be cheap per keystroke
- ✅ DO: Add
<link rel="preconnect">for CDN/asset domains - ✅ DO: Critical fonts:
<link rel="preload" as="font">withfont-display: swap - ❌ AVOID: Layout reads in render (
getBoundingClientRect,offsetHeight,scrollTop)
Navigation & State
- ✅ DO: URL reflects state—filters, tabs, pagination, expanded panels in query params
- ✅ DO: Links use
<a>/<Link>(Cmd/Ctrl+click, middle-click support) - ✅ DO: Deep-link all stateful UI (consider URL sync via
nuqsor similar) - ✅ DO: Destructive actions need confirmation modal or undo window—never immediate
- ✅ DO: Warn before navigation with unsaved changes (
beforeunloador router guard)
Touch & Interaction
- ✅ DO:
touch-action: manipulation(prevents double-tap zoom delay) - ✅ DO:
-webkit-tap-highlight-colorset intentionally - ✅ DO:
overscroll-behavior: containin modals/drawers/sheets - ✅ DO: During drag: disable text selection,
inerton dragged elements - ✅ DO:
autoFocussparingly—desktop only, single primary input; avoid on mobile
Safe Areas & Layout
- ✅ DO: Full-bleed layouts need
env(safe-area-inset-*)for notches - ✅ DO: Avoid unwanted scrollbars:
overflow-x-hiddenon containers - ✅ DO: Flex/grid over JS measurement for layout
Locale & i18n
- ✅ DO: Dates/times: use
Intl.DateTimeFormatnot hardcoded formats - ✅ DO: Numbers/currency: use
Intl.NumberFormatnot hardcoded formats - ✅ DO: Detect language via
Accept-Language/navigator.languages, not IP
Anti-Patterns to Avoid
Technical anti-patterns to avoid:
- ❌
user-scalable=noormaximum-scale=1disabling zoom - ❌
transition: all(list properties explicitly) - ❌
outline-nonewithout focus-visible replacement - ❌ Inline
onClicknavigation without<a> - ❌
<div>or<span>with click handlers (should be<button>) - ❌ Images without dimensions
- ❌ Large arrays
.map()without virtualization - ❌ Form inputs without labels
- ❌ Icon buttons without
aria-label - ❌ Hardcoded date/number formats (use
Intl.*)
HeroUI Component Patterns
Using Semantic Variants
Use semantic variants to communicate functional intent:
primary- Main action (1 per context)secondary- Alternative actions (multiple allowed)tertiary- Dismissive actions (cancel, skip)danger- Destructive actionsghost- Low-emphasis actions (when visual weight should be minimal)outline- Secondary actions (when bordered style is needed)
Don't use raw colors - semantic variants adapt to themes and accessibility.
Compound Component Structure
HeroUI's compound components enable flexible layouts:
// Card component structure
<Card>
<Card.Header>
<Card.Title>Title</Card.Title>
<Card.Description>Description</Card.Description>
</Card.Header>
<Card.Content>
{/* Main content */}
</Card.Content>
<Card.Footer>
<Button variant="primary">Action</Button>
</Card.Footer>
</Card>
Technical Customization
When customizing HeroUI components:
- Override theme variables for global changes
- Use
classNamefor component-specific styling - Leverage BEM classes for CSS-only customization
- Use render props for dynamic styling based on state
Theme Customization Best Practices
- Override CSS variables in
:rootfor light mode - Override in
[data-theme="dark"]or.darkfor dark mode - Use
oklch()color space for better color manipulation - Maintain contrast ratios for accessibility
- Test with both light and dark themes