GlassPanel
Okami's liquid-glass material: it genuinely refracts the page behind it in Chrome, and frosts, tints and edge-lights everywhere else. The chat composer is a GlassPanel.
Playground
Crisp on top
import { GlassPanel } from "@/components/shared/glass-panel";
<GlassPanel>
<p className="px-5 py-3.5 text-sm">Crisp on top</p>
</GlassPanel>Composer
The chat's composer: a GlassPanel floating over the conversation. The panel is full width and carries no padding of its own — the row inside sets it, and a focus ring on a wrapper of the same radius (22px, rounded-3xl) shows where typing goes. This is what the Composer is built from — for the chat, use Composer itself.
import { GlassPanel } from "@/components/shared/glass-panel";
import { Button } from "@/components/shared/button";
<div className="focus-within:ring-ring rounded-3xl focus-within:ring-2">
<GlassPanel radius={22}>
<div className="flex items-end gap-2 py-1.5 pr-1.5 pl-4.5">
<textarea rows={1} placeholder="Type a message…" aria-label="Message" … />
<Button variant="primary" size="lg" iconOnly leadingIcon={ArrowUp} aria-label="Send" />
</div>
</GlassPanel>
</div>Repeated elements: frost
What repeats — message bubbles, chips, cards in a list — wears the CSS .aura-frost instead: white glass with a hairline edge, blurred but not bent.
Anything free on Friday?
After work, if you can.
<p className="aura-frost rounded-3xl rounded-br-md px-4 py-2.5 text-sm">
Anything free on Friday?
</p>Two materials: glass and the card
What you touch — fields, choices, tables and the secondary button — is made of the same frost, as Tailwind classes: GLASS from components/shared/surface.ts, each with its own hairline edge. What floats over the page — popovers, menus, dialogs, toasts — wears GLASS_FLOATING, the same glass thicker, so its words stay readable over anything. A card is CARD_FRAME: white with a hairline edge and an 8px inset, its title on the white; what it holds sits in CARD, one tint of ink (5%) with no edge, as do notices and the owner's own chat bubbles. New surfaces take one of these; none paints itself white otherwise.
import { CARD, GLASS } from "@/components/shared/surface";
<input className={cn("squircle-lg border border-ink/8", GLASS)} />
<div className={cn("squircle-2xl p-4", CARD)}>…</div>API reference
| Prop | Type | Default | Description |
|---|---|---|---|
| radius | number | 18 | Corner radius in px — the lens is shaped to it. Match any ring or wrapper around the panel. |
| lens | boolean | true | Refract the page through the liquid-glass lens. false keeps the panel — its tint, blur and lit edge — unbent, at the cost of plain CSS: for panels that repeat or sit over motion. |
| style | CSSProperties | — | Merged over the panel's own: full width, a white tint at 45%, the radius. |
| children | ReactNode | — | The crisp layer on top of the glass. Pad it here — the panel has no padding. |
Built on Glass from @samasante/liquid-glass. The panel always fills its container's width; size it with the wrapper.
Guidelines
- Chrome only: a composer, a floating panel, a piece of stage furniture. One or two per screen.
- Repeated elements (message bubbles, chips, cards in a list) use the CSS
.aura-frostclass instead — the SVG filter is too heavy to multiply. - One lens on screen at most, and never over something that moves: the lens re-runs its filter every frame anything under or in it changes. Seven on the landing's bento dropped half the frames; there the panels take
lens={false}. - Children render crisp on top; never put body text you must read into the refracted layer.