Chuyển tới nội dung
Component

BottomNav

The tab bar fixed to the bottom of the screen below md, with 3 to 5 top-level destinations. It is separate from Sidebar: no shared item list; an app that has both renders its own items in each. The bar adds spacing-safe-bottom to its own bottom padding, which reads the safe area and falls back to 0px. The page viewport needs viewport-fit=cover.

Xem trước

Your workspace

Choose a destination below.

Props

  • count
  • destinations
  • badges
import { useState, type MouseEvent } from "react"
import { IconHome, IconHomeFilled, IconInbox, IconSearch } from "@tabler/icons-react"
import { BottomNav, BottomNavItem } from "@/components/ui/bottom-nav"

const [destination, setDestination] = useState("#home")
const selectDestination = (event: MouseEvent<HTMLAnchorElement>) => { event.preventDefault(); setDestination(event.currentTarget.getAttribute("href") ?? "#home") }

<div className="w-80 max-w-full overflow-hidden rounded-container border border-border bg-background-surface">
  <div className="flex flex-col gap-xs p-lg">
    <p className="text-sm font-medium">Your workspace</p>
    <p className="text-xs text-text-secondary">Choose a destination below.</p>
  </div>
  <BottomNav label="Main" value={destination} className="relative md:block">
    <BottomNavItem href="#home" label="Home" icon={<IconHome size={20} />} activeIcon={<IconHomeFilled size={20} />} onClick={selectDestination} />
    <BottomNavItem href="#search" label="Search" icon={<IconSearch size={20} />} onClick={selectDestination} />
    <BottomNavItem href="#inbox" label="Inbox" icon={<IconInbox size={20} />} count={3} onClick={selectDestination} />
  </BottomNav>
</div>

Cách dùng

Khi nào dùng

  • Show a short list of top-level destinations at the bottom of a small screen.

Khi nào không dùng

  • Put actions such as Create or Share in the navigation. Use Button.
  • Show the same bar next to a visible Sidebar.

Ví dụ

Three destinations

import { IconHome, IconHomeFilled, IconInbox, IconSearch } from "@tabler/icons-react"
import { BottomNav, BottomNavItem } from "@/components/ui/bottom-nav"

<BottomNav label="Main" className="relative md:block">
  <BottomNavItem href="#home" icon={<IconHome size={20} />} label="Home" activeIcon={<IconHomeFilled size={20} />} active />
  <BottomNavItem href="#search" icon={<IconSearch size={20} />} label="Search" />
  <BottomNavItem href="#inbox" icon={<IconInbox size={20} />} label="Inbox" count={3} />
</BottomNav>

Five destinations

import { IconHome, IconHomeFilled, IconInbox, IconLayoutGrid, IconSearch, IconUser } from "@tabler/icons-react"
import { BottomNav, BottomNavItem } from "@/components/ui/bottom-nav"

<BottomNav label="Main" className="relative md:block">
  <BottomNavItem href="#home" icon={<IconHome size={20} />} label="Home" activeIcon={<IconHomeFilled size={20} />} active />
  <BottomNavItem href="#search" icon={<IconSearch size={20} />} label="Search" />
  <BottomNavItem href="#inbox" icon={<IconInbox size={20} />} label="Inbox" count={3} />
  <BottomNavItem href="#projects" icon={<IconLayoutGrid size={20} />} label="Projects" />
  <BottomNavItem href="#profile" icon={<IconUser size={20} />} label="Profile" />
</BottomNav>

Current route

import { IconHome, IconHomeFilled, IconInbox, IconLayoutGrid, IconSearch } from "@tabler/icons-react"
import { BottomNav, BottomNavItem } from "@/components/ui/bottom-nav"

<BottomNav label="Main" value="#inbox" className="relative md:block">
  <BottomNavItem href="#home" icon={<IconHome size={20} />} label="Home" activeIcon={<IconHomeFilled size={20} />} />
  <BottomNavItem href="#search" icon={<IconSearch size={20} />} label="Search" />
  <BottomNavItem href="#inbox" icon={<IconInbox size={20} />} label="Inbox" count={3} />
  <BottomNavItem href="#projects" icon={<IconLayoutGrid size={20} />} label="Projects" />
