HeroUI Native Components
Guide to using HeroUI Native as the primary UI component library in Caracal starter.
Caracal uses HeroUI Native (v1.0.5) as the primary UI component library, providing 30+ production-ready components with built-in accessibility, theming, and styling.
Why HeroUI Native?
HeroUI Native is a comprehensive UI component library designed specifically for React Native, offering:
- Production-ready components with consistent design
- Built-in accessibility with proper ARIA labels and keyboard navigation
- Theme integration with automatic dark mode support
- TypeScript support with full type safety
- Native performance optimized for React Native
- Uniwind integration for TailwindCSS-like styling
Always refer to the official documentation for the latest updates.
Available Components
HeroUI Native provides 30+ components. Here are the most commonly used:
Form Components
- TextField - Text input with label, error states, and variants
- Button - Pressable button with multiple variants (solid, outline, ghost, light, flat)
- Checkbox - Checkbox with label and controlled state support
- Switch - Toggle switch component with theming
- RadioGroup - Radio button groups with single selection
- Select - Dropdown select with native modal support
- FormField - Complete form field wrapper with validation
Layout Components
- Card - Content container with header, body, footer sections
- Tabs - Tabbed navigation with customizable styles
- Accordion - Collapsible content sections
- Divider - Visual separator with orientation support
- Surface - Container with elevation and shadow effects
- ScrollShadow - Scroll container with shadow indicators
Feedback Components
- Dialog - Modal dialogs with customizable actions
- Toast - Notification messages with auto-dismiss
- Popover - Contextual popovers attached to elements
- BottomSheet - Bottom sheet modals for mobile UX
- Spinner - Loading spinners with various sizes
- Skeleton - Loading placeholders for content
Display Components
- Avatar - User avatars with image, initials, or icon
- Chip - Tags and labels with removable support
- ErrorView - Error state display with retry actions
- PressableFeedback - Pressable wrapper with visual feedback
Basic Usage
Import components from heroui-native:
import { Button, TextField, Card } from 'heroui-native';
import { View } from '@/components/ui';
export function MyScreen() {
return (
<View className="flex-1 p-4">
<Card>
<Card.Header>
<Text className="text-xl font-bold">Login</Text>
</Card.Header>
<Card.Body>
<TextField label="Email" placeholder="Enter your email" />
<TextField label="Password" secureTextEntry />
</Card.Body>
<Card.Footer>
<Button variant="solid" color="primary">
Sign In
</Button>
</Card.Footer>
</Card>
</View>
);
}Component Variants
Most HeroUI Native components support multiple variants:
Button Variants
import { Button } from 'heroui-native';
<Button variant="solid">Solid Button</Button>
<Button variant="outline">Outline Button</Button>
<Button variant="ghost">Ghost Button</Button>
<Button variant="light">Light Button</Button>
<Button variant="flat">Flat Button</Button>TextField Variants
import { TextField } from 'heroui-native';
<TextField variant="outline" label="Outline" />
<TextField variant="underline" label="Underline" />
<TextField variant="filled" label="Filled" />Card Variants
import { Card } from 'heroui-native';
<Card variant="elevated">Elevated Card</Card>
<Card variant="outlined">Outlined Card</Card>
<Card variant="filled">Filled Card</Card>Theming and Styling
Using with Uniwind
HeroUI Native components work seamlessly with Uniwind (TailwindCSS for React Native):
import { Button } from 'heroui-native';
import { View } from '@/components/ui';
<View className="flex-row gap-2 p-4">
<Button className="flex-1">Button 1</Button>
<Button className="flex-1">Button 2</Button>
</View>Color Customization
Components support color props:
<Button color="primary">Primary</Button>
<Button color="secondary">Secondary</Button>
<Button color="success">Success</Button>
<Button color="warning">Warning</Button>
<Button color="danger">Danger</Button>Size Variants
<Button size="sm">Small</Button>
<Button size="md">Medium</Button>
<Button size="lg">Large</Button>Form Handling
HeroUI Native components integrate with react-hook-form through controlled wrappers:
import { zodResolver } from '@hookform/resolvers/zod';
import { useForm } from 'react-hook-form';
import * as z from 'zod';
import { Button } from 'heroui-native';
import { ControlledInput } from '@/components/ui';
const schema = z.object({
email: z.string().email('Invalid email'),
password: z.string().min(6, 'Password too short'),
});
type FormData = z.infer<typeof schema>;
export function LoginForm() {
const { control, handleSubmit } = useForm<FormData>({
resolver: zodResolver(schema),
});
return (
<>
<ControlledInput
control={control}
name="email"
label="Email"
/>
<ControlledInput
control={control}
name="password"
label="Password"
secureTextEntry
/>
<Button onPress={handleSubmit(onSubmit)}>
Login
</Button>
</>
);
}See Forms documentation for complete form handling patterns.
Dark Mode Support
HeroUI Native components automatically adapt to the app's theme:
import { Button } from 'heroui-native';
export function ThemedButton() {
// Components automatically use theme colors
return (
<Button variant="solid" color="primary">
Theme-aware Button
</Button>
);
}The theme is managed by the AppThemeProvider in src/lib/contexts/theme-provider.tsx.
Component Showcases
The Caracal starter includes 30 interactive component showcases in the (components) route group. These showcases demonstrate every HeroUI Native component with:
- All available variants and props
- Usage examples and code snippets
- Dark mode demonstrations
- Form integration patterns
- Accessibility features
Accessing Showcases
Run the app and navigate to the Components section:
pnpm startAvailable Showcases
Form Components (8):
- TextField -
src/app/(components)/text-field.tsx - Button -
src/app/(components)/button.tsx - Checkbox -
src/app/(components)/checkbox.tsx - Switch -
src/app/(components)/switch.tsx - RadioGroup -
src/app/(components)/radio-group.tsx - Select -
src/app/(components)/select.tsx - SelectNativeModal -
src/app/(components)/select-native-modal.tsx - FormField -
src/app/(components)/form-field.tsx
Layout Components (7):
9. Card - src/app/(components)/card.tsx
10. Tabs - src/app/(components)/tabs.tsx
11. Accordion - src/app/(components)/accordion.tsx
12. Divider - src/app/(components)/divider.tsx
13. Surface - src/app/(components)/surface.tsx
14. ScrollShadow - src/app/(components)/scroll-shadow.tsx
15. PressableFeedback - src/app/(components)/pressable-feedback.tsx
Feedback Components (9):
16. Dialog - src/app/(components)/dialog.tsx
17. DialogNativeModal - src/app/(components)/dialog-native-modal.tsx
18. Toast - src/app/(components)/toast.tsx
19. ToastNativeModal - src/app/(components)/toast-native-modal.tsx
20. Popover - src/app/(components)/popover.tsx
21. PopoverNativeModal - src/app/(components)/popover-native-modal.tsx
22. BottomSheet - src/app/(components)/bottom-sheet.tsx
23. BottomSheetNativeModal - src/app/(components)/bottom-sheet-native-modal.tsx
24. Spinner - src/app/(components)/spinner.tsx
25. Skeleton - src/app/(components)/skeleton.tsx
Other Components (5):
26. Avatar - src/app/(components)/avatar.tsx
27. Chip - src/app/(components)/chip.tsx
28. ErrorView - src/app/(components)/error-view.tsx
29. ComponentList - src/app/(components)/component-list.tsx (navigation)
See Component Showcase Guide for detailed documentation on using showcases as learning resources.
Common Patterns
Loading States
import { useState } from 'react';
import { Button } from 'heroui-native';
export function AsyncButton() {
const [loading, setLoading] = useState(false);
return (
<Button
isLoading={loading}
onPress={async () => {
setLoading(true);
await doSomething();
setLoading(false);
}}
>
Submit
</Button>
);
}Disabled States
<Button isDisabled>Disabled Button</Button>
<TextField isDisabled label="Disabled Input" />
<Checkbox isDisabled>Disabled Checkbox</Checkbox>Icon Integration
import { Button } from 'heroui-native';
import { IconCheck } from '@/components/ui/icons';
<Button startContent={<IconCheck size={20} />}>
Save
</Button>Responsive Sizing
import { useWindowDimensions } from 'react-native';
import { Button } from 'heroui-native';
export function ResponsiveButton() {
const { width } = useWindowDimensions();
const size = width < 375 ? 'sm' : 'md';
return <Button size={size}>Responsive</Button>;
}Best Practices
DO
- Use HeroUI Native components for all UI elements (buttons, inputs, cards, etc.)
- Leverage component variants instead of custom styling
- Use the
classNameprop for layout and spacing with Uniwind - Refer to component showcases for usage examples
- Check official docs for latest props and features
DON'T
- Don't recreate HeroUI Native components from scratch
- Don't override internal component styles unnecessarily
- Don't use web-only HeroUI components (this is React Native)
- Don't assume component APIs — check documentation
- Don't ignore accessibility props (label, accessibilityLabel)
Migration from Custom Components
If you're migrating from older versions of the starter that had custom Button, Checkbox, or Select components:
Before (custom components):
import { Button, Checkbox, Select } from '@/components/ui';
<Button label="Click me" variant="primary" />
<Checkbox checked={checked} onChange={setChecked} label="Accept" />
<Select options={options} value={value} onSelect={setValue} />After (HeroUI Native):
import { Button, Checkbox, Select } from 'heroui-native';
<Button variant="solid" color="primary">Click me</Button>
<Checkbox isSelected={checked} onChange={setChecked}>Accept</Checkbox>
<Select items={options} selectedKey={value} onSelectionChange={setValue} />Documentation Resources
- Official HeroUI Native Docs: https://v3.heroui.com/native
- LLM-Optimized Docs: https://v3.heroui.com/native/llms-full.txt
- Component Showcases: Run the app and navigate to Components section
- Custom Components: See Custom Components Guide
- Styling Guide: See UI & Theming
- Forms Integration: See Forms Guide
Troubleshooting
Component not rendering
Check that you've imported from the correct package:
// Correct
import { Button } from 'heroui-native';
// Wrong — these don't exist
import { Button } from '@/components/ui';
import { Button } from 'react-native';TypeScript errors
Ensure you're using the correct prop names. HeroUI Native uses:
isDisablednotdisabledisLoadingnotloadingisSelectednotchecked(for Checkbox)onPressnotonClick
Styling issues
Animated.View from react-native-reanimated doesn't support className. Use the style prop instead:
import Animated from 'react-native-reanimated';
// Won't work
<Animated.View className="flex-1" />
// Correct
<Animated.View style={{ flex: 1 }} />Version Information
- HeroUI Native: 1.0.5
- React Native Compatibility: 0.86.2+
- React Version: 19+
- Expo SDK: 57
- Uniwind Version: 1.10.0
Next Steps:
- Explore Custom Components for specialized components
- Learn about Component Showcases for interactive examples
- Read Forms documentation for form handling patterns