React Glassy

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

PropTypeDefaultDescription
widthnumberWidth in px. If omitted, the element fills its container
heightnumberHeight in px. If omitted, the element fills its container
radiusnumber16Border radius in px
strengthnumber20Displacement intensity as a fraction of element size (20 → 10%)
chromaticAberrationnumber0RGB channel split; 0 = single-pass filter, 1 = tw-glass ratios
insetnumber8Width of the refracting edge band, in % of element size
cornerRadiusnumber4Corner radius of the undistorted center zone (map units, 0–50)
innerBlurnumber4Softness of the transition between edge band and center
outerBlurnumber1.5Smoothing of the displacement gradients
shape"rect" | "circle""rect"Shape of the undistorted center zone
blurnumber2Backdrop blur in px, applied after the displacement filter
brightnessnumber1.05brightness() in the backdrop filter chain
saturatenumber1.2saturate() in the backdrop filter chain
childrenReactNodeOptional content rendered inside the glass
classNamestringAdditional 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

EdgeGlassLensGlass
Distortion areaEdge band only, center untouchedWhole element, strongest at edges
Filter unitsobjectBoundingBox — size-independentPixels — map generated per exact size
ResizingFree — same filter for any sizeNeeds ResizeObserver + filter rebuild
Filter sharingOne filter per configOne filter per config + size
LookFlat glass panel with refracting rimConvex 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

  1. Displacement map — an SVG with a fixed viewBox="0 0 100 100" and preserveAspectRatio="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.

  2. Displacement filter — declared with filterUnits="objectBoundingBox" and primitiveUnits="objectBoundingBox": feImage spans the whole element (0..1) and the feDisplacementMap scale is a fraction of element size (strength / 200), so the effect scales with the element automatically. With chromaticAberration > 0, three passes run at different scales for R, G, B and are screen-blended.

  3. 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.

Interactive Playground

Configuration

On this page