Liquid tab bar
A liquid glass tab bar with a stretchy selection lens and a detached search button.
Loading component source...
Installation
pnpm dlx shadcn@latest add mox/mox-ui/liquid-tab-barRun this command from your project directory to add the component and its dependencies.
- 1
Install the packages
pnpm add motion clsx tailwind-merge - 2
Add the utility file
lib/utils.tsimport { clsx, type ClassValue } from "clsx";import { twMerge } from "tailwind-merge"; export function cn(...inputs: ClassValue[]) { return twMerge(clsx(inputs));} - 3
Copy and paste the code into your project
Loading source⦠- 4
Update the import paths to match your project
Point
@/lib/utilsto your utility file if your path aliases differ.
Usage
"use client"
import { LiquidTabBar } from "@/components/ui/liquid-tab-bar"
export function Demo() { return ( // hrefs make it track the url on its own, no value needed <LiquidTabBar items={[ { label: "Home", href: "/", icon: <HouseIcon /> }, { label: "Changelog", href: "/changelog", icon: <BookIcon /> }, { label: "About", href: "/about", icon: <InfoIcon /> }, ]} onSearch={(query) => setQuery(query)} /> )}Options
Pick a value to see the prop you would pass. Defaults are left out.
<LiquidTabBar />Props
| Prop | Type | Default | Description |
|---|---|---|---|
items* | (string | { label: string; href?: string; icon?: ReactNode })[] | Default: - | Tabs. An item with an icon shows only the icon and uses its label as the accessible name; an item with href is a link. |
value | number | Default: - | Index of the selected tab. Pass it to control the bar yourself; leave it out and the bar follows the url when the items have hrefs, and its own state otherwise. |
defaultValue | number | Default: 0 | Index the bar starts on when it is uncontrolled. Ignored once value is passed, and ignored when an item href matches the current url. |
onChange | (index: number) => void | Default: - | Fires with the index of the tab that was clicked. |
size | "xs" | "sm" | "md" | "lg" | Default: "md" | Scale of the bar. Sets the tab padding and icon size, and the search button follows it. |
activeColor | string | Default: "#0A84FF" | Color of the selected tab's icon or label. |
onSearch | (query: string) => void | Default: - | Shows the detached search button. Fires with the query as it is typed, and with an empty string when the search closes. Leave it out to hide search. |
searchLabel | string | Default: "Search" | Placeholder and accessible name of the search field and its button. |
closeLabel | string | Default: "Close search" | Accessible name of the button while search is open. |
className | string | Default: - | Extra classes merged onto the root element (data-slot="liquid-tab-bar"). The bar sizes to its content and never wraps. |
Click a tab and the glass lens slides to it, stretching on the way like liquid. The search button beside the bar opens a search field and turns into a close button; Escape closes it too.
Credits and license
Most components here are recreations of great work from around the web. I don't claim to be the original creator - this is my attempt to reverse-engineer, replicate, and often add a few extra features. I've tried to credit everyone; if I missed someone, let me know.
- Free to use and modify in both personal and commercial projects.
- Attribution to Mox UI is appreciated when using a component.
- Please don't resell the components as your own kit.