RightIslandMenu
A sleek, gesture-driven sliding menu component that emerges from the right edge of the screen. Inspired by iOS Dynamic Island aesthetics, it features smooth spring animations, intuitive drag gestures, and optional haptic feedback.
- Gesture-based interaction – Drag from the edge or tap to toggle
- Spring animations – Smooth, physics-based transitions using Reanimated
- Animated arrow indicator – Visual feedback that morphs based on menu state
- Haptic feedback – Optional tactile response on interactions
- Click-outside dismissal – Automatically closes when tapping outside
- Customizable appearance – Colors, dimensions, and styling options
- Dynamic height calculation – Auto-sizes based on number of options
Installation
This component requires the following dependencies:
bash
npx expo install react-native-reanimated react-native-gesture-handler expo-haptics react-native-svg @expo/vector-iconsUsage
tsx
import RightIslandMenu from "@/app/right-menu";
import { Alert } from "react-native";
export default function MyScreen() {
const handleOptionPress = (option) => {
Alert.alert(option.label, `Selected: ${option.id}`);
};
return (
<View style={{ flex: 1 }}>
<RightIslandMenu
options={[
{ id: "1", icon: "calculator-outline", label: "Calculator" },
{ id: "2", icon: "settings-outline", label: "Settings" },
{ id: "3", icon: "book-outline", label: "Notes" },
{ id: "4", icon: "calendar-outline", label: "Calendar" },
]}
onOptionPress={handleOptionPress}
width={140}
enableHaptics={true}
/>
</View>
);
}Props
| Prop | Type | Default | Description |
|---|---|---|---|
options | RightMenuOption[] | required | Array of menu options to display |
onOptionPress | (option: RightMenuOption) => void | undefined | Callback when an option is pressed |
width | number | 100 | Width of the expanded menu panel |
minHeight | number | undefined | Minimum height constraint for the menu |
maxHeight | number | undefined | Maximum height constraint for the menu |
indicatorWidth | number | 25 | Width of the drag indicator/handle |
indicatorHeight | number | 100 | Height of the drag indicator/handle |
backgroundColor | string | 'black' | Background color of the menu panel |
indicatorColor | string | 'black' | Background color of the drag indicator |
textColor | string | '#B3AFAF' | Color of option labels |
iconColor | string | '#B3AFAF' | Color of option icons |
enableHaptics | boolean | true | Enable haptic feedback on interactions |
Types
typescript
interface RightMenuOption {
id: string;
icon: keyof typeof Ionicons.glyphMap; // Any valid Ionicons name
label: string;
}Interaction Modes
Drag Gesture
Swipe left from the indicator to expand the menu. The menu follows your finger and snaps to open or closed based on:
- Velocity – Fast flicks snap to the nearest edge
- Position – Slow drags snap based on distance traveled
Tap Gesture
Tap the indicator arrow to toggle the menu open/closed.
Click Outside
Tapping anywhere outside the menu when it's open will dismiss it.
Customization Examples
Minimal Dark Theme
tsx
<RightIslandMenu
options={options}
onOptionPress={handlePress}
width={120}
backgroundColor="#1a1a1a"
indicatorColor="#1a1a1a"
textColor="#ffffff"
iconColor="#ffffff"
/>Light Theme with Larger Indicator
tsx
<RightIslandMenu
options={options}
onOptionPress={handlePress}
width={160}
indicatorWidth={30}
indicatorHeight={120}
backgroundColor="#f5f5f5"
indicatorColor="#e0e0e0"
textColor="#333333"
iconColor="#666666"
/>Constrained Height with Scroll
tsx
<RightIslandMenu
options={manyOptions}
onOptionPress={handlePress}
maxHeight={400}
width={140}
/>Animation Details
The component uses carefully tuned spring animations:
typescript
const SPRING_CONFIG = {
damping: 25,
stiffness: 300,
mass: 0.9,
overshootClamping: false,
restDisplacementThreshold: 0.01,
restSpeedThreshold: 0.01,
};This configuration provides a snappy yet smooth feel with minimal overshoot.
Notes
- The menu is positioned absolutely at
top: 50%andright: 0, centered vertically on the right edge - Icons use
@expo/vector-iconsIonicons – any valid Ionicons name works - The arrow indicator animates between pointing left (closed) and right (open)
- Menu height is calculated automatically based on the number of options (84px per option + padding)