Skip to content
WANCRAFT

C.42Typography & Text

Proximity Text

Letters swell in weight, width and scale as the pointer approaches — on any variable font.

NewReactCSSTailwindintermediate

Overview

Proximity Text turns a line of type into a field that reacts to the pointer. Every frame it reads each letter's position, applies a linear, smooth or gaussian falloff within a radius and writes font-variation-settings straight onto the letter: weight always, width when the font has a wdth axis, and optionally scale, slant and a colour blend. Letters ease towards their target so they settle rather than snap, the loop sleeps once everything is at rest, and it stops entirely offscreen or in background tabs. On touch devices it plays a slow idle wave (or stays static), and the plain text is exposed once for assistive technology.

01Installation

Method 01 · Registry

CLI verified

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

npx shadcn@latest add https://wancraft.my/r/proximity-text.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/proximity-text.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 { ProximityText } from "@/components/ui/proximity-text";

export function ProximityTextExample() {
  return (
    <ProximityText as="h2" className="text-6xl tracking-tight" />
  );
}

03Props

PropTypeDefaultDescription
textstring"Type that leans in"The text to render (exposed once to assistive technology).
as"span" | "p" | "h1" | "h2" | "h3" | "div""span"Element to render.
radiusnumber140Distance in px at which letters stop responding.
falloff"linear" | "smooth" | "gaussian""smooth"Response curve between the pointer and the radius.
minWeightnumber300wght axis value at rest.
maxWeightnumber800wght axis value under the pointer.
stretchnumber100wdth axis value under the pointer; 100 leaves the axis untouched.
scalenumber1Scale of the letter under the pointer.
slantnumber0Skew of the letter under the pointer, in degrees.
colorizebooleanfalseBlend nearby letters towards accent (color-mix in oklab).
accentstring"#FF7448"Colour used when colorize is on.
touchBehavior"wave" | "static""wave"What happens on devices without hover.
...propsHTMLAttributes—Native attributes are forwarded to the root element.

04Features

  • 01Per-letter font-variation-settings written from rAF — no React render per frame
  • 02Weight, width (wdth), scale, slant and colour responses
  • 03Linear, smooth and gaussian falloff within a radius
  • 04Eased settling; the loop sleeps when letters are at rest
  • 05Paused offscreen and in background tabs
  • 06Idle wave or static fallback on touch devices
motion · continuousinput · pointer

05Accessibility

  • The plain text is exposed once as visually hidden text; the per-letter spans are aria-hidden.
  • Purely decorative pointer response — no information depends on it.
  • With prefers-reduced-motion the letters stay at their rest weight and nothing animates.

06Limitations

  • Needs a variable font for smooth weight/width changes; static fonts snap to the nearest available weight or ignore the axis.
  • Changing weight changes letter widths, so give the line a little horizontal room.
  • Letters are inline-block spans, so kerning and ligatures across letters are not applied.