npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

react-native-magic-tab-bar

v2.1.0

Published

Customizable floating tab bar for Expo Router and React Navigation (bare React Native). Bring your own icons and labels.

Readme

react-native-magic-tab-bar is a drop-in custom bottom tab bar for React Native. Instead of the default tab bar, you get a floating, animated bar with an active-tab pill, badges, labels, haptics, glass/blur backgrounds and full theming — on both iOS and Android. The same component works whether your app uses Expo Router or React Navigation (@react-navigation/bottom-tabs), so you can search less and ship faster.

Two entry points, one look:

  • Expo RouterMagicTabs from react-native-magic-tab-bar (see Quick start).
  • Bare React Native / React NavigationMagicTabBarNavigation from react-native-magic-tab-bar/react-navigation (see React Navigation).

Pick whichever entry point matches your app — you never pull in the other framework's dependencies.

Features

  • 🎯 Drop-in for both — one component for Expo Router and React Navigation; bring your own icons.
  • Animated active pill with a spring you can tune.
  • 🏷️ Flexible labels — beside or below the icon; show on the active tab, always, or never.
  • 🔴 Badges — dots or counts on any tab.
  • 🧊 Glass / blur / transparent backgrounds (native iOS Liquid Glass supported).
  • 📳 Haptics and press callbacks (great for "scroll to top" on re-press).
  • Action (FAB) tab for a raised center button.
  • 🪶 Light mode — a compact, icon-only bar you can switch on per tab (e.g. only on an immersive full-screen feed), with a smooth transition.
  • 🎨 Fully themeable via a single theme prop.

Table of contents

Screenshots

Compatibility

| Environment | How you use it | Supported | | --- | --- | :---: | | Expo Router (SDK 56+) | MagicTabs from react-native-magic-tab-bar | ✅ | | React Navigation (@react-navigation/bottom-tabs v6 & v7) | MagicTabBarNavigation from react-native-magic-tab-bar/react-navigation | ✅ | | Bare React Native CLI | via React Navigation | ✅ | | Expo (managed & prebuild) | via Expo Router | ✅ | | iOS · Android | — | ✅ | | New Architecture (Fabric) | — | ✅ | | TypeScript | types bundled, no @types needed | ✅ |

Installation

npm install react-native-magic-tab-bar
# yarn add react-native-magic-tab-bar
# pnpm add react-native-magic-tab-bar
# bun add react-native-magic-tab-bar

Then install the peer dependencies for your framework 👇

Expo Router

Requirements: an Expo Router project (Expo SDK 56+) with an app/ directory.

Peer dependencies (normally already present in an Expo Router app):

npx expo install expo-router react-native-reanimated react-native-safe-area-context react-native-worklets

