Introduction
Components
- Accordion
- Action Sheet
- Alert
- Audio Player
- Audio Recorder
- Audio Waveform
- Avatar
- Badge
- BottomSheet
- Button
- Camera
- Camera Preview
- Card
- Carousel
- Checkbox
- Collapsible
- Color Picker
- Combobox
- Date Picker
- File Picker
- Gallery
- Hello Wave
- Icon
- Image
- Input
- Input OTP
- Link
- MediaPicker
- Mode Toggle
- Onboarding
- ParallaxScrollView
- Picker
- Popover
- Progress
- Radio
- ScrollView
- SearchBar
- Separator
- Share
- Sheet
- Skeleton
- Spinner
- Switch
- Table
- Tabs
- Text
- Toast
- Toggle
- Video
- View
Charts
import { Button } from '@/components/ui/button';
import React from 'react';
export function ButtonDemo() {
return (
<Button onPress={() => console.log('Button pressed!')}>Click me</Button>
);
}
Installation
pnpm dlx bna-ui add button
Usage
import { Button } from '@/components/ui/button';
<Button onPress={() => console.log('Button pressed!')}>Click me</Button>
Examples
Default
import { Button } from '@/components/ui/button';
import React from 'react';
export function ButtonDemo() {
return (
<Button onPress={() => console.log('Button pressed!')}>Click me</Button>
);
}
Variants
import { Button } from '@/components/ui/button';
import { View } from '@/components/ui/view';
import React from 'react';
export function ButtonVariants() {
return (
<View style={{ gap: 12 }}>
<View style={{ flexDirection: 'row', alignItems: 'center', gap: 8 }}>
<Button variant='default' onPress={() => {}} style={{ flex: 1 }}>
Default
</Button>
<Button variant='destructive' onPress={() => {}} style={{ flex: 2 }}>
Destructive
</Button>
</View>
<Button variant='success' onPress={() => {}}>
Success
</Button>
<Button variant='outline' onPress={() => {}}>
Outline
</Button>
<Button variant='secondary' onPress={() => {}}>
Secondary
</Button>
<Button variant='ghost' onPress={() => {}}>
Ghost
</Button>
<Button variant='link' onPress={() => {}}>
Link
</Button>
</View>
);
}
Sizes
import { Button } from '@/components/ui/button';
import { View } from '@/components/ui/view';
import React from 'react';
export function ButtonSizes() {
return (
<View style={{ gap: 12, alignItems: 'flex-start' }}>
<Button size='sm' onPress={() => {}}>
Small
</Button>
<Button size='default' onPress={() => {}}>
Default
</Button>
<Button size='lg' onPress={() => {}}>
Large
</Button>
</View>
);
}
With Icons
import { Button } from '@/components/ui/button';
import { View } from '@/components/ui/view';
import { Download, Mail, Plus, Search } from 'lucide-react-native';
import React from 'react';
export function ButtonWithIcons() {
return (
<View style={{ gap: 12, flexDirection: 'row', flexWrap: 'wrap' }}>
<Button icon={Download} onPress={() => {}}>
Download
</Button>
<Button icon={Mail} variant='outline' onPress={() => {}}>
Email
</Button>
<Button icon={Plus} variant='success' onPress={() => {}}>
Add Item
</Button>
<Button icon={Search} variant='secondary' onPress={() => {}}>
Search
</Button>
</View>
);
}
Icon Only
import { Button } from '@/components/ui/button';
import { View } from '@/components/ui/view';
import {
Heart,
MessageCircle,
MoreHorizontal,
Settings,
Share,
} from 'lucide-react-native';
import React from 'react';
export function ButtonIconOnly() {
return (
<View style={{ gap: 12, flexDirection: 'row', flexWrap: 'wrap' }}>
<Button size='icon' icon={Settings} />
<Button size='icon' variant='outline' icon={Heart} />
<Button size='icon' variant='secondary' icon={Share} />
<Button size='icon' variant='ghost' icon={MoreHorizontal} />
<Button size='icon' variant='destructive' icon={MessageCircle} />
</View>
);
}
Loading States
import { Button } from '@/components/ui/button';
import { View } from '@/components/ui/view';
import { Save } from 'lucide-react-native';
import React from 'react';
export function ButtonLoading() {
return (
<View style={{ gap: 12, flexDirection: 'row', flexWrap: 'wrap' }}>
<Button loading onPress={() => {}}>
Loading...
</Button>
<Button loading variant='outline' onPress={() => {}}>
Please wait
</Button>
<Button loading variant='destructive' onPress={() => {}}>
Deleting...
</Button>
<Button loading size='icon' onPress={() => {}}>
<Save size={20} color='white' />
</Button>
</View>
);
}
Disabled States
import { Button } from '@/components/ui/button';
import { View } from '@/components/ui/view';
import { Lock } from 'lucide-react-native';
import React from 'react';
export function ButtonDisabled() {
return (
<View style={{ gap: 12, flexDirection: 'row', flexWrap: 'wrap' }}>
<Button disabled onPress={() => {}}>
Disabled
</Button>
<Button disabled variant='outline' onPress={() => {}}>
Disabled Outline
</Button>
<Button disabled variant='destructive' onPress={() => {}}>
Disabled Destructive
</Button>
<Button disabled size='icon' onPress={() => {}} icon={Lock} />
</View>
);
}
Custom Styling
import { Button } from '@/components/ui/button';
import { View } from '@/components/ui/view';
import { LinearGradient } from 'expo-linear-gradient';
import { Star } from 'lucide-react-native';
export function ButtonCustom() {
return (
<View style={{ gap: 12, flexDirection: 'row', flexWrap: 'wrap' }}>
<Button
style={{ backgroundColor: '#8B5CF6', borderRadius: 12 }}
textStyle={{ color: 'white', fontWeight: 'bold' }}
onPress={() => {}}
>
Custom Purple
</Button>
<Button
variant='outline'
style={{
borderColor: '#F59E0B',
borderWidth: 2,
borderRadius: 20,
}}
textStyle={{ color: '#F59E0B', fontWeight: '600' }}
onPress={() => {}}
>
Custom Orange
</Button>
<LinearGradient
colors={['#FF6B6B', '#4ECDC4']}
start={{ x: 0, y: 0 }}
end={{ x: 1, y: 1 }}
style={{
borderRadius: 12,
overflow: 'hidden',
flex: 1,
}}
>
<Button
icon={Star}
style={{
backgroundColor: 'transparent',
}}
textStyle={{ color: 'white', fontWeight: 'bold' }}
onPress={() => {}}
>
Gradient Style
</Button>
</LinearGradient>
</View>
);
}
Animation Control
import { Button } from '@/components/ui/button';
import { Text } from '@/components/ui/text';
import { View } from '@/components/ui/view';
import React from 'react';
export function ButtonAnimation() {
return (
<View style={{ gap: 16 }}>
<View>
<Text style={{ marginBottom: 8, fontSize: 14, color: '#71717a' }}>
With Animation (default)
</Text>
<Button animation={true} onPress={() => {}}>
Animated Button
</Button>
</View>
<View>
<Text style={{ marginBottom: 8, fontSize: 14, color: '#71717a' }}>
Without Animation
</Text>
<Button animation={false} onPress={() => {}}>
Static Button
</Button>
</View>
</View>
);
}
API Reference
Button
A pressable button component with multiple variants and states.
Prop | Type | Default | Description |
---|---|---|---|
children | ReactNode | - | The button content (text or custom elements). |
onPress | () => void | - | Function called when the button is pressed. |
variant | ButtonVariant | 'default' | The visual style variant of the button. |
size | ButtonSize | 'default' | The size of the button. |
disabled | boolean | false | Whether the button is disabled. |
loading | boolean | false | Whether the button is in loading state. |
loadingVariant | SpinnerVariant | 'default' | The variant of the loading spinner. |
animation | boolean | true | Whether to enable press animations. |
icon | ComponentType<LucideProps> | - | Icon component to display before the text. |
style | ViewStyle | ViewStyle[] | - | Additional styles for the button container. |
textStyle | TextStyle | - | Additional styles for the button text. |
ButtonVariant
The available button variants:
'default'
- Primary button with solid background'destructive'
- Red button for destructive actions'success'
- Green button for success actions'outline'
- Button with border and transparent background'secondary'
- Secondary button with muted colors'ghost'
- Button with no background'link'
- Text-only button with underline
ButtonSize
The available button sizes:
'default'
- Standard button size (48px height)'sm'
- Small button size (44px height)'lg'
- Large button size (54px height)'icon'
- Square button for icons only (48x48px)
Animations
The Button component features a liquid glass animation effect by default:
- Press Animation: Scales up to 1.04x with a bouncy spring animation
- Brightness Effect: Subtle brightness increase for a glass-like effect
- Smooth Transitions: Uses
react-native-reanimated
for 60fps animations - Customizable: Can be disabled by setting
animation={false}
Accessibility
The Button component is built with accessibility in mind:
- Proper touch target size (minimum 44px)
- Disabled state prevents interaction and reduces opacity
- Loading state shows spinner with appropriate color contrast
- Supports screen readers with proper accessibility labels
- Responsive to system accessibility settings
Best Practices
- Use
'default'
variant for primary actions - Use
'outline'
or'secondary'
for secondary actions - Use
'destructive'
for delete or dangerous actions - Use
'ghost'
for subtle actions or in dense layouts - Always provide meaningful
onPress
handlers - Use loading states for async operations
- Ensure sufficient color contrast for text and backgrounds