@sellinedev/liquid-glass-react
v1.2.0
Published
Apple's Liquid Glass effect for React
Maintainers
Readme
Liquid Glass React
Apple's Liquid Glass effect, recreated for React.
Live Demo · Stress Benchmark · npm
Features
- Realistic edge bending and refraction
- Multiple refraction modes —
standard,polar,prominent,shader - Configurable frosting, saturation, and chromatic aberration
- Liquid elastic feel on hover and click
- Edges and highlights adapt to underlying content, just like Apple's
- Supports arbitrary children and custom padding
- Optimized rendering pipeline with shader map caching
Note: Safari and Firefox only partially support the effect (displacement will not be visible).
Quick Start
npm install liquid-glass-reactimport LiquidGlass from "liquid-glass-react";
function App() {
return (
<LiquidGlass>
<div className="p-6">
<h2>Your content here</h2>
<p>This will have the liquid glass effect</p>
</div>
</LiquidGlass>
);
}Examples
Card
<LiquidGlass
displacementScale={70}
blurAmount={0.0625}
saturation={140}
aberrationIntensity={2}
elasticity={0.15}
cornerRadius={24}
padding="24px"
>
<h2>John Doe</h2>
<p>Software Engineer</p>
</LiquidGlass>Button
<LiquidGlass
displacementScale={64}
blurAmount={0.1}
saturation={130}
aberrationIntensity={2}
elasticity={0.35}
cornerRadius={100}
padding="8px 16px"
onClick={() => console.log("clicked!")}
>
<span className="text-white font-medium">Click Me</span>
</LiquidGlass>|Card|Button|
|:-:|:-:|
|
|
|
Mouse Container
Track mouse movement over a larger parent area:
function App() {
const containerRef = useRef<HTMLDivElement>(null);
return (
<div ref={containerRef} className="w-full h-screen">
<LiquidGlass
mouseContainer={containerRef}
elasticity={0.3}
style={{ position: "fixed", top: "50%", left: "50%" }}
>
<div className="p-6">Glass responds to mouse anywhere</div>
</LiquidGlass>
</div>
);
}Props
| Prop | Type | Default | Description |
|:-----|:-----|:--------|:------------|
| children | ReactNode | — | Content inside the glass |
| displacementScale | number | 70 | Displacement intensity |
| blurAmount | number | 0.0625 | Blur / frosting level |
| saturation | number | 140 | Color saturation |
| aberrationIntensity | number | 2 | Chromatic aberration |
| elasticity | number | 0.15 | Liquid feel (0 = rigid) |
| cornerRadius | number | 999 | Border radius (px) |
| padding | string | — | CSS padding |
| className | string | "" | CSS classes |
| style | CSSProperties | — | Inline styles |
| overLight | boolean | false | Light background mode |
| onClick | () => void | — | Click handler |
| mouseContainer | RefObject<HTMLElement> | null | External mouse tracking area |
| mode | "standard" \| "polar" \| "prominent" \| "shader" | "standard" | Refraction mode |
| globalMousePos | { x, y } | — | Manual mouse position |
| mouseOffset | { x, y } | — | Mouse position offset |
Benchmark
An interleaved stress benchmark compares Original vs Optimized rendering pipelines across 6 phases — Baseline, Spawn Storm, BG Chaos, Mouse Tornado, Content Churn, and Combined.
Key Results
| Metric | Value | |:-------|:------| | Avg FPS Gain | +8% | | Render Reduction | 74% fewer re-renders | | Render Ratio | 3.9x fewer renders (20,286 → 5,276) |
| Phase | Orig FPS | Opt FPS | Delta | Orig Renders | Opt Renders | Ratio | |:------|:--------:|:-------:|:-----:|:------------:|:-----------:|:-----:| | Baseline | 121 | 120 | -1% | 32 | 33 | 1.0x | | Spawn Storm | 59 | 57 | -4% | 4,523 | 2,152 | 2.1x | | BG Chaos | 72 | 88 | +22% | 3,413 | 540 | 6.3x | | Mouse Tornado | 72 | 79 | +10% | 3,570 | 560 | 6.4x | | Content Churn | 72 | 89 | +25% | 3,550 | 570 | 6.2x | | Combined | 88 | 87 | -1% | 5,198 | 1,421 | 3.7x |
Run it yourself at /stress-benchmark. Results are downloadable as CSV/JSON.
Optimizations
The optimized pipeline includes:
- Shader map caching — module-level
Mapavoids regenerating displacement maps for the same dimensions useMemoshader URLs — replacesuseState+useEffectto eliminate extra rendersResizeObserver— replaceswindow.resizelistener for precise, per-element size tracking- RAF-batched DOM updates —
useRef+requestAnimationFrameinstead ofsetStatefor mouse tracking - Fast-path mouse rejection — cached bounding rect skips
getBoundingClientRectwhen cursor is far away - Early exit guard — skips
updateDOMentirely when element is inactive with zero opacity
Demo

