---
title: Design Principles
description: Core principles that guide HeroUI v3's design and development
icon: book
---

HeroUI v3 follows 10 core principles that prioritize clarity, accessibility, customization, and developer experience.

## Core Principles

### 1. Semantic Intent Over Visual Style

Use semantic naming (primary, secondary, tertiary) instead of visual descriptions (solid, flat, bordered). Inspired by [Uber's Base design system](https://base.uber.com/6d2425e9f/p/756216-button), variants follow a clear hierarchy:

<DocsImage
  src="https://heroui-assets.nyc3.cdn.digitaloceanspaces.com/docs/emphasis.jpg"
  darkSrc="https://heroui-assets.nyc3.cdn.digitaloceanspaces.com/docs/emphasis-dark.jpg"
  alt="Semantic Intent Hierarchy"
  className="object-contain"
/>


```tsx
// ✅ Semantic variants communicate hierarchy
<Button variant="primary">Save</Button>
<Button variant="secondary">Edit</Button>
<Button variant="tertiary">Cancel</Button>
```

| Variant | 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 |

### 2. Accessibility as Foundation

Built on [React Aria Components](https://react-spectrum.adobe.com/react-aria/) for WCAG 2.1 AA compliance. Automatic ARIA attributes, keyboard navigation, and screen reader support included.

```tsx
import { Tabs, TabList, Tab, TabPanel } from '@heroui/react';

<Tabs defaultSelectedKey="profile">
  <TabList aria-label="Settings">
    <Tab id="profile">Profile</Tab>
    <Tab id="security">Security</Tab>
  </TabList>
  <TabPanel id="profile">Content</TabPanel>
  <TabPanel id="security">Content</TabPanel>
</Tabs>
```

### 3. Composition Over Configuration

Compound components let you rearrange, customize, or omit parts as needed. Use dot notation, named exports, or mix both.

```tsx
// Compose parts to build exactly what you need
import {
  Accordion,
  AccordionItem,
  AccordionHeading,
  AccordionTrigger,
  AccordionIndicator,
  AccordionPanel,
  AccordionBody
} from '@heroui/react';

<Accordion>
  <AccordionItem id="1">
    <AccordionHeading>
      <AccordionTrigger>
        Question Text
        <AccordionIndicator />
      </AccordionTrigger>
    </AccordionHeading>
    <AccordionPanel>
      <AccordionBody>Answer content</AccordionBody>
    </AccordionPanel>
  </AccordionItem>
</Accordion>
```

### 4. Progressive Disclosure

Start simple, add complexity only when needed. Components work with minimal props and scale up as requirements grow.

```tsx
// Level 1: Minimal
<Button>Click me</Button>

// Level 2: Enhanced
<Button variant="primary" size="lg">
  <Icon icon="gravity-ui:check" className="mr-2" />
  Submit
</Button>

// Level 3: Advanced
<Button variant="primary" isDisabled={isLoading}>
  {isLoading ? <><Spinner size="sm" className="mr-2" /> Loading...</> : 'Submit'}
</Button>
```

### 5. Predictable Behavior

Consistent patterns across all components: sizes (`sm`, `md`, `lg`), variants, className support, and data attributes. Same API, same behavior.

```tsx
// All components follow the same patterns
<Button size="lg" variant="primary" className="custom" data-pressed="true" />
<Chip size="lg" variant="success" className="custom" />
<Avatar size="lg" className="custom" />

// Compound components support both named exports and dot notation
import { Alert, AlertIcon, CardHeader, AccordionTrigger } from '@heroui/react';

// Named exports
<Alert>
  <AlertIcon />
</Alert>

// Dot notation
<Alert>
  <Alert.Icon />
</Alert>
```

### 6. Type Safety First

Full TypeScript support with IntelliSense, auto-completion, and compile-time error detection. Extend types for custom components.

```tsx
import type { ButtonProps } from '@heroui/react';

// Type-safe props and event handlers
<Button
  variant="primary"  // Autocomplete: primary | secondary | tertiary | danger | ghost
  size="md"          // Type checked: sm | md | lg
  onPress={(e) => {  // e is properly typed as PressEvent
    console.log(e.target);
  }}
/>

// Extend types for custom components
interface CustomButtonProps extends Omit<ButtonProps, 'variant'> {
  intent: 'save' | 'cancel' | 'delete';
}
```

### 7. Separation of Styles and Logic

Styles (`@heroui/styles`) are separate from logic (`@heroui/react`), enabling use with any framework or vanilla HTML. See [Tailwind Play example](https://play.tailwindcss.com/vMYXzKPyUx).

```html
<!-- Use with plain HTML -->
<button class="button button--primary">Click me</button>
```

or with React:

```tsx
// Apply styles to any component
import { buttonVariants } from '@heroui/styles';

<Link className={buttonVariants({ variant: "primary" })} href="/home">
  Home
</Link>
```

### 8. Developer Experience Excellence

Clear APIs, descriptive errors, IntelliSense, AI-friendly markdown docs, and Storybook for visual testing.

### 9. Complete Customization

Beautiful defaults out-of-the-box. Transform the entire look with CSS variables or [BEM](https://getbem.com/) classes. Every slot is customizable.

```css
/* Theme-wide changes with variables */
:root {
  --accent: oklch(0.7 0.25 260);
  --radius: 0.375rem;
  --spacing: 0.5rem;
}

/* Component-specific customization */
@layer components {
  .button {
    @apply uppercase tracking-wider;
  }
  .button--primary {
    @apply bg-gradient-to-r from-purple-500 to-pink-500;
  }
}
```

### 10. Open and Extensible

Wrap, extend, and customize components to match your needs. Use variant functions, direct BEM class application, or create custom wrappers.

**Apply styles with variant functions:**

```tsx
import { Link } from '@heroui/react';
import { linkVariants } from '@heroui/styles';
import NextLink from 'next/link';

// Use variant functions to style framework-specific components
const slots = linkVariants({ underline: "hover" });

<NextLink className={slots.base()} href="/about">
  About Page
  <Link.Icon className={slots.icon()} />
</NextLink>
```

**Apply BEM classes directly:**

```tsx
import Link from 'next/link';

// Apply HeroUI's BEM classes directly to any element
<Link className="button button--primary" href="/dashboard">
  Dashboard
</Link>
```

**Create custom wrapper components:**

```tsx
// Custom wrapper component
const CTAButton = ({
  intent = 'primary-cta',
  children,
  ref,
  ...props
}: CTAButtonProps) => {
  const variantMap = {
    'primary-cta': 'primary',
    'secondary-cta': 'secondary',
    'minimal': 'ghost'
  };

  return (
    <Button ref={ref} variant={variantMap[intent]} {...props}>
      {children}
    </Button>
  );
};
```

**Extend with Tailwind Variants:**

```tsx
import { Button } from '@heroui/react';
import { buttonVariants, tv } from '@heroui/styles';

// Extend button styles with custom variants
const myButtonVariants = tv({
  extend: buttonVariants,
  variants: {
    variant: {
      'primary-cta': 'bg-gradient-to-r from-blue-500 to-purple-600 text-white shadow-lg',
      'secondary-cta': 'border-2 border-blue-500 text-blue-500 hover:bg-blue-50',
    }
  }
});

// Use the custom variants
function CustomButton({ variant, className, ...props }) {
  return <Button className={myButtonVariants({ variant, className })} {...props} />;
}

// Usage
<CustomButton variant="primary-cta">Get Started</CustomButton>
<CustomButton variant="secondary-cta">Learn More</CustomButton>
```

## Comparison with HeroUI v2

| Aspect | HeroUI v2 | HeroUI v3 |
|--------|-----------|-----------|
| **Animations** | Framer Motion | CSS + GPU accelerated |
| **Component Pattern** | Single components with many props | Compound components |
| **Variants** | Visual-based (solid, bordered, flat) | Semantic (primary, secondary, tertiary) |
| **Styling** | Tailwind v4 partially supported | Tailwind v4 fully supported |
| **Accessibility** | Excellent (React Aria powered) | Excellent (React Aria powered) |
| **Bundle Size** | Larger (Bundle) | Smaller (tree-shakeable) |
| **Customization Difficulty** | Medium (Props-based) | Simple (Compound components + Native CSS) |
