liquid-svelte

Liquid Glass components for Svelte 5. SVG displacement refraction, a generated specular rim, Motion springs. No canvas, no WebGL, no remote assets.

reduced motion: off · corner-shape: unsupported · optics probe · borders lab · scaling benchmark

The corner follows iOS: buttons, switches, sliders and tabs stay fully rounded, cards, panels and context menus get the continuous curve. Nothing here opts in per component — a capsule has no straight edge for a superellipse to meet, so the primitive demotes those to round on its own. Flipping this control to round everywhere therefore only changes the menu panels and the primitive tiles below; every pill and circle on the page is identical either way, which is the convention working rather than the control failing.

LiquidButton

Native <button>. Motion's press covers keyboard activation, so Space and Enter compress it exactly like a click. Tab to it and try.

shape="circle" is not a pill with equal padding: it is laid out at a literal diameter, so every circle of a size shares one rasterised map, and its rim is a fraction of that diameter rather than a per-size constant — a circle's radius is half its size, so a fixed bezel would turn the whole disc into rim and the glyph would sit in continuous distortion.

A circle is the one shape in the library where geometry cannot pick the corner: its box is square and its radius saturates, so round gives a circle and squircle gives the app-icon superellipse — both real, and iOS uses both for different things. LiquidButton pins its circles to round, because an iOS circular button is a circle; cornerShape="squircle" opts into the icon shape. The 150×150 tile at the bottom of the page is that shape.

presses: 0

LiquidSwitch

Drag the droplet — don't just tap it. At rest the thumb is an opaque knob; grabbing it melts it into refracting glass that swells and deforms as it crosses, then snaps to whichever end you threw it towards. A flick beats position. Tapping still toggles, Escape abandons a drag, and role="switch" means it announces as “switch, on”.

Notifications
Anonymous telemetry
Locked

LiquidMenu

The trigger becomes the panel, and the button is not drawn for as long as the panel is out — so what moves is one object changing shape, not a menu appearing beside a button that is plainly still there. It leaves its place as a patch of glass the button's exact size, travels to the centre of the box the menu will fill, and on the way gathers: narrower, and taller for it, the way liquid draws in before it spreads. Three frames later it spills sideways — flattening as it goes, because the volume has to be somewhere — and then rises into its own shape, the refraction growing in as it deepens, since a shallow puddle has no thickness to bend light through. Its corner is driven against the scale throughout: as round as the box allows while it is small, easing to the panel's own radius only as it settles, which is the difference between liquid finding its edges and a rectangle being enlarged. The corner shape eases on that same schedule and for the same reason: while the patch is a lozenge its radius is saturated, and a saturated corner has to be round, so the panel spills round and only becomes the superellipse once it has somewhere to put one. The radius is compensated for that shape as well — 22 is the round panel's radius, and the continuous corner gets the ~27.5 that reads as equally curved, since a superellipse at equal radius looks tighter rather than rounder. That compensated pair is also, measurably, an iOS menu corner: Apple's continuous curve is a superellipse(1.3) at ×1.25 the radius, to a third of a percent. Two scale channels, two deformation channels and a translation — no size animation, so the displacement map is rasterised once before the menu is ever opened. Arrows, Home/End, Escape, Tab and an outside press all behave; pointing at an item moves focus to it, as a native menu does.

selected:

LiquidToolbar

A circular button that stretches into a bar and back. The same swap as LiquidMenu — the trigger is not drawn for as long as the bar is out, so what moves is one object changing shape — but on one axis, and with the collapsed state as a place the control genuinely rests rather than a puddle nobody sees. That difference sets most of the design. The bar is laid out at its full width and drawn at a fraction of it, since width is the displacement map's cache key and animating it would rasterise a PNG per frame; so the shell and the trigger are locked to the same height by TOOLBAR_SIZES, which is what leaves exactly one axis to scale and makes the collapsed patch the button's box exactly. Its corner is asked for pre-divided by that scale, from half the shorter drawn side — one min, so the capsule survives turning through ninety degrees during the gather instead of having its ends flattened by CSS's radius clamp. The refraction is absent while the shell is squeezed and grows in with the unroll, because the map is baked for the settled bar and its end caps cannot survive being compressed sevenfold. The items neither fade on a timer nor ride the scale: the row cancels it, holding every well at its settled size and position from the first frame, and each one is lit when the unrolling edge reaches the width that has room for it. That threshold is geometry, so the stagger cannot drift from the spring — and the retraction plays it backwards for free. One style write per frame drives all of it.

