LensGlass Component
Physics-based glass lens refraction effect using geometry-aware displacement maps
The LensGlass component creates a realistic optical refraction effect — light bends around
the edges of the element like a real glass lens. Unlike LiquidGlass, this effect displaces
the background behind the element using a geometry-aware displacement map derived from
the element's exact dimensions and border radius.
Chromium only — this component uses backdropFilter: url('...') with an inline SVG
filter, which Safari does not support. In Safari the element renders as fully transparent
(no blur, no distortion). If you need Safari support, use LiquidGlass instead —
it falls back gracefully to blur-only in Safari.
Safari also has a compositor limitation with backdrop-filter: blur() in general:
many blurred elements on screen simultaneously causes frame drops. Chrome and Firefox handle
this without issues.
Props
| Prop | Type | Default | Description |
|---|---|---|---|
width | number | — | Width in px. If omitted, element fills its container (measured via ResizeObserver) |
height | number | — | Height in px. If omitted, element fills its container (measured via ResizeObserver) |
radius | number | 20 | Border radius in px |
depth | number | 10 | Lens depth — controls the gradient shape of the map |
blur | number | 1 | Backdrop blur (blur/2 pre-filter, blur post-filter) |
chromaticAberration | number | 1 | RGB channel split for a prism-like color fringe |
strength | number | 100 | Overall displacement intensity |
brightness | number | 1.1 | brightness() in the backdrop filter chain |
saturate | number | 1.5 | saturate() in the backdrop filter chain |
children | ReactNode | — | Optional content rendered inside the lens |
className | string | — | Additional CSS classes |
Basic Usage
No SVGFilters setup required — LensGlass is fully self-contained:
With Content
Children render inside a dedicated content layer on top of the glass effect. The backdrop distortion stays behind — content is unaffected by the filter:
Hello
Content inside the lens
Variants
Pill
Circle
Strong chromatic aberration
withLens HOC
withLens wraps any component with LensGlass — useful when you want a fixed lens shape
permanently attached to a specific component. The lens config is defined once at HOC creation;
the wrapped component receives all its own props normally.
import { withLens } from "react-glassy";
import "react-glassy/styles.css";
function ProfileCard({ name, role }: { name: string; role: string }) {
return (
<div className="flex flex-col items-center justify-center h-full gap-1 p-6 text-center">
<p className="text-lg font-semibold">{name}</p>
<p className="text-sm opacity-70">{role}</p>
</div>
);
}
export const GlassProfileCard = withLens(ProfileCard, {
width: 240,
height: 160,
radius: 24,
depth: 10,
blur: 1,
chromaticAberration: 1,
});
// Usage — pass only component props, lens config is fixed
<GlassProfileCard name="Alice" role="Designer" />Alice
Designer
How It Works
Unlike the turbulence-based filters in LiquidGlass, LensGlass generates a
geometry-aware displacement map on the fly:
-
Displacement map — an SVG with linear gradients (red = horizontal offset, green = vertical offset) whose extents are computed from
radius / widthandradius / heightratios. An inner rectangle withfilter="blur(${depth}px)"creates the convex bulge. -
Displacement filter — an SVG filter using
feImageto embed the map andfeDisplacementMapto warp the background. WithchromaticAberration > 0, three separate displacement maps run at different scales for R, G, B and are screen-blended — creating a prism-like color fringe at the edges. -
Backdrop filter chain:
backdropFilter: blur(N/2px) url('…filter') blur(Npx) brightness(1.1) saturate(1.5)Pre/post blur softens the displacement boundary; brightness and saturation compensate for the darkening SVG displacement tends to introduce.
Both SVGs are generated as data: URLs and memoized — they only regenerate when props change.