EdgeGlass Component
Edge-only glass refraction — distorts the border of the element while keeping the center perfectly readable
The EdgeGlass component refracts the backdrop only at the edges of the element — the
center stays completely undistorted. This is the key difference from LensGlass, whose
displacement reaches deeper into the element. The approach is ported from
tw-glass by
assistant-ui (MIT).
Because the filter is declared in objectBoundingBox units, a single SVG filter works for
any element size — no ResizeObserver, no per-size filter regeneration. All EdgeGlass
instances with the same config share one DOM filter regardless of their dimensions, and the
refraction band scales proportionally when the element resizes.
Chromium only — like LensGlass, this component uses backdropFilter: url(#...)
with an SVG displacement filter, which Safari does not support. In Safari the element
renders without distortion. If you need Safari support, use LiquidGlass instead.
Props
| Prop | Type | Default | Description |
|---|---|---|---|
width | number | — | Width in px. If omitted, the element fills its container |
height | number | — | Height in px. If omitted, the element fills its container |
radius | number | 16 | Border radius in px |
strength | number | 20 | Displacement intensity as a fraction of element size (20 → 10%) |
chromaticAberration | number | 0 | RGB channel split; 0 = single-pass filter, 1 = tw-glass ratios |
inset | number | 8 | Width of the refracting edge band, in % of element size |
cornerRadius | number | 4 | Corner radius of the undistorted center zone (map units, 0–50) |
innerBlur | number | 4 | Softness of the transition between edge band and center |
outerBlur | number | 1.5 | Smoothing of the displacement gradients |
shape | "rect" | "circle" | "rect" | Shape of the undistorted center zone |
blur | number | 2 | Backdrop blur in px, applied after the displacement filter |
brightness | number | 1.05 | brightness() in the backdrop filter chain |
saturate | number | 1.2 | saturate() in the backdrop filter chain |
children | ReactNode | — | Optional content rendered inside the glass |
className | string | — | Additional CSS classes |
Basic Usage
Fully self-contained — no SVGFilters setup required:
With Content
The center is undistorted, so content behind the middle of the element stays readable — only the border band bends the background:
Hello
Only the edges refract
Variants
Stronger refraction
Chromatic aberration
Three displacement passes at different scales for R, G, B, screen-blended into a prism-like fringe at the edges:
Circle
A circular neutral zone — pair it with a matching radius for round elements:
Wide edge band
Increase inset to push the refraction deeper into the element:
withEdge HOC
withEdge wraps any component with EdgeGlass, mirroring withLens and withLiquid:
import { withEdge } 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 = withEdge(ProfileCard, {
width: 240,
height: 160,
radius: 24,
strength: 25,
});
// Usage — pass only component props, glass config is fixed
<GlassProfileCard name="Alice" role="Designer" />Alice
Designer
EdgeGlass vs LensGlass
EdgeGlass | LensGlass | |
|---|---|---|
| Distortion area | Edge band only, center untouched | Whole element, strongest at edges |
| Filter units | objectBoundingBox — size-independent | Pixels — map generated per exact size |
| Resizing | Free — same filter for any size | Needs ResizeObserver + filter rebuild |
| Filter sharing | One filter per config | One filter per config + size |
| Look | Flat glass panel with refracting rim | Convex lens / droplet |
Use EdgeGlass for UI surfaces (cards, navbars, dialogs) where content behind the center
must stay readable. Use LensGlass when you want the full "liquid droplet" magnification look.
How It Works
-
Displacement map — an SVG with a fixed
viewBox="0 0 100 100"andpreserveAspectRatio="none", so it stretches to any element. Red/green linear gradients encode horizontal/vertical offsets; a neutral gray (#808080) inner shape with a small blur (innerBlur) keeps the center displacement-free. -
Displacement filter — declared with
filterUnits="objectBoundingBox"andprimitiveUnits="objectBoundingBox":feImagespans the whole element (0..1) and thefeDisplacementMapscale is a fraction of element size (strength / 200), so the effect scales with the element automatically. WithchromaticAberration > 0, three passes run at different scales for R, G, B and are screen-blended. -
Backdrop filter chain:
backdropFilter: url(#filter) blur(2px) brightness(1.05) saturate(1.2)
The filter is injected once into a shared hidden <svg> container and reference-counted —
mounting a hundred EdgeGlass elements with the same config creates exactly one filter node.