- Accordion
- Action Sheet
- Alert Dialog
- Alert
- Audio Player
- Audio Recorder
- Audio Waveform
- Avatar
- AvoidKeyboard
- Badge
- BottomSheet
- Button
- Camera Preview
- Camera
- Card
- Carousel
- Checkbox
- Collapsible
- Color Picker
- Combobox
- Date Picker
- File Picker
- Gallery
- Hello Wave
- Icon
- Image
- Input OTP
- Input
- 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
Installation
pnpm dlx bna-ui add mode-toggle
Usage
import { ModeToggle } from '@/components/ui/mode-toggle';<ModeToggle />Examples
Default
API Reference
ModeToggle
An animated button that toggles between light and dark themes. The component uses the Button component internally, so it inherits button styling and behavior.
| Prop | Type | Default | Description |
|---|---|---|---|
haptic | boolean | true | Whether to trigger haptic feedback on press. Forwarded to the underlying Button. |
variant | ButtonVariant | 'outline' | The visual variant passed through to the underlying Button. |
size | ButtonSize | 'icon' | The size passed through to the underlying Button. |
Animation Details
Icon Transition
- Scale Animation: Icons scale down to 0, change, then scale back to 1
- Duration: 150ms for each scale phase (300ms total)
- Icons: Sun for light mode, Moon for dark mode
Sun Rotation
- Rotation: 180° rotation when switching to light mode
- Duration: 300ms
- Effect: Creates a spinning sun rays effect
- Timing: Only rotates when switching to sun icon
Theme Integration
The component is a thin shell over the
useModeToggle hook — it takes isDark to pick
the icon and toggleMode for the press handler, and owns nothing else:
const { toggleMode, isDark } = useModeToggle();That hook reads the mode from ModeProvider, so a provider
has to be mounted above the toggle or it throws. Wrapping your app in
ThemeProvider is enough — it mounts one — and
every scaffold from npx bna-ui init already does.
Performance
The component is optimized for smooth animations:
- Uses
react-native-reanimatedfor 60fps animations - Animations run on the UI thread
- Minimal re-renders with
useSharedValue - Efficient icon switching with
runOnJS
Accessibility
The ModeToggle maintains accessibility:
- Uses semantic button component
- Screen readers announce theme changes
- Maintains proper focus behavior
- Works with keyboard navigation
- Respects system accessibility settings
Integration Example
// app/_layout.tsx
import { ModeToggle } from '@/components/ui/mode-toggle';
import { ThemeProvider } from '@/providers/theme-provider';
export default function RootLayout() {
return (
<ThemeProvider>
<View style={styles.header}>
<Text>My App</Text>
<ModeToggle />
</View>
{/* Rest of your app */}
</ThemeProvider>
);
}Add storage={SecureStore} to ThemeProvider to have the choice survive a
restart — see ModeProvider.
Dependencies
The component requires these utilities to function:
useModeToggle: Hook for theme switching logicButton: Base button componentIcon: Themed icon wrapperModeProvider: Holds the mode, mounted for you byThemeProvider