Liquid Glass
Apple's Liquid Glass, rebuilt from optics: rays are refracted through a curved bezel with Snell's law, baked into an SVG displacement map, and applied to the backdrop.
backdrop-filter is not part of the CSS spec and only Chromium implements it. In Safari and Firefox the panel degrades to its frost tint and rim shadow, with no refraction. How it works
The effect is a small ray tracer that runs once per size change, following Maxime Kubryk's write-up of the technique.
1. The surface
The bezel is described by a height function over x ∈ [0, 1], where 0 is the outer edge and 1 is where the glass goes flat. The surface prop picks between four of them — a circular arc, a squircle, the concave complement, and a smootherstep blend of convex and concave that produces a raised lip.
2. The refraction
Incident rays are assumed orthogonal to the background, so the angle of incidence is just the surface tilt — the derivative of the height function, scaled by thickness / bezelWidth. Snell's law (n₁·sin θ₁ = n₂·sin θ₂) gives the refracted angle, and the ray then crosses the glass before landing on the background, so the lateral shift is height · tan(θ₁ − θ₂). Convex profiles keep the landing point inside the panel; concave ones push it out past the border, where there is nothing to sample.
3. The displacement map
Displacement magnitude only depends on distance from the border, so it is computed once along a single radius and then rotated around the shape — a rounded-rect signed distance field supplies both the distance and the normal to point the vector along. The vectors are normalised by the largest magnitude, then written into a canvas with the X component in red and the Y component in green, 128 being neutral. Exactly 128 samples are taken, because an 8-bit channel cannot express any more.
That maximum magnitude comes back as the filter's scale, which is what converts the normalised map into real pixel offsets. Because scale is just an attribute, refraction and aberration can be animated freely — everything else changes the baked geometry and forces a rebuild.
4. The specular rim
A second image encodes a rim light: brightest where the tilted bezel faces specularAngle, fading out on its own as the surface flattens toward the interior. It is screened over the refracted backdrop.
Installation
npx raya-ui@latest add liquid-glassFile Structure
Performance notes
- Building the maps is a full per-pixel pass over the panel, so it is coalesced into one
requestAnimationFrameand only runs when the size or the baked geometry changes. - Moving, scaling by transform, or animating
refractionandaberrationcosts nothing extra — none of them rebuild the map. - Resizing the panel every frame does rebuild it every frame. Prefer
transform: scale()for animated size changes. aberrationabove 0 runs three displacement passes instead of one. Leave it at 0 unless you want the dispersion.
API Reference
Props
surface"convexSquircle" | "convexCircle" | "concave" | "lip""convexSquircle"Cross-section profile of the bezel. The squircle keeps the flat-to-curve transition smooth when the shape is stretched into a rectangle, which is why Apple favours it. `concave` pushes rays outward past the panel; `lip` raises a rim and dips the centre.
radiusnumber24Corner radius of the panel, in px. Also drives the rounded-rect distance field the vector field is rotated around.
bezelWidthnumber24How far the curved bezel extends inward from the border, in px. Everything past it is flat glass and refracts nothing.
thicknessnumber40Height of the glass at the end of the bezel, in px. Rays cross this much material before landing on the background, so it scales the displacement directly.
refractiveIndexnumber1.5Refractive index of the material used in Snell's law. 1 is air and bends nothing; 1.5 is window glass.
refractionnumber1Artistic multiplier on the simulated displacement. 1 keeps the physics honest; it maps straight onto the filter's `scale`, so it animates without rebuilding the map.
aberrationnumber0Chromatic dispersion as a ratio of the refraction. Above 0 each channel is refracted at its own scale and recombined, which costs two extra displacement passes.
blurnumber2Gaussian blur applied to the backdrop before it is refracted, in px. Blurring first keeps the bezel from smearing.
specularOpacitynumber0.4Brightness of the rim light, 0–1.
specularSharpnessnumber6Exponent on the rim falloff. Higher values give a shorter, sharper glint.
specularAnglenumber-60Direction the light comes from, in degrees.
frostnumber0.05Opacity of the frosted tint filling the panel, 0–1. Adapts to light and dark via `light-dark()`.
classstring—Classes applied to the inner content wrapper.
containerClassstring—Classes applied to the outer glass element — use this for sizing and positioning.
Slots
defaultContent rendered on top of the glass. It sits above the refracted backdrop and is not itself distorted.
GLASS
EFFECT
Balance
$12,450.00
<script setup lang="ts">
import { LiquidGlass } from '@/components/ui/liquid-glass'
</script>
<template>
<LiquidGlass class="w-72 h-48">
<div class="h-full w-full flex items-center justify-center p-6">
<p class="text-white font-medium">Refracted Content</p>
</div>
</LiquidGlass>
</template>