Skip to content
WingoUI
ComponentsTemplatesDocsPricingAI agentsBlogChangelogContact
Components
Buttons & Actions
ButtonButton GroupCopy ButtonDelete ButtonTheme ToggleToggleToggle Group
Inputs
Avatar UploadCalendarCheckboxColor PickerComboboxCountry SelectCron PickerCurrency InputDate PickerDate Range PickerDate Time PickerDuration PickerEmail InputEmoji PickerFile UploadFilter BuilderInputInput GroupListboxMasked InputMention InputMonth PickerMulti SelectNumber InputOTP InputPassword InputPhone InputRadio GroupRatingSearch InputSegmented ControlSelectSignature PadSliderSwitchTag InputTextareaTime PickerTimezone SelectTree Select
Forms
Address InputBooking WidgetCSV ImportFieldForm WizardInline EditInvoice line itemsRich Text EditorSchema Builder
Navigation
Back To TopBounce SidebarBreadcrumbCommand MenuGlobal SearchGooey NavHook SidebarNav MenuNav TabsPaginationProximity SidebarScroll ProgressSidebarStepsTable Of ContentsTabsTopbarUser MenuWorkspace Switcher
Overlays
Alert DialogContext MenuDialogDrawerDropdown MenuFamily DrawerHover CardPopoverShare DialogSheetShortcuts DialogTooltipTour
Feedback
AlertBannerCookie ConsentEmoji ReactionEmpty StateNotification BellNotification CenterProgressRoute ProgressSetup ChecklistSkeletonSpinnerToast
Data Display
Approval FlowAvatarBadgeCalendar ViewCode BlockComment ThreadContact cardCountdownDescription ListDiff ViewerFile ListFile managerFolderGanttJSON ViewerKbdLog ViewerMarkdownPresenceSchedulerTagTimelineTree View
Tables & Lists
Audit LogData TableDeal PipelineEditable GridKanbanListMembers tablePermissions MatrixTableTask ListVirtual List
Charts & Stats
Animated CounterArea chartBar chartDonut chartFunnel chartGaugeGitHub ActivityHeatmap calendarLeaderboardLine chartRadar chartRadial barSparklineStat CardTrackerTrend badge
Layout
AccordionApp ShellCardCollapsibleDetail LayoutEntity HeaderPage HeaderScroll AreaSeparatorSettings LayoutSplit ViewToolbar
Media
Audio PlayerCarouselCSV ViewerDOCX EditorDOCX ViewerExcel ViewerFile SystemImage compareImage CropperImage GalleryImage LightboxLocation MapPDF ViewerPowerPoint ViewerQR CodeStep PlayerVideo Player
AI Kit
Agent Status CardChat MessageChat ThreadChat WidgetConversation ListFluid OrbGrid RevealMatrix OrbModel PickerPrompt InputReasoning IndicatorRule BuilderSuggestion ChipsTool Call TimelineUsage MeterVoice InputWorkflow Canvas
Text & Effects
Background PatternGravity LettersMarqueeTerminalText AnimateText Rotate
Mobile
Action SheetBottom Tab BarFABHaptic ButtonHero HeaderInstall PromptLarge Title HeaderNotification BannerOnboarding CarouselPicker WheelPull To RefreshSlide To ConfirmSticky CTA BarSwipe DeckSwipeable Tabs
Commerce
Cart drawerCategory pickerCheckout stepsCoupon inputFavorite buttonFilter panelListing cardListing gridOrder trackerPricePrice rangePricing tableProduct galleryQuantity stepperReviewsSeller card
Marketing Sections
App Download SectionBlog Cards SectionCTA SectionFAQ SectionFeature GridFeature ShowcaseHero SectionIntegrations SectionLogo CloudMarketing FooterMarketing HeaderMarketing SectionNewsletter SectionPricing SectionStats SectionSteps SectionTeam SectionTestimonials SectionTimeline SectionVideo Section
Blocks
Admin Dashboard PageAdmin ShellAI Chat PageAPI Keys PageAutomation Builder PageCheckout PageCRM Contact PageCRM Pipeline PageError PagesInbox PageInvoice PageKPI DashboardListing Detail PageLogin PageMarketplace Home PageMarketplace Search PageMarketplace ShellMobile App HomeOnboarding FlowOrder History PagePost Listing WizardPricing PageProfile PageRegister PageSettings PageUsers Admin Page
Templates
About PageAcademy PageAccessibility PageAffiliate PageAgency PageAI Product PageAppointment Booking PageBlog PageBlog Post PageBug Bounty PageCareers PageChangelog PageCommunity PageCompare PageContact PageCustomer Story PageCustomers PageDemo Booking PageDevelopers PageDocs Home PageDownload PageEnterprise PageEvents PageExperts PageFAQ PageFeature PageGlossary PageHelp Article PageHelp Center PageHome Services PageImpact PageIntegration Detail PageIntegrations PageJob Detail PageLanding PageLaunch PageLegal PageManifesto PagePortfolio PagePress PageProduct Tour PagePromo PageReal Estate PageReferral PageResearch Report PageRestaurant PageRoadmap PageROI Calculator PageSecurity PageSolutions PageStartups PageStatus PageStorefront PageSwitch PageTemplate Gallery PageTravel PageWaitlist PageYear in Review Page
Hooks & Utilities
AI ChatChart kitCommerceDate utilsFile exportFile typesFiltersForm validationHapticsInvoicingMotion presetsNavigationNumber formatRelative timeRomanian locationsSpreadsheetText matchTonesUIProvideruseClipboarduseConsentuseControllableStateuseCooldownuseDebounceuseKeyboardInsetuseLocaleuseLongPressuseMediaControlsuseMediaQueryuseOverflowItemsusePersistedStateuseScrollEdgesuseScrollStateuseSelectionuseShortcutuseStickToBottom
GalleryTheme

