BlurMenu Component
A beautifully animated, blur-background menu component for React Native with Expo. Features smooth spring animations, customizable positioning, and a sophisticated modal management system.
Features
- ✨ Smooth Animations: Spring-based animations with staggered menu item entrances
- 🎯 Flexible Positioning: Support for 9 different FAB positions (top, bottom, center, left, right combinations)
- 🌊 Blur Background: Elegant blur effect using Expo's BlurView
- 🎭 Modal Management: Global modal manager ensures only one menu is active at a time
- 🎨 Customizable: Support for custom icons, titles, and styling
- 📱 Safe Area Aware: Automatically handles device safe areas
- 🎪 Custom Triggers: Use your own component as the menu trigger
Dependencies
This component requires the following packages:
npm install expo-blur react-native-reanimated react-native-safe-area-context @expo/vector-icons
Basic Usage
import BlurMenu, { MenuItem } from '@/components/BlurMenu';
import { useState } from 'react';
const menuItems: MenuItem[] = [
{
id: 'profile',
icon: 'person-outline',
title: 'Profile',
onPress: () => console.log('Profile pressed')
},
{
id: 'settings',
icon: 'settings-outline',
title: 'Settings',
onPress: () => console.log('Settings pressed')
},
{
id: 'logout',
icon: 'log-out-outline',
title: 'Logout',
onPress: () => console.log('Logout pressed')
}
];
export default function MyScreen() {
const [menuVisible, setMenuVisible] = useState(false);
return (
<BlurMenu
visible={menuVisible}
onToggle={() => setMenuVisible(!menuVisible)}
menuItems={menuItems}
title="Main Menu"
fabPosition="bottom-right"
/>
);
}
Props
Prop | Type | Default | Description |
---|---|---|---|
visible | boolean | - | Required. Controls menu visibility |
onToggle | () => void | - | Required. Callback when menu should toggle |
menuItems | MenuItem[] | - | Required. Array of menu items |
position | MenuPosition | 'center' | Menu content alignment ('left' | 'right' | 'center' ) |
title | string | 'Menu' | Menu title displayed at the top |
fabPosition | FabPosition | 'bottom-center' | FAB trigger position |
children | React.ReactNode | - | Custom trigger component (replaces default FAB) |
className | string | - | Additional CSS class for custom trigger |
MenuItem Interface
interface MenuItem {
id?: string; // Optional unique identifier
icon?: React.ComponentType<any> // Icon component, React node, or Ionicons name
| React.ReactNode
| string;
title: string; // Menu item label
onPress?: () => void; // Callback when item is pressed
}
Position Types
type MenuPosition = 'left' | 'right' | 'center';
type FabPosition =
| 'top-left' | 'top-right' | 'top-center'
| 'bottom-left' | 'bottom-right' | 'bottom-center'
| 'left' | 'right' | 'center';
Advanced Usage Examples
Custom Trigger Component
<BlurMenu
visible={menuVisible}
onToggle={() => setMenuVisible(!menuVisible)}
menuItems={menuItems}
title="Actions"
>
<View style={styles.customTrigger}>
<Ionicons name="ellipsis-horizontal" size={24} color="white" />
</View>
</BlurMenu>
Different FAB Positions
// Top-right corner menu
<BlurMenu
visible={menuVisible}
onToggle={() => setMenuVisible(!menuVisible)}
menuItems={menuItems}
fabPosition="top-right"
title="Quick Actions"
/>
// Left-side menu
<BlurMenu
visible={menuVisible}
onToggle={() => setMenuVisible(!menuVisible)}
menuItems={menuItems}
fabPosition="left"
position="left"
title="Navigation"
/>
Custom Icons
const menuItems: MenuItem[] = [
{
icon: <MyCustomIcon size={20} color="white" />,
title: 'Custom Action',
onPress: () => handleCustomAction()
},
{
icon: () => <AnotherIcon />,
title: 'Function Icon',
onPress: () => handleAnotherAction()
}
];
Menu with Context Actions
const contextMenuItems: MenuItem[] = [
{
icon: 'copy-outline',
title: 'Copy',
onPress: () => handleCopy()
},
{
icon: 'share-outline',
title: 'Share',
onPress: () => handleShare()
},
{
icon: 'trash-outline',
title: 'Delete',
onPress: () => handleDelete()
}
];
// Triggered by long press on an item
<BlurMenu
visible={contextMenuVisible}
onToggle={() => setContextMenuVisible(!contextMenuVisible)}
menuItems={contextMenuItems}
title="Actions"
fabPosition="center"
/>
Animation Details
The component features sophisticated animations:
- Spring Animations: Uses
react-native-reanimated
with optimized spring configurations - Staggered Entrance: Menu items appear with a 50ms delay between each item
- Direction-Aware: Animation direction depends on FAB position
- Smooth Transitions: 200-300ms timing for opacity and blur effects
Modal Management
The component includes a global modal manager that:
- Ensures only one BlurMenu is active at a time
- Automatically closes other menus when a new one opens
- Handles proper cleanup when components unmount
- Prevents modal conflicts in complex navigation scenarios
Styling Notes
- Menu uses a dark blur background with white text
- Menu items have subtle bottom borders with transparency
- FAB has a subtle shadow for depth
- All animations respect device safe areas
- Responsive design adapts to different screen sizes
Best Practices
- Menu Items: Keep menu items concise (5-7 items maximum)
- Icons: Use consistent icon styling across menu items
- Position: Choose FAB position based on your app's navigation patterns
- Performance: Menu items are optimized with proper key props
- Accessibility: Consider adding accessibility labels for better UX
Troubleshooting
Menu not appearing: Ensure expo-blur
is properly installed and linked.
Animations stuttering: Check that react-native-reanimated
is configured correctly in your project.
Multiple menus conflict: The modal manager should handle this automatically, but ensure each BlurMenu has unique menu items.
License
This component is part of the landing-rn-components library.