</BottomNav>
import { IconHome, IconHomeFilled, IconInbox, IconSearch } from "@tabler/icons-react"
import { BottomNav, BottomNavItem } from "@/components/ui/bottom-nav"

<BottomNav label="Main" className="relative md:block">
  <BottomNavItem href="#home" icon={<IconHome size={20} />} label="Home" activeIcon={<IconHomeFilled size={20} />} active asChild>
    <a href="#home">Home</a>
  </BottomNavItem>
  <BottomNavItem href="#search" icon={<IconSearch size={20} />} label="Search" asChild>
    <a href="#search">Search</a>
  </BottomNavItem>
  <BottomNavItem href="#inbox" icon={<IconInbox size={20} />} label="Inbox" asChild>
    <a href="#inbox">Inbox</a>
  </BottomNavItem>
</BottomNav>

Nên và không nên

Nên

  • Use 3 to 5 destinations with short labels.
  • Pad page content so the bar never covers the last row.
  • In these embedded demos, relative md:block keeps the bar inside its cell and visible on desktop. Omit those demo classes for a fixed mobile bar in an application.
  • Use the current route as value, or set active on one item. The component does not own navigation state.

Không nên

  • Do not put actions (Create, Share) in the bar; use a Button.
  • Do not show it next to an open Sidebar.

Props

TênKiểuGiá trịMặc địnhMô tả
labelstring-MainOn BottomNav: accessible name of the navigation landmark. On BottomNavItem: visible destination text and accessible name.
countLabel(label: string, count: number) => string--Names an item that shows a count, replacing its accessible name: (label, count) => `{label}, {count} new` by default. Vietnamese: `{label}, {count} mục mới`. Optional.
valuestring--On BottomNav: active destination href, usually supplied by the application router. Takes precedence over item active props. BottomNav does not change it on click.
href bắt buộcstring--On BottomNavItem: destination URL and selection id. Required even with asChild.
icon bắt buộcnode--On BottomNavItem: the regular 20px icon.
activeIconnode--On BottomNavItem: optional icon for the active state, such as a Filled Tabler icon.
activeboolean-falseOn BottomNavItem: marks this destination current when BottomNav has no value. Selection still uses normal link navigation.
countnumber--On BottomNavItem: a count above zero adds a badge and names the count through countLabel. Zero and negative counts are hidden.
asChildboolean-falseOn BottomNavItem: render the destination link behavior on its only child.
onClickReact.MouseEventHandler<HTMLAnchorElement>--On BottomNavItem: native link click handler. Use application navigation or preventDefault() for an in-place demonstration.

Slot

TênBắt buộcMô tả
childrencó3 to 5 BottomNavItem with href, icon, label, optional activeIcon, count and active.

Cấu tạo

PhầnMô tả
rootFixed bar on the material-thin surface, hidden from md up, with a safe-area inset.
itemOne destination link: 20px icon over a font-size-xs label, at least size-target-min tall.
iconThe 20px icon, with an optional activeIcon for its selected appearance.
labelThe item text.
badgeOptional count Badge on the icon.

Khả năng truy cập

Role: navigation

PhímHành động
TabMoves between destinations (links), in order.
EnterFollows the link.
  • A nav landmark named by label. Items are links, not tabs: no role tab and no arrow-key roving.
  • The active item has aria-current="page" and uses the Filled icon (DESIGN 9.1).
  • Every item shows a text label; icon-only bars are not allowed.
  • A count Badge adds its number to the accessible name, through countLabel.

Cài đặt

npx werewolf-ui add bottom-nav

Chạy npx werewolf-ui init một lần trong app trước khi thêm component. Init cài token, thêm CSS import và luật cho agent. Add cài component này cùng các dependency và giữ nguyên theme của bạn. Xem Cài đặt để biết yêu cầu và cách cài qua registry.