Liquid glass button
Free · MITFrosted glass button and pill toolbar with backdrop blur, rim light and a specular highlight that follows the pointer, falling back to a solid tint without backdrop-filter.
Installation
$ npx shadcn@latest add https://goodui.dev/r/liquid-glass-button.jsonThe file lands in components/goodui/liquid-glass-button.tsx and is yours to edit. With the @goodui registry added, npx shadcn@latest add @goodui/liquid-glass-button works too.
Usage
import { CalendarDays, LayoutList, Map } from "lucide-react"
import { LiquidGlassToolbar, LiquidGlassToolbarItem } from "@/components/goodui/liquid-glass-button"
export function ViewSwitcher({ view, onViewChange }: { view: string; onViewChange: (v: string) => void }) {
return (
<LiquidGlassToolbar value={view} onValueChange={onViewChange} aria-label="Bookings view">
<LiquidGlassToolbarItem value="list" compact>
<LayoutList />
<span>List</span>
</LiquidGlassToolbarItem>
<LiquidGlassToolbarItem value="calendar" compact>
<CalendarDays />
<span>Calendar</span>
</LiquidGlassToolbarItem>
<LiquidGlassToolbarItem value="map" compact>
<Map />
<span>Map</span>
</LiquidGlassToolbarItem>
</LiquidGlassToolbar>
)
}When to use
- Controls floating over photos, maps, video or colorful gradients, where a solid button would cover the content.
- A floating view switcher (List / Calendar / Map) over a busy screen: LiquidGlassToolbar with a gliding lens.
- Hero sections with an aurora or image background that call for an iOS-style glass look.
- On a plain white or dark page: glass has nothing to blur and looks washed out. Use button (variant="glass" if you still want the look on a tinted card).
- Switching views in a normal app header: use segmented-control or tabs-indicator, which have proper tab semantics.
- Long-lived app navigation on mobile: use bottom-nav.
| If you need | Use |
|---|---|
| Over bright or colorful backdrops | tone="light" (default) |
| Over dark photos or night scenes | tone="dark" |
| Single action | LiquidGlassButton |
| Pick one view of several | LiquidGlassToolbar + LiquidGlassToolbarItem |
| Text labels hidden on phones | compact on each item, with the text wrapped in a <span> |
| Preview the no-blur fallback | fallback |
Examples
Single glass button over a photo
<div className="relative h-64 overflow-hidden rounded-2xl bg-[url(/salon.jpg)] bg-cover">
<LiquidGlassButton size="lg" className="absolute start-4 bottom-4">
Book this stylist
</LiquidGlassButton>
</div>Dark tone icon button
<LiquidGlassButton tone="dark" size="icon" aria-label="Share">
<Share2 />
</LiquidGlassButton>API reference
LiquidGlassButton
| Prop | Type | Default |
|---|---|---|
| tone "light" is a white tint for colorful or bright backdrops; "dark" a smoky tint. | "light" | "dark" | "light" |
| blur Backdrop blur in px. | number | 14 |
| fallback Force the no-backdrop-filter look (to preview the fallback). | boolean | — |
| size "sm" | "md" | "lg" | "icon"; "icon" is a round 44px button. | "sm" | "md" | "lg" | "icon" | "md" |
Also accepts every <button> attribute.
LiquidGlassToolbar
| Prop | Type | Default |
|---|---|---|
| tone "light" is a white tint for colorful or bright backdrops; "dark" a smoky tint. | "light" | "dark" | "light" |
| blur Backdrop blur in px. | number | 16 |
| fallback Force the no-backdrop-filter look (to preview the fallback). | boolean | — |
| value Controlled selected item (the item's value). | string | — |
| defaultValue Initially selected item when uncontrolled. | string | — |
| onValueChange Called with the item's value when an item is clicked. | (value: string) => void | — |
Also accepts every <div> attribute.
LiquidGlassToolbarItem
| Prop | Type | Default |
|---|---|---|
| value* Identifies the item; when it matches the toolbar's value the item is selected (aria-pressed). | string | — |
| compact Hide the text label on small screens and keep only the icon. | boolean | — |
Also accepts every <button> attribute.
Accessibility
| Enter / Space | Activates a button or selects a toolbar item (native <button>). |
| Arrow Left / Arrow Right | Toolbar: moves focus to the previous or next enabled item, wrapping at the ends (swapped under dir="rtl"). |
| Home / End | Toolbar: moves focus to the first or last enabled item. |
| Tab | Toolbar: only the selected item is in the tab order (all items when nothing is selected). |
- LiquidGlassToolbar has role="toolbar" and aria-orientation="horizontal"; give it an aria-label.
- Toolbar items are <button>s with aria-pressed showing the selected one.
- Text is white with a soft shadow; on very light backdrops check legibility, or use fallback, which (in the light tone) puts dark text on a near-opaque white tint.
- Browsers without backdrop-filter automatically get the solid fallback tint.
Motion
- Button: hover scales to 1.03, press to 0.95, on a spring (stiffness 500, damping 26).
- A specular highlight follows the pointer through CSS variables and brightens on hover over 0.35 s.
- Toolbar: the selected lens glides between items with a shared layout animation (spring, stiffness 420, damping 32).
- Reduced motion: no hover or press scale, the lens jumps instead of gliding, and the highlight changes without a transition.
- The highlight writes CSS variables on pointer move, so it never re-renders React. backdrop-filter costs GPU time; avoid dozens of glass elements over video.
Notes for AI
Coding agents read these rules through MCP and llms.txt, or paste this page with Copy page.
- Place it over something worth blurring (image, gradient, aurora); on a flat background it looks like a washed-out button.
- Toolbar items need a unique value; control the toolbar with value/onValueChange or set defaultValue.
- compact hides a <span> child of the item below the sm breakpoint, so wrap the text label in <span> and keep the icon outside it.
- Sizes are sm, md, lg, icon; tone is light or dark. The glass button is always fully rounded.
- Icon-only items and buttons need an aria-label.
FAQ
What happens in browsers without backdrop-filter?
An @supports rule switches to a near-opaque white (light tone) or smoky (dark tone) tint with readable text. Pass fallback to preview it anywhere.
Is the toolbar a tab list?
No. It is a toolbar of toggle buttons (aria-pressed). For tab panels, use tabs or tabs-indicator.
Related
iOS-style segmented control whose thumb springs to the chosen segment and squeezes while pressed, with sizes, icons, full-width mode, dividers that hide next to the thumb, and radio-group arrow keys.
One button with ten variants, six tones, seven shadows, ten animations, three shapes and five sizes that all combine, plus loading and icon slots.
Soft colored light drifts slowly behind a section, with light and dark palettes and only transform animations for low CPU.
macOS-style dock whose tiles magnify on a spring as the pointer nears, with tooltips, running dots, badges and a launch bounce, falling back to a simple press scale on touch.