Mobile

Bottom Tab Bar

Mobile

Bottom Tab Bar React component for Tailwind CSS v4

Action SheetFAB
Live props
State
currentPath
Appearance
variant
indicator
showLabels
size
tone
color
badgeTone
Content
badgeLabel
dotLabel
aria-label
Behavior
hideOnScroll
haptics
scrollToTopOnReselect
Layout
position
safeArea
Code
import { BottomTabBar } from "@/components/ui/bottom-tab-bar"

<BottomTabBar />
  1. Home
  2. Components
  3. Mobile
  4. Bottom Tab Bar
Pro

Bottom Tab Bar React component for Tailwind CSS v4

v1.0.0·Added in 1.0.0

A React bottom tab bar for phones: 3 to 5 tabs at the thumb with an animated pill, badges, a raised center action and hide on scroll.

Tap a tab and the pill glides to it on a quick spring while the icon pops and swaps to its filled version; the icon dips while your finger is down. Tap the tab you are already on to scroll its page back to the top, or, on a nested page, to go back to the tab's first screen. The raised center button presses like a button and runs its action. Counts and dots sit on the icons and bounce in when they change. With hideOnScroll the bar follows your finger down out of view and comes back as soon as you scroll up or reach the end. On a keyboard Tab reaches every tab, ArrowLeft / ArrowRight move between them, Home / End jump to the first and last, Enter opens; the bar never hides while keyboard focus is inside it. On a phone it clears the home indicator (safe area) and every tab is far bigger than 44px. Under reduced motion the pill jumps and nothing pops.

Bottom Tab Bar is a Pro React component in the React mobile components category, written in TypeScript for React 19 and Tailwind CSS v4. It installs as source with npx wingo-ui@latest add bottom-tab-bar, together with Badge, useControllableState, useScrollState, Motion presets, Navigation and 2 more and the npm package motion.

Add to a project

Requirements: React 19 and Tailwind CSS v4, in Next.js (App Router or Pages), Vite or React Router. Installation guide · Next.js setup · Vite setup

npx wingo-ui@latest add bottom-tab-bar

Bottom Tab Bar is part of Pro, with 298 more Pro items: $8 a month or $150 once. 14-day refund before you download any Pro item. See plans

Usage

Import BottomTabBar from @/components/ui/bottom-tab-bar.

"use client"

import { House, Inbox, Plus, UserRound, Users } from "lucide-react"
import { BottomTabBar, type BottomTabBarItem } from "@/components/ui/bottom-tab-bar"

const tabs: BottomTabBarItem[] = [
  { label: "Home", href: "/", icon: <House />, activeIcon: <House className="fill-current" /> },
  { label: "Clients", href: "/clients", icon: <Users />, activeIcon: <Users className="fill-current" /> },
  { label: "Inbox", href: "/inbox", icon: <Inbox />, badge: 4 },
  { label: "Profile", href: "/profile", icon: <UserRound />, activeIcon: <UserRound className="fill-current" /> },
]

