Skip to content
shadcn.io

shadcn.io is not affiliated with official shadcn/ui

Backgrounds

Pro

Caustics Background for React

The bright net of light that sways across a pool floor on a sunny day, drifting behind your content. For React with Base UI, when a swimming, travel or wellness page should feel like it's underwater.

Framework

The bright net of light that sways across a pool floor on a sunny day: thin lines of light over blue water, glowing where they meet. Two nets of light, each a honeycomb bent by an SVG noise filter that's drawn once, drift in different directions and glow brighter where they cross, so the pattern keeps changing. Only their wrappers move, by CSS transforms, so the filter never runs again and no script runs.

Use it behind an aquatic product hero, a swimming school or a diving and travel page. For the water around the light, with shafts and rising motes, use Underwater; for a cell network that changes cell by cell, Voronoi; for rings spreading on a still surface, Drops; for the open sea out to the horizon, Ocean.

Preview width

Installation

Part of Pro
Pro unlocks the code and one-line install of every Pro button and text effect, plus the MCP for your AI editor.
Have Pro already? Sign in to open it.Opens here as soon as you're Pro.

Usage

import { Caustics } from "@/components/ui/caustics";
<Caustics className="flex min-h-[420px] items-center justify-center">
  <h1 className="text-5xl font-semibold">Dive into the deep end</h1>
</Caustics>

Caustics is a container: whatever you put inside sits on top of the water, in normal flow. It paints its own water, so give it a height or content. For a backdrop behind the whole page, render it empty with className="fixed inset-0 -z-10". The palette follows the colour scheme: a sunny pool with white light on a light page, a night pool with cyan light on a dark one.

Demos

Subtle

intensity="subtle" holds the light back behind body text, and scale={1.5} makes the cells half as big again, here in a small card.

Preview width

Neon

waterColor and lightColor take any CSS colours, used in both colour schemes: here an indigo pool with pink light.

Preview width

Accessibility

The water is decoration: it's hidden from assistive tech and lets every click through to your content. With reduced motion both nets stand still, a still picture of the pool floor. Nothing flashes: the nets drift slowly, with no change in brightness.

Put copy in your foreground colour (text-foreground). Between the lines it keeps 6:1 on a light page and about 9:1 on a dark one. Where a bright line crosses a letter it falls to about 5.6:1 on a light page but about 3.2:1 on a dark one, fine for a headline: for body text on dark pages use intensity="subtle", which keeps it above 5:1. The light is dimmer on a dark page for this reason.

FAQ

What is a caustic?

The net of bright lines a wavy water surface focuses onto the floor below it. Each ripple acts as a small lens, so the light gathers into curved lines around darker cells.

How is it made?

A hexagon pattern bent by a static SVG turbulence filter, drawn once when the background first shows. Two copies of different sizes, one turned, drift in different directions and glow where they cross. The filter itself never animates, so moving the nets costs no repaints.

How do I change the colours?

Pass waterColor for the water and lightColor for the light, any CSS colours; they then apply in both colour schemes. By default both are tuned per scheme: a sunny pool on a light page and a night pool on a dark one. You can also set --caustics-water and --caustics-light in your CSS.

Can I make the net tighter or looser?

Yes: scale sizes the cells (1 by default, from 0.25 to 4), so 2 gives broad cells and 0.5 a tight net. speed sets the drift: 0.5 is calmer, 2 like a windy day.

Will text on top stay readable?

Headlines read well at the default. For body text, especially on a dark page, use intensity="subtle" or put the copy on a soft panel.

Does it cost much?

The filter is drawn once, which takes a moment of the browser's raster threads (about half a second for a full hero), and again only when the box is resized. After that, moving the nets is a transform the browser does without repainting.

API Reference

Caustics

<div> data-slot="caustics"

PropType
intensity?"subtle" | "medium" | "strong"

How bright the net of light is: subtle behind body text, strong for a sunny pool.

Type
"subtle" | "medium" | "strong"
Default
"medium"
lightColor?string

The light's colour, any CSS colour. By default near-white on a light page and cyan on a dark one.

scale?number

The cells' size, a multiplier: 2 is twice as big, 0.5 half. @default 1.

Default
1
speed?number

How fast the nets drift: 2 is twice as fast, 0.5 half as fast.

Default
1
waterColor?string

The water's colour, any CSS colour. By default a sunny aqua on a light page and a night-pool navy on a dark one.

render?ReactElement | ((props: object, state: object) => ReactElement)

Replace the host element or compose it with another component.

Type
ReactElement | ((props: object, state: object) => ReactElement)
className?string

Merged with the part's classes.

CSS variableType
--caustics-lstring
--caustics-lightstring

The light's colour (near-white, cyan on a dark page).

--caustics-speedstring

The drift's speed, a multiplier (1).

--caustics-waterstring

The water's colour (aqua, navy on a dark page).

All 100 backgrounds