Acting on an item leaves the bar open, which is the whole difference from a menu: these are repeatable actions against something still on screen, not one choice that dismisses what asked for it. Favourites toggles in place. Arrows move between wells, Home/End jump, Escape and an outside press retract — and Tab falls through and takes focus out, as the ARIA toolbar pattern requires, which collapses the bar behind it.

last action: · favourite: off

LiquidSlider

Same droplet: an opaque knob until you grab it, then clear refracting glass that swells and squashes along its travel. A transparent <input type="range"> sits over the track, so arrows, PageUp/PageDown and Home/End all work — and melt the droplet too.

64
21.5°C
30

LiquidSearchField

A native <input type="search"> in a glass capsule. The whole pill is the target — press anywhere and the caret lands in the field. Enter submits, Escape clears a non-empty field (and only then: an empty one lets the key through to whatever surface the field sits in), and the clear button hands focus straight back, because a cleared search is the start of the next one. The field is the button ladder's height — 30/38/46 — so it rows up with the circle buttons it shares a bar with, and its bezel is the toolbar's 0.26 law: the flat centre has to carry a text line and a caret, not just a label.

query: · submitted:

expandable is the toolbar's unroll with a text field inside: a circular search button that becomes the input — the trigger is not drawn while the field is out, the collapsed patch is its exact box, and the capsule unrolls from whichever edge anchor pins. The morph is legal by the same law as the toolbar's: the field's height is the circle's diameter, so one axis scales and the other holds. Focus lands in the input on expansion; Escape steps back down the ladder — clear, then retract — and a field holding a query stays out through outside clicks, because an active search is a state, not a transient.

LiquidTabs

tablist / tab / tabpanel with roving focus and manual activation. Arrow keys move, Home and End jump, the disabled tab is skipped.

A displacement map encodes the refraction vector per pixel — X in red, Y in green, 128 neutral. The bezel carries almost all of it; the centre stays flat.

Segments take an optional icon snippet — beside the label, above it with iconPlacement="top", or alone with iconOnly, where the label moves onto the button's aria-label. The bubble paints over the labels, so the lens refracts the glyphs it crosses — grab one and watch the fringing.

LiquidNavBar and LiquidScrollEdge

Scroll inside the panel. The bar is not a glass surface and has no surface at all — no tint, no rim, no shadow, no boundary. What appears is a progressive blur: four stacked backdrop layers, each masked to a different depth, so the blur radius ramps from the pinned edge instead of stopping at a line. The content loses definition as it approaches the top; nothing is laid over it. That is what iOS actually does, and it is why the controls can be real glass — they sit beside the band, not inside it, so their refraction still reaches the page.

It takes its cue from the large title's bottom edge closing on the bar's, not from an absolute offset, so the inline title arrives exactly as the large one goes under. Nothing is sprung: the scroll position is the animation.

materialisation: 0.00

LiquidLens

Drag it across the text. Arrow keys move it too (hold Shift for larger steps), and Escape abandons a pointer drag and restores the starting position. It stretches along the direction of travel, capped at 12%.

The refraction is a displacement map: for every pixel, the distance to the outline picks a magnitude off a 128-entry lookup table, and the outward edge normal turns it into a vector. X goes in the red channel, Y in the green, 128 meaning “no shift”.

The lookup table comes from Snell's law applied to a quartic squircle profile. Convex surfaces have an infinite slope right at the rim, so the exact vector form matters: it saturates at a finite offset instead of collapsing the whole table into a one-pixel spike.

Peak displacement is about four times the bezel width. That sounds enormous, and it is — but it only applies in a very thin band at the outer edge. A tenth of the way into the bezel the magnitude is already down to 0.47, and halfway in it is 0.05.

LiquidGlass — the primitive

Everything above composes this. It takes content through a snippet and exposes the geometry and optics as typed props.

These four vary profile — the height of the glass surface across the bezel, which is what bends the light. The corner control in the header varies cornerShape, the outline. Two unrelated axes that both have a squircle in them, hence the labels: the first tile is the default quartic surface, and it keeps that surface whatever the outline is set to.

squircle profile
concave profile
lip profile
aberration

Refraction through backdrop-filter: url(#…) is Chromium-only. Firefox and Safari fall back to the degraded tier — blur, tint, rim and shadows, no distortion. Switch tiers above to compare.