# Spotlight text

> A light follows the cursor and reveals the copy.

- Type: Component (light)
- Page: https://textlab.dev/components/spotlight-text
- Markdown: https://textlab.dev/components/spotlight-text.md
- Registry item: https://textlab.dev/r/spotlight-text.json
- Source file: `registry/textlab/spotlight-text/spotlight-text.tsx`
- Dependencies: none
- Variants: reveal, glow, outline
- Keywords: spotlight, flashlight, torch, cursor reveal, mask, hover light

## When to use

- Hero statements meant to be explored.
- Dark, cinematic sections.

## When not to use

- Instructions or anything people must read in full immediately.
- Light backgrounds with the glow variant.

## Installation

### CLI

```bash
npx shadcn@latest add @textlab/spotlight-text
pnpm dlx shadcn@latest add @textlab/spotlight-text
```

The `@textlab` name needs `"registries": { "@textlab": "https://textlab.dev/r/{name}.json" }` in `components.json`. Without it, use the full URL:

```bash
npx shadcn@latest add https://textlab.dev/r/spotlight-text.json
```

Import the tokens once in your root layout: `import "@/components/textlab/tokens.css";`

### Manual

1. Install the dependencies: `npm install motion@12`
2. Copy `text-fx` (https://textlab.dev/r/text-fx.json) and this component into `components/textlab/`.

## Usage

```tsx
import { SpotlightText } from "@/components/textlab/spotlight-text/spotlight-text";

export function Example() {
  return <SpotlightText as="h2" text="Look around" variant="glow" />;
}
```

## API reference

### SpotlightText

| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| `text` (required) | `string` | – | The copy. |
| `variant` | `"reveal" \| "glow" \| "outline"` | `"reveal"` | Lift dim text, add a warm light, or fill hollow letters under the light. |
| `radius` | `number` | `2.2` | Radius of the light in em. |
| `color` | `string` | `var(--tl-fx-glow)` | Light color for the glow variant. |
| `dim` | `number` | `0.22` | Visibility outside the light, 0 to 1. |
| `as` | `ElementType` | `"span"` | Rendered element. |
| `reducedMotion` | `"user" \| "always" \| "never"` | `"user"` | user follows the OS setting; always shows the still version. |
| `className` | `string` | – | Merged onto the root. |

## Accessibility

- Screen readers get the text from a hidden copy.
- Outside the light the text stays legible at reduced contrast; raise dim if it must pass AA.

## Motion

- The light trails the pointer slightly, like a heavy torch.
- When the pointer leaves, the light fades rather than snapping off.

## Reduced motion

Shows the text normally with no light.

## Performance

- A radial mask driven by CSS variables written once per frame while moving.

## Notes for AI

- Use only the props documented above. Do not invent props.
- Keep the screen-reader text and the reduced-motion branch when editing the source.
- Pick a variant from: reveal, glow, outline.

## Related

- [Holographic text](https://textlab.dev/components/holo-text.md): Foil that shifts color as you move across it.
- [Glass text](https://textlab.dev/components/glass-text.md): Glass letters that bend the scene behind them.
- [Variable proximity](https://textlab.dev/components/variable-proximity.md): Weight and width swell near the cursor.

## Also in light

- [Gradient text](https://textlab.dev/components/gradient-text.md): Color flows slowly through the letters.
- [Shimmer text](https://textlab.dev/components/shimmer-text.md): A calm light passes across the words.
- [Neon sign](https://textlab.dev/components/neon-text.md): A neon sign that hums and flickers on.
- [Aurora text](https://textlab.dev/components/aurora-text.md): Northern lights drift inside the letters.

## Source

### components/textlab/spotlight-text/spotlight-text.tsx

```tsx
"use client";

import { useRef, type CSSProperties, type ElementType } from "react";
import { srOnly } from "../lib/a11y";
import { usePointerVars } from "../lib/use-pointer-vars";
import { useReduced, type ReducedMotion } from "../lib/use-reduced";

export type SpotlightTextVariant = "reveal" | "glow" | "outline";

export interface SpotlightTextProps {
  text: string;
  /** reveal lifts dim text to full, glow adds a warm light, outline fills hollow letters under the light. */
  variant?: SpotlightTextVariant;
  /** Radius of the light, in em. */
  radius?: number;
  /** Light color for the glow variant. */
  color?: string;
  /** How visible the text is outside the light, 0 to 1. */
  dim?: number;
  as?: ElementType;
  reducedMotion?: ReducedMotion;
  className?: string;
  style?: CSSProperties;
}

/**
 * A light follows the cursor and reveals the copy. Works with touch too: drag a finger across it.
 * Outside the light the text stays legible, just quieter.
 */
export function SpotlightText({ text, variant = "reveal", radius = 2.2, color = "var(--tl-fx-glow, #f59e0b)", dim = 0.22, as: Tag = "span", reducedMotion = "user", className, style }: SpotlightTextProps) {
  const ref = useRef<HTMLElement | null>(null);
  const reduced = useReduced(reducedMotion);
  usePointerVars(ref, { enabled: !reduced, rate: 14, rest: null });

  if (reduced) {
    return (
      <Tag className={className} style={style}>
        {text}
      </Tag>
    );
  }

  const mask = `radial-gradient(circle ${radius}em at var(--tl-x, 50%) var(--tl-y, 50%), #000 0%, rgb(0 0 0 / 0.6) 45%, transparent 100%)`;
  const base: CSSProperties =
    variant === "outline"
      ? { WebkitTextFillColor: "transparent", WebkitTextStroke: "0.02em color-mix(in oklab, currentColor 55%, transparent)" }
      : { opacity: dim };

  return (
    <Tag ref={ref} className={className} style={{ position: "relative", display: "inline-block", touchAction: "pan-y", ...style }}>
      <span style={srOnly}>{text}</span>
      <span aria-hidden="true" style={base}>
        {text}
      </span>
      <span
        aria-hidden="true"
        style={{
          position: "absolute",
          inset: 0,
          WebkitMaskImage: mask,
          maskImage: mask,
          opacity: "calc(0.25 + var(--tl-in, 0) * 0.75)",
          color: variant === "glow" ? `color-mix(in oklab, ${color} 55%, white)` : undefined,
          textShadow: variant === "glow" ? `0 0 0.3em ${color}, 0 0 0.8em color-mix(in oklab, ${color} 50%, transparent)` : undefined,
        }}
      >
        {text}
      </span>
    </Tag>
  );
}

export default SpotlightText;
```

Full library index: https://textlab.dev/llms.txt
