Design Principles

Core principles that guide HeroUI v3's design and development

HeroUI Native follows 9 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, variants follow a clear hierarchy:

Semantic Intent Hierarchy
// ✅ Semantic variants communicate hierarchy
<Button variant="primary">Save</Button>
<Button variant="secondary">Edit</Button>
<Button variant="tertiary">Cancel</Button>
VariantPurposeUsage
PrimaryMain action to move forward1 per context
SecondaryAlternative actionsMultiple allowed
TertiaryDismissive actions (cancel, skip)Sparingly
DangerDestructive actionsWhen needed

2. Accessibility as Foundation

Accessibility follows mobile development best practices with proper touch accessibility, focus management, and screen reader support built into every component. All components include proper accessibility labels and semantic structure for VoiceOver (iOS) and TalkBack (Android).

import { Tabs } from 'heroui-native';

<Tabs value="profile" onValueChange={setActiveTab}>
  <Tabs.List>
    <Tabs.Indicator />
    <Tabs.Trigger value="profile">
      <Tabs.Label>Profile</Tabs.Label>
    </Tabs.Trigger>
    <Tabs.Trigger value="security">
      <Tabs.Label>Security</Tabs.Label>
    </Tabs.Trigger>
  </Tabs.List>
  <Tabs.Content value="profile">Content</Tabs.Content>
  <Tabs.Content value="security">Content</Tabs.Content>
</Tabs>

3. Composition Over Configuration

Compound components let you rearrange, customize, or omit parts as needed. Use dot notation to compose components exactly as you need them.

// Compose parts to build exactly what you need
import { Accordion } from 'heroui-native';

<Accordion>
  <Accordion.Item value="1">
    <Accordion.Trigger>
      Question Text
      <Accordion.Indicator />
    </Accordion.Trigger>
    <Accordion.Content>Answer content</Accordion.Content>
  </Accordion.Item>
</Accordion>

4. Progressive Disclosure

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

import { Button, Icon, Spinner } from 'heroui-native';

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

// Level 2: Enhanced
<Button variant="primary" size="lg">
  <Icon name="check" size={20} />
  <Button.Label>Submit</Button.Label>
</Button>

// Level 3: Advanced
<Button variant="primary" isDisabled={isLoading}>
  {isLoading ? (
    <>
      <Spinner size="sm" />
      <Button.Label>Loading...</Button.Label>
    </>
  ) : (
    <Button.Label>Submit</Button.Label>
  )}
</Button>

5. Predictable Behavior

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

import { Button, Chip, Avatar } from 'heroui-native';

// All components follow the same patterns
<Button size="lg" variant="primary" className="custom">
  <Button.Label>Click me</Button.Label>
</Button>
<Chip size="lg" color="success" className="custom">
  <Chip.Label>Success</Chip.Label>
</Chip>
<Avatar size="lg" className="custom">
  <Avatar.Fallback>JD</Avatar.Fallback>
</Avatar>

6. Type Safety First

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

import type { ButtonRootProps } from 'heroui-native';

// Type-safe props and event handlers
<Button
  variant="primary"  // Autocomplete: primary | secondary | tertiary | ghost | danger | danger-soft
  size="md"          // Type checked: sm | md | lg
  onPress={() => {   // Properly typed press handler
    console.log('Button pressed');
  }}
>
  <Button.Label>Click me</Button.Label>
</Button>

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

7. Developer Experience Excellence

Clear APIs, descriptive errors, IntelliSense and AI-friendly markdown docs.

8. Complete Customization

Beautiful defaults out-of-the-box. Transform the entire look with CSS variables through Uniwind's theming system. Every slot is customizable.

/* Custom colors using Uniwind's theme layer */
@layer theme {
  @variant light {
    --accent: oklch(0.65 0.25 270); /* Custom indigo accent */
    --background: oklch(0.98 0 0);  /* Custom background */
  }

  @variant dark {
    --accent: oklch(0.65 0.25 270);
    --background: oklch(0.15 0 0);
  }
}

/* Radius customization */
@theme {
  --radius: 0.75rem; /* Increase for rounder components */
}

9. Open and Extensible

Wrap, extend, and customize components to match your needs. Create custom wrappers or apply custom styles using className.

import { Button } from 'heroui-native';
import type { ButtonRootProps } from 'heroui-native';

// Custom wrapper component
interface CTAButtonProps extends Omit<ButtonRootProps, 'variant'> {
  intent?: 'primary-cta' | 'secondary-cta' | 'minimal';
}

const CTAButton = ({
  intent = 'primary-cta',
  children,
  ...props
}: CTAButtonProps) => {
  const variantMap = {
    'primary-cta': 'primary',
    'secondary-cta': 'secondary',
    'minimal': 'ghost'
  } as const;

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

// Usage
<CTAButton intent="primary-cta">Get Started</CTAButton>
<CTAButton intent="secondary-cta">Learn More</CTAButton>

Extend with Tailwind Variants:

import { Button } from 'heroui-native';
import { tv } from 'tailwind-variants';

// Extend button styles with custom variants
const myButtonVariants = tv({
  base: 'px-4 py-2 rounded-lg',
  variants: {
    variant: {
      'primary-cta': 'bg-accent text-accent-foreground px-8 py-4 shadow-lg',
      'secondary-cta': 'border-2 border-accent text-accent px-6 py-3',
    }
  },
  defaultVariants: {
    variant: 'primary-cta',
  }
});

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

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

On this page