Lighting
Light that behaves like light.
The rim is lit as a curved surface. A specular highlight catches the light, and fresnel brightens the edge where the glass turns away from you.
REAL HTML · EVERY BROWSER · NO DEPENDENCIES
This text is real. Select it, Cmd+F it, click the buttons.
Drop an image to look through the glass
Not a screenshot, not a canvas. The lens refracts the live page, so text stays selectable and buttons stay clickable. In Chrome, Firefox and Safari.
Lighting
The rim is lit as a curved surface. A specular highlight catches the light, and fresnel brightens the edge where the glass turns away from you.
Bevel
Set how far the curve reaches in. Take it all the way to the middle and the lens becomes a magnifier. Move over it.Drag it around.
Button mode
Hover and the glass brightens. Press and the bevel flattens as the shadow tightens. Springs, so it never snaps.
Tone
Grade what's behind the lens without touching the page.
Presets
Pick one, then tune it. Presets are plain settings on LiquidGlass.presets, so your site can use them too.
0
dependencies
1
file to copy
3
browser engines
A switch, a tab bar and a button, built on the lens and tuned side by side with iOS 26, down to its springs. Hover, press and drag them.
Switch
Solid at rest. Hover, press or drag and the thumb dissolves into a lens that bends the track around it, then sets back down once it stops. Plain, or with a label each side.
Light
Dark
Tab bar
A lens lifts off the current tab and follows your finger, the bar swelling as you press. Let go and it lands on the nearest tab, hangs a moment, and sets down.
Light
Dark
Button
A clear lens over whatever is behind it. Hover and it grows and fills with its tint; press and it swells a little more, with a glow under your finger. With an icon, or with words.
Four stages, all standard web platform: a copy of the page, a map of how far each pixel moves, an SVG filter that moves them, and light painted on top.
Step 1 · Copy
An SVG filter can't see what's behind an element. backdrop-filter: url() could, but only Chrome supports it. So the lens keeps its own copy of the page, made with cloneNode(true) and positioned so every pixel lines up with the original.
A MutationObserver, plus input and scroll listeners, marks the copy stale, and it's rebuilt on the next frame. Cloning drops live state, so input values, checkboxes, canvas pixels and scroll offsets are carried across by hand.
Step 2 · Map
The lens is a signed distance field for a rounded rectangle: negative inside, zero on the edge. Across the bevel the glass is a quarter circle, so the bend grows as 1 − √(1 − t²), where t runs from 0 at the bevel's inner edge to 1 at the rim. The direction is the field's gradient, which points straight out.
Each offset is written to a canvas, x in red and y in green, centred on 128. The curve stops just short of vertical, since a vertical edge would bend without limit.
Step 3 · Filter
Real glass bends each wavelength a little differently. The filter runs the displacement three times at slightly different strengths, keeps red from the strongest, green from the middle and blue from the weakest, then adds them back together.
Brightness and saturation are one colour matrix at the end. Frost is a CSS blur() around the filter rather than feGaussianBlur inside it, which keeps it on the GPU in Firefox.
Step 4 · Light
Lighting is a canvas over the glass. Each rim pixel gets a 3D normal that tilts outward as the bevel rounds over. A Blinn-Phong half vector between a top-left light and your eye gives the specular spot, and fresnel brightens the edge where the surface turns away.
It's drawn at device resolution when the shape changes, never per frame. Moving the lens is only a transform.
The frame loop checks three flags: the copy is stale, the shape changed, or the lens moved. On an idle frame it does nothing.
Position is a damped spring, so new input just retargets it mid-flight. Speed stretches the lens along its path, and reduced motion snaps instead.
Map channels are 8-bit, so zoom stored there moved in half-pixel steps. Instead the filtered layer is built at 1/zoom size and scaled up.
Browsers rasterise filters on the CSS pixel grid. At a fractional position the refraction gets resampled and shimmers, so the lens snaps to whole pixels.
Safari drops a filter over GPU layers and mis-scales transformed content inside one. The copy loses will-change and animations, and moves with left and top.
Screen readers, keyboard focus and find-in-page only ever meet the real page. The copy is inert and hidden, and its IDs are stripped so they stay unique.
Liquid glass on the web, side by side. Each takes a different path to the same look, and each path has its trade-offs.
From each project's README and source in October 2026. Libraries change, so check the links for the latest. Our copy doesn't show hover or focus states, video or WebGL canvases.
One small package for plain JavaScript, React or a single script tag. No dependencies. Tune the lens and the code below follows along.
npm install @dazecoop/liquid-glass
You're using an uploaded image. Swap your-image.jpg for a URL on your site.
Components
Import the stylesheet once. In React each one is a component, controlled or not. In plain HTML, write the markup and call initComponents(). Add data-theme="light" to any ancestor for the light look.
JavaScript
source, a live element. Floats over the page by default.button makes it brighten on hover and flatten on press.true.clear, frosted, dark, prism, dome.React
source.defaultChecked.{ value, label, icon, href }.tint.Every one cleans up on unmount and is safe in StrictMode and on the server.
Parameters