Skip to content
WANCRAFT

E.80Backgrounds & Effects

Flashlight Reveal

A dark layer with a soft, eased flashlight that reveals the content beneath the pointer.

NewReactCSSTailwindintermediate

Overview

Flashlight Reveal lays a dark, pointer-transparent overlay over your content and cuts a soft circular light into it with a radial CSS mask. The light eases after the pointer in a short rAF loop that writes CSS variables and stops as soon as it settles, so nothing re-renders while you move. The reveal is purely visual: the content is ordinary DOM that stays readable by screen readers, focusable and clickable. Keyboard focus pulls the light onto the focused element, a Reveal all toggle lifts the darkness entirely, and on touch the light follows the finger or a tap reveals everything.

01Installation

Method 01 · Registry

CLI verified

Uses the shadcn CLI in a project initialised with shadcn init. Installs the file to components/ui/flashlight-reveal.tsx and adds its dependencies.

npx shadcn@latest add https://wancraft.my/r/flashlight-reveal.json

Method 02 · Copy and paste

  1. 1. No extra dependencies — React and Tailwind CSS only.
  2. 2. Copy the source from the Code tab into components/ui/flashlight-reveal.tsx.
  3. 3. Import it and adjust props.
Dependencies
None
Peer
react ≥ 18, tailwindcss ≥ 4
Added
13 Oct 2026
Updated
—

02Usage

The default configuration. Change properties above to generate a tailored example in the Usage tab.

example.tsx
import { FlashlightReveal } from "@/components/ui/flashlight-reveal";

export function FlashlightRevealExample() {
  return (
    <div className="relative h-80 w-full overflow-hidden rounded-xl">
      <FlashlightReveal
        cover={<p className="p-6 font-mono text-xs uppercase tracking-widest text-white/50">Move the light</p>}
      >
        <div className="flex h-full items-center justify-center bg-white p-8 dark:bg-zinc-950">
          <p className="text-3xl font-medium tracking-tight">Hidden in plain sight.</p>
        </div>
      </FlashlightReveal>
    </div>
  );
}

03Props

PropTypeDefaultDescription
childrenReactNode—Content revealed by the light. Always rendered and accessible.
coverReactNode—Decorative content drawn on the dark layer (aria-hidden).
radiusnumber150Radius of the light in px.
softnessnumber0.6Edge feather, 0 (hard) to 1 (fully soft).
smoothingnumber0.8Follow lag per 60fps frame, 0 (instant) to 0.95.
darknessnumber0.94Opacity of the dark layer.
overlayColorstring"#0A0B0D"Colour of the dark layer.
glowstring"#FF7448"Soft-light tint inside the beam; also the toggle's focus ring.
showTogglebooleantrueRender the Reveal all toggle button (aria-pressed).
touchBehavior"follow" | "reveal""follow"Touch: the light follows the finger, or a tap reveals everything.
revealedboolean—Controlled full reveal.
defaultRevealedbooleanfalseInitial full reveal (uncontrolled).
onRevealedChange(revealed: boolean) => void—Called when the toggle or a touch reveal changes the state.
toggleLabelstring"Reveal all"Visible label of the toggle.
...propsHTMLAttributes<HTMLDivElement>—Forwarded to the root, which is absolute inset-0 — place it inside a positioned parent.

04Features

  • 01Radial CSS mask with adjustable radius and feathered edge
  • 02Eased follow in a self-stopping rAF loop; CSS variables, no re-renders
  • 03Light follows keyboard focus inside the revealed content
  • 04Reveal all toggle that animates the beam open to the whole area
  • 05Touch: follow the finger or tap to reveal everything
  • 06Optional decorative cover layer and warm soft-light glow
motion · tweeninput · pointerinput · focusinput · keyboardinput · click

05Accessibility

  • The reveal is visual only: content is never hidden from screen readers and stays focusable and clickable.
  • The dark layer, cover and glow are aria-hidden and ignore pointer events.
  • Keyboard focus (focus-visible) moves the light onto the focused element so it is always visible.
  • The Reveal all toggle is a real button with aria-pressed and a visible focus ring.
  • prefers-reduced-motion makes the light jump to its target with no easing.