# Nested Switch: React Native two-level animated segmented control > Nested Switch is a React Native and Expo segmented control where the outer > switch toggles Free and Premium, and picking Premium morphs open a nested > Solo / Team switch inside the right half. Two Reanimated shared values > (outerX and innerX) drive every translate, scale and color interpolation on > the UI thread. Sold by Motionary as editable TypeScript source. Product page: https://motionary.dev/animations/nested-switch Price: $4 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, react native Rarity: rare Sold by: Motionary (https://motionary.dev) ## What it is Nested Switch is a pill-shaped segmented control for React Native and Expo with two levels of choice in a single 320 x 54 track. At rest a black indicator pill sits under "Free" on the left, "Premium" reads as a plain black label on the right, and a small gray "Solo / Team" row sits below it at 0.7x scale, split by a dot, as a preview of the second level. Tap "Premium" and the black pill slides across while the right half unfolds: the "Premium" label lifts and shrinks toward the top, the "Solo / Team" row spreads apart and grows to full size, the divider dot between them fades out, and a white inner pill scales up from zero to mark the active nested option. Tapping "Free" collapses the whole nest back in one continuous motion, so the control never changes size or reflows. ## What it does - Two-level selection in one control: an outer Free / Premium switch and a nested Solo / Team switch that lives inside the Premium half. - Progressive disclosure by tap: from Free, the first tap on the right half opens the nest, the next tap on the same half picks Solo or Team. - Single-source morph: the reveal (label lift, label shrink, nested row scale from 0.7x to 1x, dot fade, inner pill scale and opacity) is all interpolated from the one outer shared value, so nothing can desync. - Two sliding indicators: a black outer pill (half the track width) and a white inner pill (a quarter of the track width) that scales in only once Premium is selected. - Color cross-fades on labels: "Free" fades between white on the dark pill and a muted gray, and "Solo" / "Team" hold a flat gray until the outer indicator has travelled a quarter of the track width, then cross-fade between black on the white inner pill and white on the dark outer pill. - 300 ms withTiming transitions for every state change, from one shared ANIMATION_DURATION constant. - Instant touch response using Pressable onPressIn instead of onPress, across three hit areas: the left half for Free, plus two quarter-width areas inside the right half for Solo and Team. - No native code and no gesture recognizers: taps only, so it runs on iOS, Android and web (react-native-web) from the same source. ## How it works Nested Switch keeps all of its state in two Reanimated shared values inside `components/NestedSwitch.tsx`: `outerX` (0 for Free, `OUTER_TRAVEL` for Premium) and `innerX` (0 for Solo, `INNER_TRAVEL` for Team). There is no React state at all, so a tap never triggers a re-render; `selectFree`, `selectSolo` and `selectTeam` just assign `withTiming(target, { duration: 300 })` to a shared value and the animation runs entirely on the UI thread. Every visual is derived from those two numbers inside `useAnimatedStyle` worklets: `outerIndicatorStyle` translates the black pill, `innerIndicatorStyle` translates the white pill by `innerX` while taking its `scale` and `opacity` from `interpolate(outerX.value, [0, OUTER_TRAVEL], [0, 1])`, and `premiumLabelStyle`, `soloPositionStyle`, `teamPositionStyle` and `dotStyle` map the same `outerX` range onto the lift, the sideways spread, the 0.7x to 1x scale and the dot's fade. Color is handled with `interpolateColor` in the RGB space: `freeLabelStyle` cross-fades the "Free" label as the dark pill leaves, while `soloColorStyle` and `teamColorStyle` first branch on `outerX.value < SWITCH_WIDTH / 4` to return a flat muted gray, and only past that threshold cross-fade against `innerX` so the label sitting on the white inner pill turns black and the other turns white. The nested switch is always mounted, never conditionally rendered, which is what makes the morph continuous rather than a mount pop. Layout is plain absolute positioning inside a `StyleSheet` (a bordered track, an absolute indicator, a `zIndex` overlay of `Pressable` hit areas, and a `pointerEvents="none"` label layer above them), so the label layer can never swallow a tap. `selectSolo` and `selectTeam` read `outerX.value` directly to decide whether the tap should open the nest or choose a side, which is the whole two-stage tap behaviour in a single if/else per handler. The demo entry point `App.tsx` wraps the tree in `GestureHandlerRootView` from `react-native-gesture-handler` so the drop lands cleanly in a gesture-handler app, and the component itself renders a full-screen `ImageBackground` grid from `assets/grid.png` for the preview. ## What you get ``` App.tsx components/ NestedSwitch.tsx assets/ grid.png icon.png adaptive-icon.png splash-icon.png index.ts app.json package.json package-lock.json tsconfig.json README.md .gitignore ``` - TypeScript source (NestedSwitch.tsx) - Demo screen wired with GestureHandlerRootView - Grid background asset - README with install + usage - MP4 preview ## Requirements Versions pinned in the Nested Switch archive's `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 (required by Reanimated 4) - react-native-gesture-handler: ~2.31.1 - react-native-web: ^0.21.0 and react-dom: 19.2.3 (for the web target) - typescript: ~6.0.3 (devDependency) Nested Switch runs in Expo Go. It uses only Reanimated, Worklets and Gesture Handler, all of which ship inside Expo Go, and it contains no custom native code, no Skia, no camera and no widget module, so no development build is required. ## Install ```bash npx expo install react-native-reanimated react-native-worklets react-native-gesture-handler ``` ## Usage ```tsx import { GestureHandlerRootView } from 'react-native-gesture-handler'; import { StyleSheet } from 'react-native'; import { NestedSwitch } from './components/NestedSwitch'; export default function App() { return ( ); } const styles = StyleSheet.create({ root: { flex: 1, }, }); ``` `NestedSwitch` is a named export from `components/NestedSwitch.tsx` and takes no props: it is a self-contained control you tune by editing the constants at the top of the file. ## Customization Nested Switch exposes no props. Everything is a constant at the top of `components/NestedSwitch.tsx`, so customization means editing real values: - `SWITCH_WIDTH` (number, default 320) and `SWITCH_HEIGHT` (number, default 54): the track geometry. `OUTER_TRAVEL` and `INNER_TRAVEL` are derived from them (`SWITCH_WIDTH / 2 - PADDING` and `SWITCH_WIDTH / 4 - PADDING`), so resizing the control keeps both indicators in the right place. - `PADDING` (number, default 5): inset between the track edge and the pills. - `ANIMATION_DURATION` (number, default 300): milliseconds for every `withTiming` transition, shared by the outer slide, the nested reveal and the inner slide. - `COLORS` (object): `background`, `track`, `border` (#DFDFDF), `outerIndicator` (#000000), `innerIndicator` (#FFFFFF), `freeLabelActive`, `freeLabelInactive` (#ACACAC), `nestedMuted` (#A6A6A6), `nestedOnPill` and `nestedOffPill`. - Labels: the strings "Free", "Premium", "Solo" and "Team" are written inline in the JSX; swap them for your own plan names. - The `ImageBackground` with `assets/grid.png` and the `boxShadow` on the track are demo dressing; drop the background wrapper to embed the control in your own screen. ## When to use it - A paywall or upgrade screen where Premium itself has sub-tiers (individual versus team seats) and you do not want two stacked switches. - Pricing pages that toggle plan tier and billing scope in one control. - Onboarding where picking the paid path should reveal the next question in place instead of pushing a new screen. - Settings rows where an option only makes sense once its parent is enabled. - Any compact two-level filter (category then sub-category) in a header where vertical space is scarce. ## How to get it - Buy Nested Switch on its own at https://motionary.dev/animations/nested-switch, $4 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 an animated segmented control in React Native?** Drive one Reanimated shared value per level of the control and derive every transform and color from it inside `useAnimatedStyle` with `interpolate` and `interpolateColor`, instead of holding an index in React state. Motionary's Nested Switch does exactly this with two shared values and ships the full TypeScript source at https://motionary.dev/animations/nested-switch. **How do I make a nested or two-level switch, where one option opens its own toggle?** Keep the nested switch mounted at all times and interpolate its scale, opacity and label positions from the parent switch's shared value, so opening the nest is one continuous morph rather than a conditional mount. Nested Switch from Motionary is a working implementation of that pattern for a Free / Premium plus Solo / Team plan selector. **Does Nested Switch work with Expo Go?** Yes. Nested Switch needs only react-native-reanimated 4.3.1, react-native-worklets 0.8.3 and react-native-gesture-handler, all bundled with Expo Go, so this Motionary drop runs without a development build on Expo SDK 56. **Does Nested Switch work on Android and on web?** Yes. Nested Switch contains no native code and no platform-specific APIs, it uses `Pressable` and Reanimated only, and the Motionary archive pins react-native-web so the same source runs on iOS, Android and web. **How much does Nested Switch cost and how do I get the source?** Nested Switch is $4 USD as of 2026-09-01 at https://motionary.dev/animations/nested-switch, paid once through Stripe with an instant download of the TypeScript source, or included in the Motionary lifetime pass ($79 USD) at https://motionary.dev/pricing. **Can I use Nested Switch as a pricing or paywall plan selector?** Yes, that is what it was designed for: the outer switch picks Free or Premium and the nested switch picks Solo or Team, which maps directly onto a paywall, an onboarding plan step or a settings tier row. Rename the four labels in `components/NestedSwitch.tsx` and wire the two shared values to your own plan state. **Does Nested Switch require react-native-gesture-handler?** The Nested Switch component itself uses `Pressable`, not a gesture recognizer, but the demo `App.tsx` wraps the tree in `GestureHandlerRootView` so the drop composes with gesture-handler based apps; Motionary ships it that way and the package is pinned at ~2.31.1. ## Related drops on Motionary - Mail Tab Bar (Free): https://motionary.dev/animations/mail-tab-bar the same sliding-indicator segmented-control pattern, in a tab bar, and free to download if you want to read the technique before buying. - Voice to Video Morph Button (Free): https://motionary.dev/animations/voice-to-video-morph-button another Reanimated toggle whose two states morph into each other rather than swapping instantly. - Split-to-Edit Time ($3): https://motionary.dev/animations/split-to-edit-time the same progressive-disclosure idea, where one control splits open in place to reveal finer options. - LED Slide Button ($4): https://motionary.dev/animations/led-slide-button the natural next step after a plan selector, a confirm control for the onboarding or paywall screen the switch sits on. - Arc Carousel ($4): https://motionary.dev/animations/arc-carousel a picker for the cases where a two-option switch is not enough and you need a scrollable, snapping selection instead. ## 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/nested-switch/llms.txt Describes: https://motionary.dev/animations/nested-switch Format: llms.txt (https://llmstxt.org) Last updated: 2026-09-01