export function MobileNav({ onCreate }: { onCreate: () => void }) {
  return (
    <BottomTabBar
      className="md:hidden"
      items={tabs}
      action={{ label: "Add", icon: <Plus />, onSelect: onCreate }}
      hideOnScroll
    />
  )
}

Props

  • items*
    BottomTabBarItem[]

    3 to 5 tabs (a dev warning above 5). The shared NavItem shape: id, label, href, icon, activeIcon (shown while active, e.g. a filled glyph), badge (a number is a count, a node renders as is), disabled, match, onSelect; plus dot: true for an 8px dot instead of a count. Items without href are buttons.

  • value
    string

    The active tab's key (navItemKey: id, else href, else the label). Controls the bar.

  • defaultValue
    string

    The first active tab while uncontrolled and no current path is known. Default: the first enabled tab.

  • onValueChange
    (key: string, item: BottomTabBarItem) => void

    Fires whenever another tab is activated, in every mode (controlled, router, uncontrolled).

  • currentPathdefault ""
    string

    The current pathname. Empty: the LinkProvider's. With a path the router decides the active tab (the longest matching href) and clicks store nothing. Try /inbox or /clients/northwind-tech.

  • action
    { label: string; icon: ReactNode; onSelect?: () => void; href?: string }

    The raised center button (Add, Compose, Scan), placed in the middle of the tabs (with 4 tabs: 2, action, 2). label becomes its aria-label; filled with the tone.

  • variantdefault "bar"
    "bar" | "floating"

    bar: full width on the bottom edge with a glass surface and a hairline (iOS). floating: an inset glass pill above the safe area (iOS 26), the pill indicator behind the whole tab.

  • indicatordefault "pill"
    "pill" | "line" | "dot" | "none"

    pill: a 56x32 tinted pill behind the icon (Material 3). line: a 2px bar on the top edge of the tab. dot: a 4px dot under the label. none: color only. Every one moves between tabs on a snappy spring.

  • showLabelsdefault "always"
    "always" | "active" | "never"

    active: only the active tab shows its label and the others center their icon. never: icons only; the labels stay for screen readers and as tooltips.

  • sizedefault "md"
    "sm" | "md"

    Bar height 56 / 64px, icons 22 / 24px, labels 10 / 11px. Both stay far above 44px targets.

  • tonedefault "neutral"
    "neutral" | "brand" | "success" | "warning" | "danger" | "info"

    The active color (neutral: the foreground, with a gray pill) and the fill of the center action. Other tones tint the pill and the active label.

  • colordefault ""
    string

    Any CSS color. Replaces the tone for the active tab and the action. Leave empty to use the tone.

  • badgeTonedefault "danger"
    "neutral" | "brand" | "success" | "warning" | "danger" | "info"

    The fill of count badges and dots. Red by default: on every platform people read a red count as unread.

  • badgeLabeldefault "unread"
    string

    Read by screen readers after a count: "Inbox, 4 unread". The visible badge is hidden from them.

  • dotLabeldefault "new"
    string

    Read by screen readers after a dot: "Profile, new".

  • aria-labeldefault "Primary"
    string

    The name of the <nav> landmark.

  • hideOnScrolldefault false
    boolean

    Slides down while you scroll down, following the finger, and comes back on scroll up, at the end of the content and whenever focus is inside. Transform only, no re-render per frame.

  • positiondefault "auto"
    "auto" | "fixed" | "sticky" | "static"

    auto: fixed to the viewport, or static inside an app shell whose content column scrolls. sticky: sticky bottom-0 as the last child of a scroll container (phone frames, demos). static: in the flow. Writes --bottom-bar-offset (on <html> when fixed, else on its parent) so floating buttons clear it.

  • safeAreadefault true
    boolean

    Pads env(safe-area-inset-bottom) so the tabs clear the iPhone home indicator (the floating pill keeps at least 12px). It is 0 in desktop browsers.

  • hapticsdefault true
    boolean

    A 10ms vibration on a tab change where the browser supports it (Android; iOS ignores it).

  • scrollToTopOnReselectdefault true
    boolean

    Tapping the active tab scrolls its page to the top (iOS). On a nested page the tab first goes back to its root.

  • onReselect
    (item: BottomTabBarItem) => void

    Runs when the active tab is tapped again (refresh a feed, focus a search).

  • scrollTarget
    HTMLElement | Window | RefObject<HTMLElement | null> | null

    What scrolls, for hide on scroll and reselect. Default: the nearest ScrollContainerProvider, else the window.

  • linkComponent
    (props: LinkComponentProps) => ReactNode

    The router link for this bar only (a component, or "a"). Usually set once for the app with LinkProvider.

  • classNames
    Partial<Record<"inner" | "list" | "link" | "icon" | "label" | "indicator" | "action", string>>

    Extra classes for the inner parts: the bar surface, the list, each tab link, icon box, label, the indicator and the action.

  • className
    string

    Extra classes for the <nav>, merged last. Set [--bar-bg:var(--surface)] when the bar sits on a surface other than the page.