Make sure the Reanimated/Worklets Babel plugin is enabled (Expo SDK 56's babel-preset-expo configures this automatically).

Optional — install only if you use the matching feature:

npx expo install expo-glass-effect   # native iOS Liquid Glass (glass prop)
npx expo install expo-haptics        # selection haptics (haptics prop)
npx expo install @expo/vector-icons  # only for the /default-tabs demo set

React Native CLI (React Navigation)

Requirements: a bare React Native CLI app using @react-navigation/bottom-tabs.

npm install @react-navigation/native @react-navigation/bottom-tabs \
  react-native-screens react-native-safe-area-context \
  react-native-reanimated react-native-worklets

Add the Worklets/Reanimated plugin last in your babel.config.js:

module.exports = {
  presets: ['module:@react-native/babel-preset'],
  plugins: ['react-native-worklets/plugin'],
};

iOS: cd ios && pod install. No Expo packages are required — the glass and haptics props are Expo-only and simply no-op here unless you install expo-glass-effect / expo-haptics.

See the runnable example-cli app for a complete setup.

Quick start

Use MagicTabs as your tab navigator in app/_layout.tsx. Each entry in tabs maps a route to an icon and label:

// app/_layout.tsx
import { MagicTabs } from "react-native-magic-tab-bar";
import { Ionicons } from "@expo/vector-icons";

export default function Layout() {
  return (
    <MagicTabs
      tabs={[
        { name: "index",   href: "/",        label: "Home",    icon: ({ color, size }) => <Ionicons name="home"    color={color} size={size} /> },
        { name: "search",  href: "/search",  label: "Search",  icon: ({ color, size }) => <Ionicons name="search"  color={color} size={size} /> },
        { name: "profile", href: "/profile", label: "Profile", icon: ({ color, size }) => <Ionicons name="person"  color={color} size={size} /> },
      ]}
    />
  );
}
  • name must match the route file in your app/ directory (e.g. index, search, profile).
  • href is where the tab navigates.
  • icon receives { focused, color, size } so you can swap glyphs/colors for the active state.

MagicTabs renders Expo Router's <Tabs> for you — put it straight in app/_layout.tsx. There's no separate <Tabs> wrapper to set up.

Tip — filled vs. outline icons: use focused to swap the glyph on the active tab:

icon: ({ focused, color, size }) => (
  <Ionicons name={focused ? "home" : "home-outline"} color={color} size={size} />
);

Want a ready-made set for a quick look? Import the demo tabs from the subpath (this is the only thing that pulls in @expo/vector-icons, so the core stays dependency-free):

import { defaultTabs } from "react-native-magic-tab-bar/default-tabs";

<MagicTabs tabs={defaultTabs} />;

React Navigation (bare React Native)

In a bare React Native app you use MagicTabBarNavigation as the tabBar of a bottom tab navigator. It takes the same tab config as MagicTabs — just without href (React Navigation routes by name) — so the bar looks and behaves identically.

import { NavigationContainer } from "@react-navigation/native";
import { createBottomTabNavigator } from "@react-navigation/bottom-tabs";
import { SafeAreaProvider } from "react-native-safe-area-context";
import { MagicTabBarNavigation } from "react-native-magic-tab-bar/react-navigation";
import Ionicons from "react-native-vector-icons/Ionicons";

const Tab = createBottomTabNavigator();

const tabs = [
  { name: "Home",    label: "Home",    icon: ({ color, size }) => <Ionicons name="home"   color={color} size={size} /> },
  { name: "Search",  label: "Search",  icon: ({ color, size }) => <Ionicons name="search" color={color} size={size} /> },
  { name: "Profile", label: "Profile", icon: ({ color, size }) => <Ionicons name="person" color={color} size={size} /> },
];

export default function App() {
  return (
    <SafeAreaProvider>
      <NavigationContainer>
        <Tab.Navigator
          screenOptions={{ headerShown: false }}
          tabBar={(props) => <MagicTabBarNavigation {...props} tabs={tabs} />}
        >
          <Tab.Screen name="Home"    component={HomeScreen} />
          <Tab.Screen name="Search"  component={SearchScreen} />
          <Tab.Screen name="Profile" component={ProfileScreen} />
        </Tab.Navigator>
      </NavigationContainer>
    </SafeAreaProvider>
  );
}
  • Each tabs[].name must match a <Tab.Screen name>.
  • No href — that's an Expo Router concept; React Navigation navigates by name.
  • Every visual prop from MagicTabs (theme, showLabels, labelPosition, variant, isTransparent, renderBackground, haptics, onTabPress, …) works here too, plus all the Recipes below.

Icons are bring-your-own, exactly like the Expo entry — the icon render function is identical. This example uses react-native-vector-icons (the bare-RN counterpart of @expo/vector-icons). Bundle its fonts the CocoaPods way — not react-native-asset: on iOS the pod bundles the font files (just add a UIAppFonts entry to Info.plist), and on Android apply the package's fonts.gradle in app/build.gradle. The only Expo-specific props are glass (expo-glass-effect) and haptics (expo-haptics), which no-op in bare RN unless you add those modules.

Prefer to keep the config next to your screens instead of a tabs array? The config is just data — build it however you like; only name and icon are required per tab.

Recipes

The recipes below are written with MagicTabs (Expo Router), but every prop shown also works on MagicTabBarNavigation — pass it the same way.

Labels

Labels are beside the icon by default (labelPosition="right"), shown only on the active tab.

<MagicTabs tabs={tabs} labelPosition="bottom" showLabels="always" /> // Material-style bar
<MagicTabs tabs={tabs} showLabels={false} />                         // icon-only bar

| showLabels | Effect | | --- | --- | | true / "active" | Label on the focused tab only (default) | | "always" | Label on every tab (requires labelPosition="bottom") | | false / "never" | Icon-only |

labelPosition is "right" (default) or "bottom". You can also override visibility per tab with showLabel on the tab config.

Badges

{ name: "inbox", href: "/inbox", label: "Inbox", badge: 5,   icon },  // count bubble
{ name: "alerts", href: "/alerts", label: "Alerts", badge: true, icon }, // dot

badge accepts a number, string, or boolean (true = dot). Numbers above 99 show as 99+. Colors come from theme.badgeColor / theme.badgeTextColor.

Haptics and press callbacks

<MagicTabs
  tabs={tabs}
  haptics // selection haptic on tap (needs expo-haptics)
  onTabPress={(name, focused) => {
    if (focused) scrollToTop(name); // re-pressing the active tab
  }}
/>

onTabPress / onTabLongPress receive (name, focused), where focused tells you the tab was already active — perfect for scroll-to-top or reset-stack behavior.

Disabled tabs

{ name: "soon", href: "/soon", label: "Soon", disabled: true, icon }

Dims the tab and blocks navigation to it.

Action (FAB) tab

Render a raised, circular center button:

{ name: "create", href: "/create", variant: "action", icon }

Uses theme.actionColor / theme.actionIconColor.

Glass, blur and transparency

<MagicTabs tabs={tabs} glass />                          // native iOS Liquid Glass (iOS 26+)
<MagicTabs tabs={tabs} isTransparent transparency={0.4} />// translucent bar
<MagicTabs tabs={tabs} renderBackground={() => <MyBlurView />} /> // any custom background
  • glass uses expo-glass-effect on iOS 26+ and falls back to the translucent barColor elsewhere.
  • renderBackground renders any view behind the bar; when omitted, a solid barColor is used.

Light mode (compact bar)

A shorter, icon-only bar (65% width, floating higher). Turn it on for the whole bar, or per tab so it only appears on an immersive screen:

// Whole bar
<MagicTabs tabs={tabs} isLight lightBottomMargin={40} />

// Per tab — the bar morphs to light only while "explore" is the active route
<MagicTabs
  tabs={[
    { name: "index",   href: "/",        label: "Home",    icon },
    { name: "explore", href: "/explore", label: "Explore", icon, isLight: true },
    { name: "profile", href: "/profile", label: "Profile", icon },
  ]}
/>

The transition between the normal and light bar is animated. lightBottomMargin (default 14) controls the extra gap above the screen edge in light mode.

Theming

Everything visual — colors, sizes, corner radius, the animation spring — lives in one theme prop. Override any subset; the rest falls back to defaultTheme.

The colors that matter most:

| Token | Controls | | --- | --- | | barColor | the bar's background | | activePillColor | the pill highlight behind the active tab | | activeColor | the active tab's icon + label | | inactiveColor | the icons of inactive tabs | | badgeColor / badgeTextColor | the badge bubble + its text | | actionColor / actionIconColor | the action (FAB) tab |

<MagicTabs
  tabs={tabs}
  theme={{
    barColor: "#17171C",        // dark bar
    activePillColor: "#2563EB", // blue highlight behind the active tab
    activeColor: "#FFFFFF",     // active icon/label
    inactiveColor: "#9BA0AA",   // inactive icons
    radius: 24,                 // rounder bar & pill
    spring: { mass: 0.6, damping: 16, stiffness: 200 }, // snappier animation
  }}
/>

See the full token list with defaults for sizes (iconSize, height, fontSize), spacing (horizontalMargin, bottomInset) and more.

API

<MagicTabs />

| Prop | Type | Default | Description | | --- | --- | --- | --- | | tabs | MagicTabConfig[] | required | The tabs, in order. | | theme | Partial<MagicTabBarTheme> | defaultTheme | Override any visual token. | | showLabels | boolean \| 'active' \| 'always' \| 'never' | 'active' | When labels are shown. 'always' needs labelPosition="bottom". | | labelPosition | 'right' \| 'bottom' | 'right' | Label beside or below the icon. | | variant | 'floating' \| 'docked' | 'floating' | Float over content, or dock in flow. | | isLight | boolean | false | Force the compact light bar for all tabs. | | lightBottomMargin | number | 14 | Extra bottom gap in light mode only. | | isTransparent | boolean | false | Make the bar background see-through. | | transparency | number | 0.6 | Bar opacity 0–1 while isTransparent. | | glass | boolean | false | Native iOS Liquid Glass (needs expo-glass-effect). | | renderBackground | () => ReactNode | — | Custom background (blur/glass) behind the bar. | | haptics | boolean | false | Selection haptic on press (needs expo-haptics). | | onTabPress | (name, focused) => void | — | Fired on tab press. | | onTabLongPress | (name, focused) => void | — | Fired on tab long-press. |

MagicTabConfig

| Field | Type | Description | | --- | --- | --- | | name | string | Route name. Expo Router: matches the file in app/. React Navigation: matches <Tab.Screen name>. | | href | MagicHref? | Destination, e.g. / or /search. Required for Expo Router, ignored by React Navigation. | | icon | (p: MagicTabIconProps) => ReactNode | Renders the icon. Gets { focused, color, size }. | | label | string? | Text label. | | showLabel | boolean? | Per-tab override of showLabels. | | badge | number \| string \| boolean? | Dot (true) or count bubble. | | disabled | boolean? | Dim the tab and block navigation. | | variant | 'action'? | Render as a raised FAB button. | | isLight | boolean? | Switch the whole bar to light mode while this tab is active. |

<MagicTabBarNavigation />

The React Navigation binding, imported from react-native-magic-tab-bar/react-navigation. Pass it to Tab.Navigator's tabBar prop.

It receives React Navigation's BottomTabBarProps (spread from {...props}) plus:

| Prop | Type | Default | Description | | --- | --- | --- | --- | | tabs | MagicNavigationTab[] | required | Per-tab config keyed by route name (same as MagicTabConfig but without href). |

All other visual props are identical to <MagicTabs />: theme, showLabels, labelPosition, variant, isLight, lightBottomMargin, isTransparent, transparency, glass, renderBackground, haptics, onTabPress, onTabLongPress.

MagicNavigationTab is Omit<MagicTabConfig, 'href'>.

MagicTabBarTheme

| Token | Default | | | --- | --- | --- | | barColor | rgba(38,38,40,0.94) | Bar background | | activePillColor | rgba(120,120,124,0.55) | Active-tab pill | | activeColor | #FFFFFF | Active icon/label color | | inactiveColor | #FFFFFF | Inactive icon color | | iconSize | 22 | Icon size | | fontSize | 12 | Active label size | | height | 56 | Bar height | | radius | 28 | Bar & pill corner radius | | badgeColor | #FF3B30 | Badge background | | badgeTextColor | #FFFFFF | Badge text | | actionColor | #0A84FF | Action (FAB) background | | actionIconColor | #FFFFFF | Action (FAB) icon | | horizontalMargin | 14 | Side margin from screen edges | | bottomInset | 10 | Extra space below the bar | | spring | { mass: 0.6, damping: 18, stiffness: 180 } | Pill/label animation |

Exported types

MagicTabConfig, MagicHref, MagicTabIconProps, MagicTabBarTheme, MagicTabBarVariant, MagicTabPressHandler, MagicLabelMode, MagicLabelPosition, MagicSpringConfig, plus the defaultTheme value.

From react-native-magic-tab-bar/react-navigation: MagicTabBarNavigation, MagicTabBarNavigationProps, MagicNavigationTab.

defaultTabs is exported from the react-native-magic-tab-bar/default-tabs subpath (not the main entry), so the core adds zero runtime dependencies.

Development

This repo is a monorepo: the library lives at the root (src/), with two runnable example apps that import the library straight from source:

  • example — Expo Router app (MagicTabs).
  • example-cli — bare React Native CLI app (MagicTabBarNavigation).
# Expo Router example
npm install            # from the repo root: installs example deps + build tooling
cd example && npx expo start

# React Native CLI example
cd example-cli && npm install
npm run ios            # or: npm run android

Editing files in src/ hot-reloads in whichever example is running.

Building / publishing

Publishing is restricted to package maintainers.

npm run build     # react-native-builder-bob -> lib/ (ESM + d.ts)
npm publish

Roadmap

  • Sliding active-pill that animates between tabs (currently per-tab pill).
  • ✅ ~~A React Navigation (@react-navigation/bottom-tabs) adapter for bare RN.~~ Shipped — see React Navigation.

License

MIT