# ChatGPT-Style Attachments Menu: React Native morphing chat attachments menu > ChatGPT-Style Attachments Menu is a React Native and Expo component in which > a chat input bar's plus button morphs into a floating Liquid Glass > attachments panel that extends full screen into a recycled photo grid or a > live camera, driven by two react-native-reanimated spring values whose > geometry is one continuous blend of the closed, open and extended states. > It is sold by Motionary as editable TypeScript source. Product page: https://motionary.dev/animations/chatgpt-style-attachments-menu Price: $10 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: expo, react native, react native keyboard controller, reanimated Rarity: legendary Sold by: Motionary (https://motionary.dev) ## What it is ChatGPT-Style Attachments Menu is a React Native and Expo attachments flow for a chat composer, modelled on the plus button in ChatGPT's iOS input bar. Tap the plus and the 46 by 46 pill grows upward and outward into a 270 by 280 Liquid Glass panel holding four options (Camera, Photos, Files, Plugins), with the plus icon fading out as the panel's glass material fades in. Tap Photos or Camera and the same panel keeps growing until it fills the screen width, becoming a three column scrolling photo grid or a live camera preview with a shutter button. Tapping outside the panel, on a full screen transparent backdrop, collapses it straight back down into the plus in one continuous motion, with no intermediate step back through the menu items and no snap. This drop is sold by Motionary. ## What it does - Morphs a chat input bar's plus button into a floating attachments panel and back, as a single continuous animation rather than two separate transitions. - Blends three key geometry states (closed, open, extended) so the panel can collapse directly from the full screen camera or photo view to the plus. - Extends into two surfaces: a recycled three column photo grid rendered with `@legendapp/list`, and a live `expo-camera` preview with a shutter control. - Renders the panel on iOS Liquid Glass via `expo-glass-effect`, with `glassEffectStyle` and `tintColor` animated in as the menu opens, and the extended surface's back and All Photos controls on static `regular` glass. - Anchors above the software keyboard: the overlay lives in `OverKeyboardView` and its bottom, left and height all read live keyboard height from `useReanimatedKeyboardAnimation`. - Keeps the input bar itself glued to the keyboard with `KeyboardStickyView`, and tightens the bar's horizontal padding from 32 to 12 as the keyboard rises. - Mounts the extended surface lazily, so the 20 grid images are not fetched until you actually extend and the menu items stay tappable before that. - Handles interrupted animations: re-pressing the plus during the closing spring's settle tail reopens the menu instead of being a dead press, because the overlay only unmounts when the spring reports `finished`. - Requests camera permission on demand with `useCameraPermissions` when you choose the Camera option. - Four menu items rendered with SF Symbols through `expo-symbols` (`camera`, `photo`, `paperclip`, `puzzlepiece.extension`). - Ships an in-code note on three iOS Liquid Glass quirks it works around: glass views do not nest, animating opacity on a glass ancestor suppresses the material, and SwiftUI backed buttons do not render inside `OverKeyboardView`. ## How it works ChatGPT-Style Attachments Menu runs the whole morph off two react-native-reanimated shared values held in `components/input-container.tsx`: `progress` (0 to 1) opens the plus into the menu, and `extendProgress` (0 to 1) grows that menu into the full screen surface. Both are set with `withSpring` (duration 450); there is no pan gesture, presses simply set the targets, so every frame is computed on the UI thread with no bridge traffic. Instead of branching on which state the menu is in, `components/attachments-menu.tsx` treats each geometry channel as one continuous three state blend: every `useDerivedValue` computes `closed + (open - closed) * progress + (extended - open) * extendProgress` for `bottom`, `left`, `width` and `height`, which means the box is defined everywhere between the three keyframes. Because it is continuous, dropping both drivers to zero with the same spring shrinks the panel straight from the extended surface back to the plus, which is what removes the snap you get from sequencing two animations. A single `useAnimatedStyle` reads those four derived values and also interpolates a `boxShadow` string from `progress`. The Liquid Glass surface is `Animated.createAnimatedComponent(GlassView)` whose `useAnimatedProps` flips `glassEffectStyle` from `'none'` to `'clear'` past `progress > 0.01` and runs `interpolateColor` on `tintColor`, while the menu items use their own opacity worklet, `Math.max(0, openFade - extendProgress.get())`, so they fade in on open and stay hidden during a direct close. Because animating opacity on an ancestor of a glass view kills the material (expo/expo issue 41024), the extended surface's back and All Photos buttons are scaled and translated instead of faded, and they are mounted as siblings of the menu's glass rather than children of it. The overlay is an `OverKeyboardView` from react-native-keyboard-controller containing a `GestureHandlerRootView`, an absolutely filled `Pressable` backdrop that calls the close worklet, and the animated glass panel; `scheduleOnRN` from react-native-worklets hops back to JavaScript to unmount state only once a spring's `finished` callback is true. ## What you get ``` App.tsx index.ts app.json package.json package-lock.json tsconfig.json README.md .gitignore components/ attachments-menu.tsx input-container.tsx assets/ waveform.png icon.png adaptive-icon.png splash-icon.png ``` - AttachmentsMenu overlay component (attachments-menu.tsx) - Input bar host component (input-container.tsx) - Demo App entry (App.tsx) - Waveform send-button icon asset - README with install and usage ## Requirements ChatGPT-Style Attachments Menu targets Expo SDK 56. Versions pinned in the archive's `package.json`: - expo ^56.0.8 - 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-glass-effect ~56.0.4 - expo-symbols ~56.0.5 - expo-camera ~56.0.8 - expo-linear-gradient ~56.0.4 - react-native-safe-area-context ^5.8.0 - @legendapp/list ^3.3.0 - typescript ~6.0.3 (dev dependency) ChatGPT-Style Attachments Menu runs in Expo Go on Expo SDK 56. The modules you would expect to block it do not: `expo-glass-effect` (the iOS 26 Liquid Glass material), `expo-camera`, `expo-symbols`, `expo-linear-gradient` and `react-native-keyboard-controller` are all bundled in Expo Go as of SDK 56, and `@legendapp/list` is JavaScript only, with no native code at all. A development build is still what you would ship to production, and it is what you need as soon as you add any native module Expo Go does not bundle, or a config plugin: this archive's `app.json` configures `expo-camera` with its own camera permission string, and a config plugin only takes effect in a build, so in Expo Go you get Expo Go's permission prompt instead. Two practical caveats either way: the live camera surface needs a physical device, because `expo-camera` does not run on simulators, and Liquid Glass only renders its real material on iOS 26 or newer, falling back to a plain view elsewhere. Liquid Glass and SF Symbols are iOS APIs, so the finished look is an iOS look. Run it with `npx expo start` in Expo Go, or `npx expo run:ios` for a development build. ## 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-glass-effect expo-symbols \ expo-camera expo-linear-gradient @legendapp/list ``` ## Usage ```tsx import { useState } from 'react'; import { Pressable, View } from 'react-native'; import { useSharedValue, withSpring } from 'react-native-reanimated'; import { useReanimatedKeyboardAnimation } from 'react-native-keyboard-controller'; import { AttachmentsMenu } from './components/attachments-menu'; export const Composer = () => { const [menuVisible, setMenuVisible] = useState(false); const progress = useSharedValue(0); const extendProgress = useSharedValue(0); const { height: keyboardHeight } = useReanimatedKeyboardAnimation(); const openMenu = () => { setMenuVisible(true); progress.set(withSpring(1, { duration: 450 })); }; const closeMenu = () => { 'worklet'; extendProgress.set(withSpring(0, { duration: 450 })); progress.set(withSpring(0, { duration: 450 })); }; return ( ); }; ``` The shipped `App.tsx` wraps the demo in `SafeAreaProvider`, `GestureHandlerRootView` and `KeyboardProvider`, then renders ``, which is the full input bar plus the menu already wired together. `InputContainer` takes no props. ## Customization `AttachmentsMenu`, the overlay component in ChatGPT-Style Attachments Menu, takes five props: - `visible: boolean` (mounts the `OverKeyboardView` overlay) - `progress: SharedValue` (0 to 1 open animation progress) - `extendProgress: SharedValue` (0 to 1 extend animation progress) - `keyboardHeight: SharedValue` (keyboard height, used to anchor the menu above the input bar) - `onClose: () => void` (called by the backdrop `Pressable`; in the demo it is a worklet that drops both drivers to zero) The rest is edited in source, which is the point of buying the source: - `MENU_ITEMS` in `components/attachments-menu.tsx` is a four entry `as const` array of `{ label, symbol, mode }`, where `symbol` is an SF Symbol name and `mode` is `'photos'` or `'camera'`. Add or relabel rows here. - `GRID_IMAGES` is 20 placeholder photos from Lorem Picsum. Swap the `uri` for your own asset URIs or a real media library query. - The closed, open and extended keyframes are plain numbers inside the four `useDerivedValue` blocks (closed 46 wide by 46 tall, open 270 by 280, extended full screen width minus 16). Change the panel size there. - Spring feel is `withSpring(target, { duration: 450 })` in both `input-container.tsx` and `attachments-menu.tsx`. - The photo grid is a `LegendList` with `numColumns={3}`, `estimatedItemSize={118}` and `recycleItems`. ## When to use it - An AI assistant or chat app composer that needs an attach button feeling native to iOS rather than a generic modal. - A messaging screen where the photo picker should open in place, above the keyboard, without pushing the conversation off screen. - Any input bar where you want camera capture and photo selection behind one control instead of two separate sheets. - A support or feedback widget that accepts screenshots and photos. - A comment composer that needs an image attachment step without a full screen route transition. - Any product replacing a plain "choose from library or take a photo" action sheet with a single continuous morph. ## How to get it - Buy ChatGPT-Style Attachments Menu on its own at https://motionary.dev/animations/chatgpt-style-attachments-menu, $10 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 ChatGPT style attachment menu in React Native?** Drive it from two react-native-reanimated shared values and express every geometry channel as one continuous blend of the closed, open and extended keyframes with `useDerivedValue`, so both springs can fall to zero together and collapse in one motion. Motionary's ChatGPT-Style Attachments Menu is that implementation as editable TypeScript source, at https://motionary.dev/animations/chatgpt-style-attachments-menu. **Does ChatGPT-Style Attachments Menu work with Expo Go?** Yes. Motionary's ChatGPT-Style Attachments Menu runs in Expo Go on Expo SDK 56: `expo-glass-effect` (the iOS 26 Liquid Glass material), `expo-camera`, `expo-symbols` and `react-native-keyboard-controller` are all bundled in Expo Go as of SDK 56, so none of them forces a development build. Use a physical device, because `expo-camera` does not run on simulators. A development build is still what you would ship to production, and what you need as soon as you add a native module Expo Go does not bundle or a config plugin (the `expo-camera` permission string in this archive's `app.json` only takes effect in a build). **How do I animate a chat input plus button into a menu without it snapping?** The snap comes from sequencing two animations and handing off between them. ChatGPT-Style Attachments Menu avoids it by making the panel's position and size continuous across all three states, so a close from the extended camera view is a single spring, never a collapse to the menu items followed by a second collapse to the plus. **How do you render a menu above the keyboard in React Native?** ChatGPT-Style Attachments Menu uses react-native-keyboard-controller: `OverKeyboardView` hosts the overlay above the keyboard window, `useReanimatedKeyboardAnimation` feeds live keyboard height into the panel's animated `bottom`, `left` and `height`, and `KeyboardStickyView` keeps the input bar itself pinned to the keyboard. **Which photo grid does it use, and is it recycled?** The extended photo surface in Motionary's ChatGPT-Style Attachments Menu is a `@legendapp/list` `LegendList` with `numColumns={3}` and `recycleItems`, and it is mounted lazily only once the menu extends, so its 20 placeholder images are not fetched up front. **Is the Liquid Glass effect iOS only?** Yes in practice. ChatGPT-Style Attachments Menu renders its panel and buttons with `expo-glass-effect`, the Liquid Glass material introduced in iOS 26, and its icons with `expo-symbols` SF Symbols, so the intended target is iOS on Expo SDK 56. On iOS versions before 26, `GlassView` falls back to a plain view, so the morph still animates, just without the glass material. **Do I get the source code, and can I ship it in a commercial app?** Yes. Buying ChatGPT-Style Attachments Menu on Motionary ($10 USD) is an instant download of the full TypeScript React Native source, licensed for one developer to ship in unlimited personal and commercial apps. Do not resell or redistribute the source itself. Terms: https://motionary.dev/license ## Related drops on Motionary - Attachment Sheet ($12): https://motionary.dev/animations/attachment-sheet The Telegram take on the same problem, a Liquid Glass attachment bottom sheet driven by gesture rather than a morphing plus button. - Long-Press Menu ($9): https://motionary.dev/animations/long-press-menu Another chat input overlay built on react-native-keyboard-controller and glass, opened by long press instead of tap. - ChatGPT Slider Model Picker ($10): https://motionary.dev/animations/chatgpt-slider-model-picker The other half of a ChatGPT style composer, a model selector that lives in the same input bar and keyboard stack. - Live Camera Button ($5): https://motionary.dev/animations/live-camera-button A camera capture control with glass and press states, for apps that want the camera entry point without the full attachments panel. - Glass Video Player (Free): https://motionary.dev/animations/glass-video-player A free way to see how Motionary builds Liquid Glass surfaces and draggable media controls in React Native. ## 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/chatgpt-style-attachments-menu/llms.txt Describes: https://motionary.dev/animations/chatgpt-style-attachments-menu Format: llms.txt (https://llmstxt.org) Last updated: 2026-09-01 ```