liquefy-ui
uiglass-docksource: ok · hit
GlassDock
A macOS-style dock: a glass rail of icon buttons that magnify under the pointer.
npx shadcn add "https://liquefy-ui.com/r/glass-dock.json"free
Visual style
glass-blur
Tags auto-generated by rules on 9/24/2026 — empty means no evidence, not lack of support.
Dependencies
Bundle weight · lightRegistry dependencies
https://liquefy-ui.com/r/liquefy-ui.jsonhttps://liquefy-ui.com/r/liquid-surface.jsonhttps://liquefy-ui.com/r/styles-prop.json
Files1 · source cached 10/15/2026, 5:46:10 AM
registry/glass-dock.tsx
'use client'
import {
Children,
forwardRef,
isValidElement,
type ButtonHTMLAttributes,
type CSSProperties,
type HTMLAttributes,
type ReactNode,
} from 'react'
import { LiquidSurface } from '@/components/ui/liquid-surface'
import { useLiquidStyles, type LiquidStyleProps } from '@/lib/styles-prop'
export type GlassDockProps = HTMLAttributes<HTMLElement> & LiquidStyleProps & {
children: ReactNode
label?: string
position?: 'inline' | 'floating'
}
export const GlassDock = forwardRef<HTMLElement, GlassDockProps>(({
children,
className,
label = 'Primary navigation',
position = 'inline',
style,
styles,
...props
}, ref) => {
const items = Children.toArray(children)
const activeIndex = items.findIndex((child) => {
return isValidElement<DockItemProps>(child) && child.props.active
})
const dockStyle = {
'--lq-dock-active-index': Math.max(0, activeIndex),
'--lq-dock-item-count': items.length,
} as CSSProperties
// The shell is the layout box; the glass bar inside keeps its own geometry.
const root = useLiquidStyles('lq-dock-shell', { className, style, styles })
return (
<nav
aria-label={label}
className={root.className}
data-position={position}
ref={ref}
style={root.style}
{...props}
>
<LiquidSurface className="lq-dock" radius="18px" style={dockStyle}>
<span aria-hidden="true" className="lq-dock__indicator" data-visible={activeIndex >= 0} />
{items}
</LiquidSurface>
</nav>
)
})
GlassDock.displayName = 'GlassDock'
export type DockItemProps = ButtonHTMLAttributes<HTMLButtonElement> & LiquidStyleProps & {
active?: boolean
icon: ReactNode
label: string
}
export const DockItem = forwardRef<HTMLButtonElement, DockItemProps>(({
active = false,
className,
icon,
label,
style,
styles,
...props
}, ref) => {
const root = useLiquidStyles('lq-dock__item', { className, style, styles })
return (
<button
aria-current={active ? 'page' : undefined}
aria-label={label}
className={root.className}
data-active={active}
ref={ref}
style={root.style}
title={label}
type="button"
{...props}
>
{icon}
</button>
)
})
DockItem.displayName = 'DockItem'