TL;DR Use bg-white/10, a light border and backdrop-blur + backdrop-saturate for the frosted layer in every browser. backdrop-filter: url(#svg-filter) refraction renders only in Chromium, yet Firefox and WebKit report it as supported, so gate it with a Chromium check via useSyncExternalStore, keep blur in its own rule, and add a prefers-reduced-transparency fallback.
Liquid glass in React comes in two layers. The frosted part is a translucent background with backdrop-filter: blur() saturate(), a thin light border and an inner highlight, and it works in Chrome, Safari and Firefox. The part that bends what's behind the glass needs an SVG filter applied through backdrop-filter: url(#filter), and that only renders in Chromium. Firefox and WebKit still report the url() value as supported, so @supports can't gate it. Keep blur as the default everywhere, switch the SVG filter on only in Chromium, and give people who ask for less transparency a solid background.
I make qodesign, a set of React + TypeScript components with Tailwind (most also use Framer Motion). Our Liquid Glass Tab Bar uses the frosted layer, so I wanted to know exactly where the refraction layer works before telling anyone to add it. On October 21, 2026 I built a test page in a fresh Next 16.4.2 app (React 19.3.0, Tailwind v4), ran tsc and next build, and loaded the production build in headless Chromium 156, Firefox 157 and Playwright's WebKit 27.2. Every panel sat on top of vertical red, yellow, blue and black stripes, so blur and bending both show up as measurable changes in the pixels.
The frosted layer is four things: a background that is mostly transparent, a backdrop blur, a saturation boost so the colours behind look richer, and a light edge. These are the values from our tab bar as Tailwind classes:
MDN's backdrop-filter page points out that the element or its background has to be transparent or partly transparent for the effect to show. In practice glass also needs something busy behind it. Over a flat colour it just looks grey.
In Chromium, the blur(16px) panel cut the edge contrast of the stripes behind it from 3.59 to 1.99 (average brightness change between neighbouring pixels, on a 0 to 255 scale).
Apple's version bends the content at the edges of the glass. On the web the usual way to get close is an SVG filter with feTurbulence or a displacement image feeding feDisplacementMap, referenced from backdrop-filter. Here's the component I tested. It renders its own filter with an id from useId, so two panels on one page don't share a filter:
Use it like any wrapper: <LiquidGlass className="rounded-[32px] p-4">…</LiquidGlass>. Raise scale for stronger bending. Turbulence gives a wobbly, watery look. For the clean lens-edge look, swap it for an feImage displacement map.
On the useId point: React 19.3 gave me ids like _R_6lubrb_, which already work inside url(#…). I tested the raw id and the cleaned one and both rendered the same. The replace costs nothing and protects you if the format changes again.
Here's what I measured. With vertical stripes behind a panel, every row of pixels is identical, so the average change between rows is 0. Blur keeps it at 0. Anything that bends the stripes makes it go up.
Engine
Bending under the SVG panel
Plain blur() visible in my run
Chromium 156
yes, row change 0.52 (0 without the filter)
yes
Firefox 157, headless
no
no
WebKit 27.2 (Playwright), headless
no
no
Chromium is clear. For the other two I can't lean on my screenshots: on this headless Linux setup even plain blur() didn't show up, so the missing bend proves nothing by itself. The public bug trackers fill the gap. WebKit's bug 245510, "backdrop-filter: url(#some-svg-filter) doesn't work with SVG filters like feDisplacementMap", was opened in September 2022 and was still marked NEW when I checked. Mozilla's bug 1961378 is titled "backdrop-filter gets ignored if it would fall back to a blob image (such like with some SVG url filters)", also NEW.
That Firefox title is the reason the CSS above keeps url() out of the default rule. If Firefox ignores the whole declaration, you lose your blur too and the glass turns into a faint tint. With the split rules, Firefox and Safari keep the frosted layer whatever happens.
All three accept the syntax. Parsing it and rendering it are different things, so @supports gives you a yes in exactly the browsers you were trying to filter out.
What I used instead is navigator.userAgentData. MDN's compatibility data lists it in Chrome and Edge from version 90 and not in Firefox or Safari, and its brands list includes "Chromium" in Chromium-based browsers. That's a browser check, and I'd normally avoid one, but here it matches the one fact that matters: who renders SVG backdrop filters today. When WebKit or Firefox fix their bugs, you change one function.
It would if you read navigator during render, because the server has no navigator. useSyncExternalStore with a server snapshot of false avoids that. The server HTML and the first client render both have no lg-on class, then React switches to the real value after hydration.
In my production build the refract="auto" panel got lg-on in Chromium and didn't in Firefox or WebKit, with 0 page errors in all three. Its computed backdrop-filter in Chromium was url("#lg-_R_clubrb_") blur(2px) saturate(1.6), and in the other two it stayed blur(2px) saturate(1.6).
Some people turn on "Reduce transparency" in their OS settings, and glass is the first thing that setting is meant to remove. The prefers-reduced-transparency media query lets you respect it. MDN marks it experimental with limited availability: its compatibility data lists Chrome from 118, Firefox behind a flag, and no Safari support.
I emulated the setting in Chromium through DevTools. The query matched, the panel's backdrop-filter became none and its background became rgba(20, 20, 24, 0.92), which is the fallback from the CSS above. Pick a fallback colour that keeps your text readable without any blur. For the same idea applied to animation, see the prefers-reduced-motion guide.
I didn't measure it for this post, and a headless browser with a software renderer wouldn't give honest numbers anyway. The tab bar's own guide notes that backdrop blur costs GPU time, which is why the bar switches its blur off while the lens and player states are open. If you animate a glass panel, test on a real phone and keep the number of blurred layers on screen small.
Ship the frosted layer everywhere. Add the SVG refraction as an extra for Chromium, behind a check that doesn't trust @supports. Add the reduced-transparency fallback. If you want a finished piece, the animated tab bar guide and the Liquid Glass Tab Bar use the frosted layer with a magnifying lens made from a scaled copy of the bar, which looks the same in every browser.
Not tested: real Safari on macOS or iOS, Firefox with a real GPU, Edge, and frame rates on phones. All runs were headless on Linux.
Yes for filter functions like blur() and saturate(). MDN's compatibility data lists backdrop-filter in Safari 18 and with the -webkit- prefix since Safari 9, so keep the prefixed line for older versions. SVG filters through backdrop-filter: url() are a different story: WebKit bug 245510 for that was still open on October 21, 2026.
If your glass uses backdrop-filter: url(#filter), only Chromium renders it. Mozilla's bug 1961378 says Firefox can ignore the whole backdrop-filter when an SVG url filter is involved, which would also drop your blur. Keep blur() in a separate default rule and add the url() only for Chromium.
No. In my test Chromium 156, Firefox 157 and WebKit 27.2 all returned true for CSS.supports('backdrop-filter', 'url(#x)'). Checking navigator.userAgentData for the "Chromium" brand worked, with useSyncExternalStore to avoid a hydration mismatch.
Use bg-white/10 border border-white/15 backdrop-blur-[16px] backdrop-saturate-[1.9] plus an inset shadow for the highlight, on top of something colourful. For the refraction layer, use a small CSS class that adds url(#id) to the backdrop filter, because the id comes from useId at runtime, and only turn it on in Chromium.
Yes. Add @media (prefers-reduced-transparency: reduce) and swap the blur for a nearly solid background. Chromium supports the query from version 118 according to MDN's data, and browsers without it simply ignore the rule.