Skip to content
shadcn.io

shadcn.io is not affiliated with official shadcn/ui

Tabs Underline Navbar Block for React

A navbar for a financial reporting tool built as cells: the wordmark in its own cell, full-height report tabs whose 2 px mark sits on the bar's bottom edge and slides on selection, and an Export action, with arrow-key navigation and a scrolling tab row on phones.

Framework
UI library

Preview

Preview width

Installation

Part of Pro
Pro unlocks the code and one-line install of every Pro button and text effect, plus the MCP for your AI editor.
Have Pro already? Sign in to open it.Opens here as soon as you're Pro.

Overview

A navbar for React with Base UI that works like a row of tabs. Three cells sit on the spine's top rule, divided by hairlines that meet it with + marks: the wordmark, six report tabs (Overview, Revenue, Expenses, Cash flow, Forecasts and Audit log) and an Export Shine Button. The tabs fill the bar's whole height, and the current tab's mark is a 2 px stroke that sits exactly on the bar's bottom edge, over the next block's top rule, as if the page hung from it. Choose another tab and the stroke slides there, sized to the tab: its inline start and width come from the tab's measured box (measured again whenever the row resizes), so it works in right-to-left pages, and the first position is set without a transition. The tabs are links in a single tab stop: Tab enters on the current tab, the arrow keys, Home and End move focus along the row (reversed in right-to-left pages) and Enter chooses. On a phone the wordmark shrinks to its icon, Export to an icon, and the tab row scrolls inside the bar with soft edges and the current tab brought into view. The bar is 56 pixels high and draws no bottom border. It's built from Guides and Shine Button, with your theme's tokens for every colour. For dashboards and report viewers where the bar is also the page's tab strip. It isn't an ARIA tablist: the tabs are navigation links, with aria-current="page" on the current one.

FAQ

How do I change the tabs?

Edit TABS at the top of the file: each entry is an id, a label and an href, and useState("revenue") sets the first current tab. The demo's links point at # and choosing one calls preventDefault; with a real router, delete the onClick handler and compute active from the current path.

Why does the stroke sit on the next block's top rule?

The stroke is placed one pixel below the bar's bottom edge and given z-10, so it paints over the hairline that the next block draws as its top rule instead of next to it: the tab and the page rule meet. On a phone the row scrolls, which clips anything outside it, so the stroke sits just inside the bar's bottom edge instead. If you stack something under the bar that draws its own top border, the stroke covers it only under the current tab.

How does it work with a keyboard and a screen reader?

The tabs are links in a nav landmark named Main. Only one is in the tab order at a time (a roving tab stop): Tab goes from the wordmark to the current tab and then to Export. Left and Right move focus between tabs (swapped in right-to-left pages), wrapping at the ends, and Home and End jump to the first and last; focus moves but nothing is chosen until Enter, so a screen reader user can browse the tabs without navigating. The current tab is announced as the current page. The mark is decorative and hidden.

How does it work on a phone?

Below the sm breakpoint the wordmark is just its icon and Export is a download icon (its text stays in the accessible name), leaving the bar to the tabs. The tab row scrolls sideways inside the bar with a soft fade at each edge, and the current tab is scrolled to the middle when the page loads and when you choose another; the scrollbar is hidden. From md the row doesn't scroll. Export renders the link it's given with render, with nativeButton={false}.

What happens with reduced motion?

With reduced motion the stroke jumps to the chosen tab at once and the row scrolls instantly instead of smoothly. The band of light on Export fades in where it stands instead of sweeping.

How does it sit on the page, and can it stick to the top?

The navbar is the page's first block: its + marks and rails line up with every block under it, and it draws no bottom border. To keep it in view while the page scrolls, add sticky top-0 z-40 bg-background/80 backdrop-blur to the header; give it an opaque bg-background if you want the stroke to stay legible over content.

  • Pro

    A one-bar navbar for a design studio whose links draw a hairline underline in from the inline start on hover and focus and retract it toward the end, with the current page keeping its full line, using nothing but a CSS transform.

  • Pro

    Pill Links Navbar

    Link highlights

    A navbar for a sprint-planning app where the current page is a pill that slides to whichever link you choose, with the links and a Shine Button grouped at the end and hover only tinting.

  • Pro

    A navbar for a meal-planning app that centres its three destinations in a tray of equal segments, each an icon, a label and a count, with one raised thumb that slides under the current one and folds to icons on a phone.

  • Pro

    Scroll Spy Navbar

    Link highlights

    A navbar whose current link follows the section in view in a framed scrolling page preview, with a 1-pixel stroke that slides to it and links that scroll to their section.

  • Pro

    A segmented control in a slim bar whose choice rewrites a one-line summary beside it.

  • Pro

    Gradient Border Navbar

    Link highlights

    A navbar with a soft hairline glint on the page rule under the current link, fainter on hover and focus, with no border added and nothing that moves, and a sheet menu on phones.