A modern React Native floating bottom menu component with smooth animations, haptic feedback, blur overlay, and theme support. Features an expandable interface that transforms from a compact chat button to a full menu with customizable items.
- 🎭 Smooth Animations: Built with React Native Reanimated for 60fps performance
- 📱 Responsive Design: Automatically centers and adapts to screen width
- 🌙 Dark/Light Theme: Full support for theme switching with adaptive colors
- 📳 Haptic Feedback: Native vibration feedback on menu expansion
- 🌫️ Blur Overlay: Glass effect background when menu is expanded
- 🎯 Touch-to-Close: Tap anywhere on blur overlay to close menu
- 📜 Scrollable Content: Smooth scrolling menu items with custom icons
- 🎨 Custom Fonts: Instrument Serif font integration for elegant typography
- 🔧 StyleSheet Organized: Clean, maintainable code structure
- ⚡ Performance Optimized: Efficient animations with reduced bounce
| Platform | Status | Notes |
|---|---|---|
| iOS | ✅ Full Support | Native haptic feedback, smooth animations |
| Android | ✅ Full Support | Haptic feedback, native performance |
| Web | ✅ Full Support | Blur effects, responsive design |
| Dependency | Version | Required |
|---|---|---|
| Expo SDK | 53.0.0+ | ✅ |
| React Native | 0.79+ | ✅ |
| React Native Reanimated | 3.17+ | ✅ |
| Expo Blur | Latest | ✅ |
| Expo Haptics | Latest | ✅ |
| Expo Font | Latest | ✅ |
| TypeScript | 5.8+ | ✅ |
# Install core dependencies
npm install react-native-reanimated
# Install Expo modules
npx expo install expo-blur expo-haptics expo-font
# Install custom fonts (if using Instrument Serif)
npm install @expo-google-fonts/instrument-serifassets/
└── fonts/
├── InstrumentSerif-Regular.ttf
└── InstrumentSerif-Italic.ttf
// App.tsx
import { useState } from 'react';
import BottomMenuExpandable from './components/BottomMenuExpandable';
export default function App() {
const [isDarkTheme, setIsDarkTheme] = useState(false);
return (
<SafeAreaView style={{ flex: 1 }}>
{/* Your app content */}
{/* Floating bottom menu */}
<BottomMenuExpandable isDarkTheme={isDarkTheme} />
</SafeAreaView>
);
}import BottomMenuExpandable from './components/BottomMenuExpandable';
export default function App() {
const [isDarkTheme, setIsDarkTheme] = useState(false);
return (
<SafeAreaView style={{ flex: 1, backgroundColor: isDarkTheme ? '#000' : '#fff' }}>
{/* Your content here */}
<BottomMenuExpandable isDarkTheme={isDarkTheme} />
</SafeAreaView>
);
}import AnimationSwitchTheme from './components/AnimationSwitchTheme';
import BottomMenuExpandable from './components/BottomMenuExpandable';
export default function App() {
const [isDarkTheme, setIsDarkTheme] = useState(false);
const handleThemeChange = (isDark: boolean) => {
setIsDarkTheme(isDark);
};
return (
<SafeAreaView style={{ flex: 1 }}>
{/* Header with theme toggle */}
<View style={{ padding: 20 }}>
<AnimationSwitchTheme onThemeChange={handleThemeChange} />
</View>
{/* Floating menu */}
<BottomMenuExpandable isDarkTheme={isDarkTheme} />
</SafeAreaView>
);
}| Prop | Type | Default | Description |
|---|---|---|---|
isDarkTheme |
boolean |
false |
Controls dark/light theme appearance |
const menuItems = [
{ id: 1, icon: 'chatbubble-outline', text: 'Chat', color: '#AFFF00' },
{ id: 2, icon: 'search-outline', text: 'Search', color: '#FF9500' },
{ id: 3, icon: 'heart-outline', text: 'Favorites', color: '#FF3B30' },
// Add more items...
];const themeColors = {
menuBg: isDarkTheme ? '#1C1C1E' : '#FFFFFF',
textColor: isDarkTheme ? '#FFFFFF' : '#000000',
accentColor: '#AFFF00', // Custom accent color
separator: isDarkTheme ? '#38383A' : '#E5E5E7',
};// Expansion animation with less bounce
menuWidth.value = withSpring(expandedWidth, { damping: 20, stiffness: 150 });
// Haptic feedback intensity
Haptics.impactAsync(Haptics.ImpactFeedbackStyle.Medium);- Chat Icon: Positioned on the left with custom accent color
- Chat Text: "Chat" in Instrument Serif Italic font
- Separator: Vertical line divider
- Plus Button: Expansion trigger on the right
- Header: "Menu Principal" title with close button
- Scrollable Items: 10 customizable menu options
- Blur Overlay: Touch-to-close background
- Smooth Animations: Spring-based transitions
- Haptic Feedback: Immediate vibration on tap
- Size Animation: Width/height expansion with spring
- Blur Fade-in: Background overlay appears
- Chat Fade-out: Logo and text disappear
- Content Reveal: Menu items slide in with stagger
- Reduced Bounce:
damping: 20for stable animations - Efficient Springs: Optimized stiffness values
- StyleSheet: Organized styles for better performance
- Font Loading: Conditional rendering until fonts load
- Background:
#1C1C1E - Text:
#FFFFFF - Secondary:
#8E8E93 - Border:
#38383A
- Background:
#FFFFFF - Text:
#000000 - Secondary:
#6D6D70 - Border:
#E5E5E7
- Menu Expansion: Tap plus button to expand
- Menu Closing: Tap X or blur overlay to close
- Item Selection: Tap any menu item (customizable actions)
- Haptic Response: Vibration feedback on expansion
- Touch Targets: Minimum 44px touch areas
- Visual Feedback: Clear hover and press states
- Screen Readers: Proper accessibility labels
// Animated values for smooth transitions
const menuWidth = useSharedValue(140);
const menuHeight = useSharedValue(60);
const blurOpacity = useSharedValue(0);
const chatOpacity = useSharedValue(1);
// StyleSheet organization
const styles = StyleSheet.create({
compactMenu: { /* Compact layout styles */ },
expandedMenu: { /* Expanded layout styles */ },
blurOverlay: { /* Blur effect styles */ },
});const [fontsLoaded] = useFonts({
'InstrumentSerif-Italic': require('../assets/fonts/InstrumentSerif-Italic.ttf'),
});- Verify font files are in
assets/fonts/directory - Check font file names match exactly
- Ensure
expo-fontis properly installed
- Reduce animation complexity
- Check device performance
- Verify Reanimated installation
- Ensure
expo-bluris installed - Check platform compatibility
- Verify overlay positioning
- Test on physical device (not simulator)
- Check
expo-hapticsinstallation - Verify platform permissions
const customMenuItems = [
{
id: 1,
icon: 'custom-icon',
text: 'Custom Action',
color: '#FF6B6B',
onPress: () => {
// Custom action logic
}
},
];// Handle expansion completion
runOnJS(setIsExpanded)(true);
// Custom animation sequences
setTimeout(() => {
// Delayed animations
}, 200);- Native haptic feedback support
- Smooth blur effects
- Spring animations optimized
- Haptic feedback with compatibility layer
- Material Design blur effects
- Optimized for various screen sizes
- CSS-based blur fallbacks
- Mouse interaction support
- Responsive design adaptation
When contributing:
- Test on all platforms (iOS, Android, Web)
- Ensure animations maintain 60fps
- Verify theme switching works correctly
- Test with different screen sizes
- Update StyleSheet organization
- Maintain accessibility standards
This component is part of the expo-auto-resizing-input project.