Theming

The glass material has one tuning surface, split across two files. Change either and every component that uses <Pane> updates.

Static tokens — app/globals.css

Blur radius, saturation, tint, border and shadow colors don't need JavaScript, so they live as CSS custom properties with light/dark pairs, the same way shadcn/ui themes work.

:root {
  --pane-blur-regular: 20px;
  --pane-blur-clear: 14px;
  --pane-saturation: 1.9;
  --pane-tint-regular: rgba(255, 255, 255, 0.45);
  --pane-border-regular: rgba(255, 255, 255, 0.85);
  --pane-highlight: rgba(255, 255, 255, 0.85);
  --pane-shadow: rgba(0, 0, 0, 0.1);
}

.dark {
  --pane-tint-regular: rgba(30, 30, 34, 0.45);
  --pane-border-regular: rgba(255, 255, 255, 0.14);
  --pane-highlight: rgba(255, 255, 255, 0.22);
  --pane-shadow: rgba(0, 0, 0, 0.5);
}

Dynamic tunables — lib/glass/config.ts

Everything that feeds the SVG refraction filter or the spring physics has to live in JS. This is the file to open if you want more or less lensing, a stronger chromatic-aberration edge, or snappier vs. softer press feedback.

import type {
  GlassDisplacementConfig,
  GlassSpecularConfig,
  GlassSpringConfig,
  GlassVariant,
} from "./types";

/**
 * Single tuning surface for the whole glass engine. Every Pane-based component
 * reads from here, so the entire library's material quality can be adjusted
 * from this one file. Static color/blur tokens live in `app/globals.css`
 * (`--pane-*` custom properties) since they don't need JS; only values that
 * feed the SVG filter or the spring physics live here.
 */

export const GLASS_DISPLACEMENT: Record<GlassVariant, GlassDisplacementConfig> =
  {
    regular: {
      strength: 46,
      band: 0.55,
      chromaticAberration: 1.2,
      blur: 6,
    },
    clear: {
      strength: 64,
      band: 0.7,
      chromaticAberration: 2,
      blur: 5,
    },
  };

export const GLASS_SPECULAR: GlassSpecularConfig = {
  intensity: 0.55,
  size: 260,
  angle: 115,
};

export const GLASS_SPRING: Record<
  "press" | "hover" | "drag",
  GlassSpringConfig
> = {
  press: { stiffness: 500, damping: 30, mass: 0.6 },
  hover: { stiffness: 300, damping: 24, mass: 0.8 },
  drag: { stiffness: 260, damping: 26, mass: 1 },
};

/** Minimum element area (px^2) below which the displacement filter is skipped. */
export const GLASS_MIN_FILTER_AREA = 64;

Quality tiers

use-glass-support feature-detects the browser and prefers-reduced-transparency, and returns one of three tiers:

  • full — Chromium browsers get the complete effect: blur, saturation, edge refraction and chromatic aberration.
  • reduced— everyone else gets blur, saturation and the pointer-reactive specular highlight, without edge lensing (their engines don't reliably support an SVG filter referenced inside backdrop-filter).
  • none — a solid tinted fallback when the browser has no backdrop-filter support, or the user asked for reduced transparency.