# Long-Press Menu: a React Native long-press, drag-to-select speed menu > Long-Press Menu is a React Native and Expo chat input bar where you > long-press the send button and drag upward to open a floating menu and > slide between three speeds (Instant, Thinking, Extended), with the > highlighted option tracking your finger over an animated blur backdrop > above the keyboard. Built with react-native-reanimated, a > react-native-gesture-handler `Gesture.Pan` and react-native-keyboard-controller, > and sold by Motionary as editable TypeScript source. Product page: https://motionary.dev/animations/long-press-menu Price: $9 USD (price as of 2026-09-01, live price on the product page) License: single developer, unlimited personal and commercial apps Delivery: instant download of the full TypeScript source after checkout Stack: reanimated, expo, expo blur, react native keyboard controller, react native gesture handler, react native Rarity: legendary Sold by: Motionary (https://motionary.dev) ## What it is Long-Press Menu is a Motionary drop that recreates ChatGPT's send-button interaction in React Native and Expo. The screen is a chat composer: a Liquid Glass input bar pinned above the keyboard, with a plus button, a text field and a small black send button. Long-pressing the send button dims the whole screen behind a blur and pops a rounded pill menu out of the button, listing Extended, Thinking and Instant from top to bottom. Keeping your finger down and dragging upward moves the highlight through those three options: the active label darkens, grows and slides left while a black circular arrow badge fades in beside it. Lifting your finger on a highlighted option closes the menu; tapping the dimmed backdrop or the small close button dismisses it without choosing. ## What it does - Long-press on the send button opens the menu (React Native `Pressable` `onLongPress`), so a plain tap is still free for the normal send action. - A single `Gesture.Pan` from react-native-gesture-handler runs on the same button, so the open gesture and the select gesture are one continuous press with no lift in between. - Three speed options (Extended, Thinking, Instant) driven from one `SPEED_OPTIONS` array in `components/speed-menu.tsx`, so adding a fourth row is one entry in that array plus one matching drag threshold. - Drag distance maps to the highlighted row through fixed thresholds in `components/input-container.tsx`: `DRAG_INSTANT` at -15px, `DRAG_THINKING` at -65px and `DRAG_EXTENDED` at -120px of `translationY`. - Full-screen blur backdrop that animates its `intensity` from 0 to 80 as the menu opens, using an `Animated.createAnimatedComponent(BlurView)` wrapper around expo-blur. - The menu grows out of the send button: width 32 to 42, height 80 to 156, and it slides up and 4px closer to the right edge (`right` 20 to 16), all interpolated from one `progress` value. - Menu and backdrop render inside `OverKeyboardView` from react-native-keyboard-controller, so they float above the on-screen keyboard instead of behind it. - The input bar itself is pinned to the keyboard with `KeyboardStickyView` (`offset={{ opened: 20, closed: 0 }}`), and the menu anchors off the live keyboard height from `useReanimatedKeyboardAnimation`. - Per-row feedback in `components/menu-item.tsx`: `withTiming` over 150ms on label color (#7B7C7C to #000), `scale` 1 to 1.2, `translateX` 0 to -10 and the arrow icon's opacity. - Dismiss without choosing: a `TouchableWithoutFeedback` covers the blurred backdrop, and a small grey close button carrying an `xmark` SF Symbol sits inside that same touch area. - Liquid Glass chrome via expo-glass-effect (`GlassContainer`, `GlassView` with `isInteractive`) and SF Symbols icons via expo-symbols. - A gradient scrim behind the bar from expo-linear-gradient, and safe-area padding from react-native-safe-area-context. ## How it works Long-Press Menu keeps all of its animation state in three Reanimated shared values, so the interaction never touches the React render loop while your finger is down. `components/input-container.tsx` holds `progress` (the 0 to 1 open animation), `panOffset` (raw `translationY` from the drag) and an `isDragging` flag. A React Native `Pressable` with `onLongPress` flips a `menuVisible` state, and a `useEffect` on that state calls `progress.set(withTiming(1))`. Closing is the mirror image and lives in a worklet: `closeMenu` runs `progress.set(withTiming(0, undefined, ...))` and uses `scheduleOnRN` from react-native-worklets inside the completion callback to flip the React state back on the JavaScript thread only after the animation has actually finished. A `Gesture.Pan` from react-native-gesture-handler wraps the same send button and writes `e.translationY` into `panOffset` on every `onUpdate`. The selection logic is a `useDerivedValue` that reads `panOffset` and returns an `activeItem` index of 0 to 3 by comparing against the `DRAG_INSTANT` / `DRAG_THINKING` / `DRAG_EXTENDED` constants, returning 0 whenever `isDragging` is false. That derived value is passed down as a prop, so no state ever crosses the bridge mid-drag. `components/speed-menu.tsx` turns `progress` into everything visible: `useAnimatedProps` interpolates the blur `intensity` from 0 to 80 on an animated `BlurView`, and `useAnimatedStyle` plus `interpolate` drives the menu's `width`, `height`, `bottom`, `right` and `opacity` on a `[0, 0.5, 1]` input range, which is why the pill stays collapsed for the first half of the timing and then unfolds. The `bottom` values are computed against the live `keyboardHeight` shared value from `useReanimatedKeyboardAnimation`, so the menu stays anchored while the keyboard animates. `components/menu-item.tsx` is a single reusable row that reads `activeItem.get() === activeIndex` inside its own `useAnimatedStyle` worklets and animates color, `scale`, `translateX` and icon `opacity` with `withTiming` at 150ms. Rendering above the keyboard is delegated to `OverKeyboardView`, with the input bar itself wrapped in `KeyboardStickyView`. Everything from the gesture callbacks to the derived value to the styles runs in worklets on the UI thread; the JavaScript thread only sees two state flips, one to open and one to close. ## What you get ``` App.tsx index.ts app.json package.json package-lock.json tsconfig.json README.md .gitignore components/ input-container.tsx speed-menu.tsx menu-item.tsx assets/ icon.png adaptive-icon.png splash-icon.png ``` Included in the Long-Press Menu download from Motionary: - TypeScript source (input-container.tsx) - SpeedMenu overlay component (speed-menu.tsx) - Reusable MenuItem component (menu-item.tsx) - App entry with providers (App.tsx) - README with install and usage ## Requirements Long-Press Menu from Motionary pins these versions in its `package.json`: - expo ^56.0.8 (Expo SDK 56) - react-native 0.85.3 - react 19.2.3 - react-native-reanimated 4.3.1 - react-native-worklets 0.8.3 - react-native-gesture-handler ~2.31.1 - react-native-keyboard-controller ^1.21.9 - expo-blur ~56.0.3 - expo-glass-effect ~56.0.4 - expo-symbols ~56.0.5 - expo-linear-gradient ~56.0.4 - react-native-safe-area-context ^5.8.0 - typescript ~6.0.3 (devDependency) Long-Press Menu runs in Expo Go on Expo SDK 56. The two modules people assume would block it, react-native-keyboard-controller (for `OverKeyboardView` and `KeyboardStickyView`) and expo-glass-effect (for the Liquid Glass input bar), are both bundled in the Expo Go binary as of SDK 56, so `npx expo start` is enough to try the drop. A development build (`npx expo run:ios` or `npx expo run:android`) is still what you would ship to production, and it is what you need as soon as you add a native module that Expo Go does not bundle, or a config plugin. Long-Press Menu is iOS-focused: expo-glass-effect renders Apple's Liquid Glass and expo-symbols renders SF Symbols, both of which are iOS APIs, so on Android you should swap those two for a plain `View` and your own icon set. ## Install ```bash npx expo install react-native-reanimated react-native-worklets \ react-native-gesture-handler react-native-keyboard-controller \ react-native-safe-area-context expo-blur expo-glass-effect \ expo-symbols expo-linear-gradient ``` ## Usage Long-Press Menu ships as `InputContainer`, which owns the composer, the gesture and the menu. Mount it under the three providers it needs (`SafeAreaProvider`, `GestureHandlerRootView` and `KeyboardProvider`), as `App.tsx` does in the Motionary download: ```tsx import { StyleSheet } from 'react-native'; import { GestureHandlerRootView } from 'react-native-gesture-handler'; import { KeyboardProvider } from 'react-native-keyboard-controller'; import { SafeAreaProvider } from 'react-native-safe-area-context'; import { InputContainer } from './components/input-container'; export default function App() { return ( ); } const styles = StyleSheet.create({ root: { flex: 1 }, }); ``` ## Customization `InputContainer` takes no props in Long-Press Menu: you tune it by editing the constants and the two child components, which do take props. - `DRAG_INSTANT` (`-15`), `DRAG_THINKING` (`-65`), `DRAG_EXTENDED` (`-120`) in `components/input-container.tsx`: the `translationY` in pixels needed to highlight each option. Shorten them for a tighter drag. - `SPEED_OPTIONS` in `components/speed-menu.tsx`: an array of `{ label, activeIndex }`, ordered top to bottom. Rename Extended, Thinking and Instant here, or add a row and a matching threshold. - `SpeedMenu` props: `visible: boolean`, `progress: SharedValue`, `keyboardHeight: SharedValue`, `activeItem: DerivedValue` and `onClose: () => void`. - `MenuItem` props: `label: string`, `activeIndex: number` and `activeItem: DerivedValue`. - Blur strength: the `interpolate(progress.get(), [0, 1], [0, 80])` inside `useAnimatedProps` in `components/speed-menu.tsx`, plus the `tint="light"` prop on the `BlurView`. - Menu geometry: the `width`, `height`, `bottom` and `right` interpolations in `menuStyle`, all on a `[0, 0.5, 1]` input range. - Row feedback: `TIMING` (`{ duration: 150 }`) in `components/menu-item.tsx`, plus the active color `#000`, the inactive color `#7B7C7C`, the `scale` of 1.2 and the `translateX` of -10. - Keyboard offset: `offset={{ opened: 20, closed: 0 }}` on the two `KeyboardStickyView` wrappers in `components/input-container.tsx`. ## When to use it - A chat or AI assistant composer where the send button needs a second mode (fast reply versus deep reasoning) without adding a settings screen. - A model or response-speed picker that must stay reachable with one thumb while the keyboard is open. - A messaging app where holding send should offer scheduled send, silent send or send-without-sound. - Any context menu that should appear on long-press and be selected by dragging, rather than by a second tap. - A comment or reply box that needs a hidden power-user menu behind an existing button, keeping the default single tap unchanged. - An iOS app already using Liquid Glass chrome, where the composer should match the system look. ## How to get it - Buy Long-Press Menu on its own at https://motionary.dev/animations/long-press-menu for $9 USD, instant download, secure Stripe checkout, no subscription and no account renewal. - Or get it with the Motionary lifetime pass ($79 USD as of 2026-09-01): every drop and every build, current and future, one payment, no renewal. https://motionary.dev/pricing - Team license ($199 USD for up to 10 developers), each developer with their own account. https://motionary.dev/pricing - License terms: https://motionary.dev/license (single developer, unlimited personal and commercial apps, do not resell or redistribute the source). - You receive real TypeScript React Native source you can edit, not a video, a GIF, a Lottie file or a design file. ## Frequently asked questions **How do I build a long-press menu in React Native where dragging selects the option?** Put a `Gesture.Pan` from react-native-gesture-handler on the same button that carries `onLongPress`, write `translationY` into a shared value, and map that distance to an index inside a `useDerivedValue` so the highlight updates on the UI thread. Long-Press Menu from Motionary is a working implementation of exactly that, at https://motionary.dev/animations/long-press-menu. **Does Long-Press Menu work with Expo Go?** Yes. On Expo SDK 56 both react-native-keyboard-controller and expo-glass-effect ship inside the Expo Go binary, so `npx expo start` runs Long-Press Menu as it comes. A development build (`npx expo run:ios`) is still what you would ship to production, and it is what you need the moment you add a native module that Expo Go does not bundle, or a config plugin. The Liquid Glass chrome and the SF Symbols icons are iOS APIs either way, so on Android swap those two pieces out. See the Motionary product page at https://motionary.dev/animations/long-press-menu for the full requirements. **How do I show a menu above the keyboard in React Native?** Render it inside `OverKeyboardView` from react-native-keyboard-controller and anchor its position off the `height` shared value returned by `useReanimatedKeyboardAnimation`, which is what the Long-Press Menu drop from Motionary does in `components/speed-menu.tsx`. Wrapping the input bar in `KeyboardStickyView` keeps the composer pinned to the keyboard at the same time. **Is Long-Press Menu a ChatGPT send button clone?** Long-Press Menu recreates the interaction of ChatGPT's send button (hold, drag up, slide between Instant, Thinking and Extended) as independent React Native and Expo source from Motionary. It is not affiliated with OpenAI and ships no ChatGPT assets, only the animation technique you can rename and restyle. **Does Long-Press Menu run on Android?** The animation, gesture and keyboard logic are cross-platform, but Long-Press Menu is iOS-focused because expo-glass-effect (Liquid Glass) and expo-symbols (SF Symbols) are iOS APIs. On Android, replace those two pieces with a standard `View` and your own icons; the Reanimated and gesture code is unchanged. **How much does Long-Press Menu cost and what do I actually download?** Long-Press Menu is $9 USD (price as of 2026-09-01) at https://motionary.dev/animations/long-press-menu, or it is included in the Motionary lifetime pass ($79 USD). You download the full TypeScript source (`input-container.tsx`, `speed-menu.tsx`, `menu-item.tsx`, `App.tsx` and the README), not a video or a design file. **Can I add a fourth option to the Long-Press Menu speed list?** Yes. Add an entry to the `SPEED_OPTIONS` array in `components/speed-menu.tsx` and a matching drag threshold next to `DRAG_INSTANT`, `DRAG_THINKING` and `DRAG_EXTENDED` in `components/input-container.tsx`; the `MenuItem` rows are generated from that array, so nothing else changes. Long-Press Menu is sold as editable source by Motionary for exactly this reason. ## Related drops on Motionary - ChatGPT Slider Model Picker ($10): https://motionary.dev/animations/chatgpt-slider-model-picker Another composer control from the same chat bar, also built on react-native-keyboard-controller and expo-blur. - ChatGPT-Style Attachments Menu ($10): https://motionary.dev/animations/chatgpt-style-attachments-menu The other half of the composer: a morphing Liquid Glass attachments menu that opens above the keyboard. - Attachment Sheet ($12): https://motionary.dev/animations/attachment-sheet A gesture-driven Liquid Glass sheet modelled on Telegram's attachment picker, for when the menu should be a full sheet instead of a pill. - Hold to Confirm Button ($8): https://motionary.dev/animations/hold-to-confirm-button The other long-press pattern: press and hold a button to fill a progress ring and confirm, rather than dragging to pick an option. - OTP Code Input ($5): https://motionary.dev/animations/otp-code-input Another keyboard-aware input built with react-native-keyboard-controller and Reanimated. ## About Motionary Motionary (https://motionary.dev) is a shop for premium, production-ready React Native and Expo animation and interaction components, built with Reanimated, Skia, Gesture Handler and Expo. Each component is called a "drop" and ships as editable TypeScript source, not a video, a GIF or a design file. Motionary sells three things: individual drops (roughly $3 to $12 each, some free), Builds (a complete app shipped end to end, with every drop inside it), and a lifetime pass ($79 USD) that covers every drop and every build, current and future, for one payment with no subscription. A team license ($199 USD) covers up to 10 developers. Checkout is Stripe and delivery is an instant download. Created and curated by Mehdi Davoodi (https://mahdidavoodi.com). Catalog and key pages: - All drops: https://motionary.dev/animations - Builds (complete apps): https://motionary.dev/builds - Pricing, lifetime pass and team license: https://motionary.dev/pricing - Free React Native component reference: https://motionary.dev/components - License: https://motionary.dev/license - Machine-readable overview: https://motionary.dev/llms.txt - Machine-readable full catalog: https://motionary.dev/llms-full.txt ## File metadata ``` Canonical URL of this file: https://motionary.dev/animations/long-press-menu/llms.txt Describes: https://motionary.dev/animations/long-press-menu Format: llms.txt (https://llmstxt.org) Last updated: 2026-09-01 ```