Back to Components

Sticky Right Menu

Menu
about 2 months ago

About

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-icons

Usage

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

PropTypeDefaultDescription
optionsRightMenuOption[]requiredArray of menu options to display
onOptionPress(option: RightMenuOption) => voidundefinedCallback when an option is pressed
widthnumber100Width of the expanded menu panel
minHeightnumberundefinedMinimum height constraint for the menu
maxHeightnumberundefinedMaximum height constraint for the menu
indicatorWidthnumber25Width of the drag indicator/handle
indicatorHeightnumber100Height of the drag indicator/handle
backgroundColorstring'black'Background color of the menu panel
indicatorColorstring'black'Background color of the drag indicator
textColorstring'#B3AFAF'Color of option labels
iconColorstring'#B3AFAF'Color of option icons
enableHapticsbooleantrueEnable 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% and right: 0, centered vertically on the right edge
  • Icons use @expo/vector-icons Ionicons – 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)

Posted by

E

eren

@eren