Parts

  • BottomTabBarItem

    type

    One tab: the shared navigation item (label, href, icon, activeIcon, badge, disabled and the rest of NavItem) plus dot, an 8px dot in place of a count.

  • BottomTabBarAction

    type

    The raised center button (compose, add, scan): { label, icon, onSelect?, href? }.

Examples

Floating

variant="floating": an inset glass pill over a photo feed.

Indicators

pill, line, dot or color only; each moves between tabs on a snappy spring.

Labels

Always, only on the active tab, or never (kept for screen readers).

Hide on scroll

The bar follows your finger out of view and returns on scroll up.

Three to five tabs

Three tabs without an action; four and five tabs around a raised center action.

Live badges

Counts bounce when they change and read as "Inbox, 5 unread".

Brand marketplace

tone="brand" with the line indicator and a camera action.

Dependencies

motionbadgeuse-controllable-stateuse-scroll-statemotionnavigationtonesui-config

Files

  • components/ui/bottom-tab-bar.tsx

FAQ

Is the React Bottom Tab Bar component free?

The preview, props and docs are free; copying the source needs a Pro plan. See plans.

How do I install Bottom Tab Bar?

Run npx wingo-ui@latest add bottom-tab-bar. It also adds the Wingo UI items it builds on (Badge, useControllableState, useScrollState, Motion presets, Navigation and 2 more) and the npm package motion. With shadcn, add the @wingo-ui registry with your API key, then run npx shadcn@latest add @wingo-ui/bottom-tab-bar.

How does Bottom Tab Bar behave on phones?

On a phone it clears the home indicator (safe area) and every tab is far bigger than 44px.

See also

TopbarLarge Title HeaderGooey NavBadgeNavigationlibuseScrollStatehook

Used in

Mobile App HomeApp ShellAdmin ShellMarketplace Shell

More React mobile components

Sticky CTA BarSlide To ConfirmAction SheetFABHaptic ButtonInstall Prompt
All 15 React mobile components

Articles using this component

  • Konsta UI Alternative for React: Ionic vs Wingo UI

    Comparisons and alternatives · Nov 6, 2026 · 10 min read

  • Nextjs PWA Without next-pwa: Offline Page and App Shell

    Mobile UI in React · Nov 5, 2026 · 12 min read

  • Shadcn Sidebar Mobile: Fix the Sheet and Add a Tab Bar

    Mobile UI in React · Nov 5, 2026 · 9 min read

  • React Floating Action Button: Speed Dial and Safe Areas

    Mobile UI in React · Oct 16, 2026 · 9 min read

PreviousAction SheetNext FAB
9:41

Hi, Anna

Tuesday, Sep 23, 2026

Collected in September

$48,920.00

+12% vs August

To collect

$12,480

Open quotes

12

Recent activity

  • Payment receivedNorthwind Tech Inc. · #2026-0412$12,480
  • Invoice issuedKeystone Construction · #2026-0415$27,600
  • Quote acceptedSummit Logistics · #Q-2026-118$8,216
  • New clientBistro 21 · New York
  • Payment receivedGreenleaf Pharmacy · #2026-0409$3,940
  • Invoice issuedOld Mill Bakery · #2026-0414$1,150
  • Quote sentStudio Pixel · #Q-2026-121$2,100
  • Payment receivedNorth Studio LLC · #2026-0401$5,300
  • Invoice issuedWestside Books · #2026-0413$640
  • New clientGreen House Realty · Phoenix
  • Home
  • Clients
  • 4Inbox
  • Profile
/tap a tabautohide offreselect → tophaptics onsafe area on