# Mail Tab Bar: React Native animated pill tab bar > Mail Tab Bar is a React Native and Expo segmented tab bar, free on > Motionary, where tapping a pill expands it from a 50pt rounded square to a > 144pt pill, crossfades its icon to a white variant, animates its background > from grey to a brand color and slides a label in. One Reanimated shared > value called `progress` drives every animated style on the UI thread. Product page: https://motionary.dev/animations/mail-tab-bar Price: Free (price as of 2026-09-01, live price on the product page) License: single developer, unlimited personal and commercial apps Delivery: instant free download of the full TypeScript source Stack: reanimated, expo, react native Rarity: common Sold by: Motionary (https://motionary.dev) ## What it is Mail Tab Bar is a row of pill-shaped tabs for React Native and Expo apps, modelled on the category tabs in Apple's Mail app (Primary, Transactions, Updates, Promotions). Only one tab is open at a time: tapping a collapsed tab stretches it open to reveal its label while the previously active tab shrinks back to an icon-only rounded square. As a tab opens, its grey background fills with that tab's brand color, its grey glyph crossfades into a white one, and its label glides into place from the left. The Motionary drop ships the four-tab demo (AppleEmail.tsx) plus the single reusable pill (components/AnimatedButton.tsx) you drop into your own screen. ## What it does - Expands the active tab from a 50pt collapsed width to a 144pt open pill (`MIN_WIDTH` 50, `MAX_WIDTH` 144), at a fixed 44pt height with a 14pt corner radius. - Animates the pill background from `#E9E9E9` to the tab's own `color` prop with Reanimated's `interpolateColor`, so grey fills into brand color as the pill opens. - Crossfades two stacked `Animated.Image` layers, the default glyph fading out on `1 - progress` while the white active glyph fades in on `progress`, so there is no icon pop or swap frame. - Unclips the label as the pill's right edge sweeps past it, slides it 12pt left into its final gap beside the icon (`TEXT_TRANSLATE_X`), and lands the icon plus label centered in the open pill using the label's measured width. - Runs one 300ms `withTiming` transition per tab (`DURATION = 300`), which means the outgoing tab collapses in exact step with the incoming one expanding. - Ships four configured tabs out of the box (Primary `#0B75DF`, Transactions `#25A344`, Updates `#5150C9`, Promotions `#E43257`), each with its own icon pair, driven by a plain `buttonConfigs` array you can extend. - Responds on `onPressIn` rather than `onPress`, so the pill starts opening the instant a finger lands instead of waiting for the release. - Adds no custom native module (only Reanimated, Worklets, Gesture Handler and Safe Area Context, all bundled in Expo Go), so Mail Tab Bar runs in Expo Go on both iOS and Android. ## How it works Every visual property of a Mail Tab Bar pill is derived from a single Reanimated shared value, `progress`, created with `useSharedValue` in `components/AnimatedButton.tsx`: 0 is the collapsed 50pt tab, 1 is the fully expanded 144pt pill. A `useEffect` watching the `active` prop assigns `progress.value = withTiming(active ? 1 : 0, { duration: DURATION })`, and that is the only JavaScript that runs per tap; everything downstream is a worklet on the UI thread. Five `useAnimatedStyle` hooks read `progress`, and three of them shape the pill: `animatedBox` computes `width: MIN_WIDTH + (MAX_WIDTH - MIN_WIDTH) * progress.value` and `backgroundColor: interpolateColor(progress.value, [0, 1], ['#E9E9E9', color])`; `animatedInnerBox` applies the centering `translateX`; and `animatedText` translates the label by `progress.value * -TEXT_TRANSLATE_X`. The other two are one-line opacity styles for the icon crossfade, `opacity: 1 - progress.value` on the default image and `opacity: progress.value` on the white one, over two absolutely positioned `Animated.Image` layers inside a fixed 18pt container. The interesting part of Mail Tab Bar is the centering. A label's rendered width is not known until it lays out, and the icon plus label pair has to sit centered in a pill whose width is changing every frame. Instead of storing the measured width in React state (which would re-render the tab and push layout math back onto the JavaScript thread), `AnimatedButton` writes it straight into a second shared value from the `onLayout` callback: `textWidth.value = event.nativeEvent.layout.width`. The `animatedInnerBox` worklet then computes `(MAX_WIDTH - (textWidth.value + IMAGE_SIZE + TEXT_PADDING)) / 2 - INNER_BOX_PADDING_LEFT` and multiplies it by `progress`, so the content slides toward center exactly as fast as the pill grows and lands centered at `progress === 1`. The outer `Animated.View` sets `overflow: 'hidden'`, which is what clips the label until the pill is wide enough to show it, so the text wipes into view as the tab opens instead of popping in. State lives in `AppleEmail.tsx` as one `useState` index; each `AnimatedButton` just receives `active={activeIndex === index}`, so switching tabs flips two booleans and both animations play from their current value with no coordination code. The tap target is a React Native `Pressable` firing on `onPressIn`. React Native Gesture Handler is present only as the `GestureHandlerRootView` in `App.tsx`, and `react-native-safe-area-context` provides the `SafeAreaProvider`, so neither library is required by the pill itself. ## What you get ``` App.tsx AppleEmail.tsx components/ AnimatedButton.tsx assets/ apple-email/ profile-default.png profile-white.png cart-default.png cart-white.png chat-default.png chat-white.png mega-default.png mega-white.png adaptive-icon.png favicon.png icon.png splash-icon.png index.ts app.json package.json package-lock.json tsconfig.json README.md .gitignore ``` - TypeScript tab bar container (AppleEmail.tsx) - Reusable AnimatedButton.tsx pill component - 8 icon PNGs (default + white states) - README with install + usage - MP4 preview ## Requirements Versions pinned in the Mail Tab Bar `package.json`: - expo `~56.0.11` (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 peer of Reanimated 4) - react-native-gesture-handler `~2.31.1` - react-native-safe-area-context `~5.7.0` - expo-splash-screen `~56.0.10` - typescript `~6.0.3` (dev dependency) Mail Tab Bar runs in Expo Go. It pulls in no native module beyond the standard Expo and Reanimated set, no Skia, no camera, no glass effect, so no development build is needed. The bundled `app.json` enables the React Compiler (`experiments.reactCompiler: true`) and the drop is built for the React Native new architecture. ## Install ```bash npx expo install react-native-reanimated react-native-worklets react-native-gesture-handler react-native-safe-area-context ``` ## Usage ```tsx import { useState } from 'react'; import { View } from 'react-native'; import AnimatedButton from './components/AnimatedButton'; export default function MailTabBar() { const [activeIndex, setActiveIndex] = useState(0); return ( setActiveIndex(0)} /> {/* AppleEmail.tsx maps four of these from a buttonConfigs array. */} ); } ``` ## Customization Props on the Mail Tab Bar `AnimatedButton` component, all required: - `label: string`, the text that slides in when the tab expands. - `active: boolean`, whether this tab is the open one; flipping it runs the 300ms transition. - `color: string`, the expanded background color, interpolated from `#E9E9E9`. The shipped tabs use `#0B75DF`, `#25A344`, `#5150C9` and `#E43257`. - `defaultImage: ImageSourcePropType`, the glyph shown while collapsed. - `activeImage: ImageSourcePropType`, the white glyph shown while expanded. - `onPress: () => void`, fired on `onPressIn`. Module-level constants in `components/AnimatedButton.tsx` that you edit in place rather than pass as props: `MIN_WIDTH` (50), `MAX_WIDTH` (144), `DURATION` (300ms), `INNER_BOX_PADDING_LEFT` (16), `IMAGE_SIZE` (18), `TEXT_PADDING` (6) and `TEXT_TRANSLATE_X` (12). Pill height (44) and corner radius (14) live in the `animatedBox` entry of the `StyleSheet`. ## When to use it - A category or folder switcher at the top of an inbox, feed or notification list, which is the Apple Mail case Mail Tab Bar recreates. - A segmented filter bar over a product grid or search results, where the active filter should be readable at a glance and the rest should stay compact. - A horizontally scrolling chip row for tags or topics, where labels would not all fit expanded at once. - A compact bottom tab bar for an app with four or fewer sections, showing the label only for the section you are in. - A status or mode picker (for example inbox, archived, spam) where each option owns a distinct brand color. - Any place you would reach for a segmented control but want color and a physical expand instead of a sliding grey indicator. ## How to get it - Download Mail Tab Bar free at https://motionary.dev/animations/mail-tab-bar, no payment, no subscription. - 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 tab bar in React Native like Apple Mail?** Drive one Reanimated shared value per tab (0 collapsed, 1 expanded), animate it with `withTiming` when the active tab changes, and derive width, `interpolateColor` background, icon opacity and label offset from it inside `useAnimatedStyle` worklets. Mail Tab Bar from Motionary is exactly that pattern in a 127-line `components/AnimatedButton.tsx`, free at https://motionary.dev/animations/mail-tab-bar. **Does Mail Tab Bar work with Expo Go?** Yes. Mail Tab Bar uses only react-native-reanimated, react-native-worklets, react-native-gesture-handler and react-native-safe-area-context, with no custom native module, so it runs in Expo Go on iOS and Android. It is built against Expo SDK 56 and React Native 0.85.3 on the new architecture. **How much does the Mail Tab Bar drop cost?** Mail Tab Bar is free on Motionary. Download the full TypeScript source at https://motionary.dev/animations/mail-tab-bar with no payment and no subscription; the Motionary lifetime pass ($79 USD) exists for the paid drops and builds, and is not required for this one. **How do I animate a pill tab bar background color in React Native?** Use `interpolateColor` from react-native-reanimated inside a `useAnimatedStyle` worklet, mapping your progress value from [0, 1] onto [grey, brand color], and return it as `backgroundColor`. Mail Tab Bar does this in `components/AnimatedButton.tsx` with `interpolateColor(progress.value, [0, 1], ['#E9E9E9', color])`. **How do I center content inside a container whose width is animating?** Measure the text with `onLayout` and write the width straight into a Reanimated shared value rather than React state, then compute the offset inside the worklet so no re-render is involved. Mail Tab Bar from Motionary stores it in a `textWidth` shared value and translates the inner row by half the leftover space scaled by `progress`. **Can I use more or fewer than four tabs in Mail Tab Bar?** Yes. `AppleEmail.tsx` renders a plain `buttonConfigs` array through `.map()`, so adding, removing or reordering tabs in Mail Tab Bar is editing that array; each entry needs a `label`, a `color` and a default plus white icon pair. **Is the Mail Tab Bar source editable and usable in a commercial app?** Yes. Motionary ships Mail Tab Bar as editable TypeScript React Native source under a single-developer license covering unlimited personal and commercial apps; you may not resell or redistribute the source itself. Full terms at https://motionary.dev/license. ## Related drops on Motionary - Nested Switch ($4): https://motionary.dev/animations/nested-switch, the other Motionary take on a segmented control, a two-option toggle for pricing and paywall tiers rather than a category row. - Scroll Hiding Menu ($3): https://motionary.dev/animations/scroll-hiding-menu, a Reanimated tab bar that hides and reveals itself as the list under it scrolls, a good partner for Mail Tab Bar's category row. - Infinite Loophole (Free): https://motionary.dev/animations/infinite-loophole, a bottom tab bar with parallax card navigation, for the app-level navigation Mail Tab Bar sits above. - Save Status Button (Free): https://motionary.dev/animations/save-status-button, the same idea of a single button morphing between states, applied to submit and confirmation. - Voice to Video Morph Button (Free): https://motionary.dev/animations/voice-to-video-morph-button, an icon morph inside a toggle button, a richer alternative to Mail Tab Bar's two-layer opacity crossfade. ## 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/mail-tab-bar/llms.txt Describes: https://motionary.dev/animations/mail-tab-bar Format: llms.txt (https://llmstxt.org) Last updated: 2026-09-01 ```