website-glass
Components

Glass Dock

A liquid-glass bottom-nav dock — a refracting glass bar with a selection pill you can tap or drag between items; the pill lifts into a glass lens with velocity gel as it travels, then settles at the nearest item.

Playground

Edit the props live and copy the config.

Radius
20
Refraction
0.28
Frost
0.3
Labels
Search
Accent
<GlassDock
  items={items}
  radius={20}
  strength={0.28}
  frost={0.3}
  showLabels={true}
  search
  accent="#38bdf8"
/>

Install

npx shadcn@latest add https://websiteglass.com/r/glass-dock.json

Usage

import { GlassDock } from '@/components/ui/glass-dock';
import { House, LayoutGrid, BarChart3, Settings } from 'lucide-react';

const items = [
  { value: 'home', label: 'Home', icon: <House className="size-full" /> },
  { value: 'dash', label: 'Dashboard', icon: <LayoutGrid className="size-full" /> },
  { value: 'stats', label: 'Analytics', icon: <BarChart3 className="size-full" /> },
  { value: 'settings', label: 'Settings', icon: <Settings className="size-full" /> },
];

<GlassDock items={items} value={tab} onValueChange={setTab} />

Props

GlassDock

PropTypeDefaultDescription
itemsDockItem[]requiredThe nav items.
valuestringControlled active item value.
defaultValuestringfirst itemInitial active value when uncontrolled.
onValueChange(v: string) => voidFires when the selection changes.
radiusnumber20Bar corner radius in px. Large values (e.g. 9999) make a fully-round pill bar.
pillRadiusnumberradius - 7Selection-pill / item corner radius in px.
strengthnumber0.28Refraction strength of the bar (0–1).
frostnumber0.3Frostiness (0 = clear, 1 = fully frosted) — drives tint + blur.
tintnumberfrom frostOverride tint alpha (0–1).
blurnumberfrom frostOverride backdrop blur in px.
accentstring#38bdf8Accent colour for the active item.
showLabelsbooleantrueShow text labels under each icon; false = compact icon-only.
searchbooleanfalseAdd a detached search button; tapping it wipes a clear-refraction search field over the dock (the items fade out so nothing shows through), with a × to close.
onSearchChange(q: string) => voidFires as the search query changes.
searchPlaceholderstring"Search"Placeholder for the expanded search field.
accessoryReactNodeExtra detached buttons rendered after the bar (e.g. a GlassDockButton).

Every visual knob is a prop — radius, pillRadius, strength, frost, tint, blur, and accent — so the whole look is driven from props, nothing hardcoded.

DockItem

FieldTypeDescription
valuestringUnique value for the item.
labelstringText label under the icon.
iconReactNodeThe icon.

Detached buttons

Besides the built-in expanding search, the registry also exports GlassDockButton — a standalone detached glass button that matches the dock. It is a plain action button (fires onClick), not an expand — icon-only, and a perfect circle at a large radius. Use it on its own, or via the dock's accessory slot where it auto-matches the bar height:

import { GlassDock, GlassDockButton } from '@/components/ui/glass-dock';
import { Plus } from 'lucide-react';

// via the accessory slot (matches the bar height automatically)
<GlassDock
  items={items}
  value={tab}
  onValueChange={setTab}
  accessory={<GlassDockButton icon={<Plus className="size-full" />} onClick={createTask} />}
/>

// or standalone, with an explicit size
<GlassDockButton icon={<Plus className="size-full" />} size={56} radius={9999} onClick={createTask} />

GlassDockButton

PropTypeDefaultDescription
iconReactNoderequiredThe icon (icon-only, no text label).
sizenumberFixed square size in px. Omit to stretch to a sibling dock's height.
radiusnumber20Corner radius in px. Large values (e.g. 9999) make it a circle.
strengthnumber0.28Refraction strength (0–1).
frostnumber0.3Frostiness — drives tint + blur.
tint / blurnumberfrom frostOverride tint alpha / backdrop blur.

All native <button> props are forwarded. Pass matching radius/frost to keep it visually in step with a customised dock.

Interaction

The bar is a real refracting glass surface (it bends the content behind it via the lens engine on Chromium; frosted fallback elsewhere). The active item wears a soft pill. Tap another item and the pill springs to it; grab and drag the pill and it lifts into a glass lens with velocity-driven gel, tracking the item beneath it, then settles into a pill at the nearest item on release.