Skip to content
shadcn.io

shadcn.io is not affiliated with official shadcn/ui

Text

Pro

Variable Proximity for React

Text whose letters grow heavier as the pointer comes near, each by its own distance. For React with Base UI, when a headline should answer the pointer.

Framework

Variable Proximity thickens each letter as the pointer comes near it: the letter right under the pointer is at its heaviest and the weight fades with distance, so a bold patch follows the pointer through the text. When the pointer leaves, every letter eases back to rest.

Use it for a large headline or a word on a landing page that invites the pointer over it. To light letters up rather than thicken them, use Spotlight Text; to swell a display word across its column, Text Pressure; to push letters apart, Kerning Text. The letters' centres are measured once as the pointer enters; each move writes the pointer's position to two CSS variables, and a CSS utility the install adds to your stylesheet works out each letter's weight from its distance, with no animation frame loop.

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 { VariableProximity } from "@/components/ui/variable-proximity";
<VariableProximity text="Bring the pointer closer" />

Demos

Falloff

falloff is how the weight fades between the pointer and radius: linear evenly, quadratic sharply, with only the nearest letters heavy, and smooth in a soft bell with a wide peak.

Preview width

Range

minWeight is the weight at rest and maxWeight the weight under the pointer, any weights your font has; radius is how far the pointer reaches, in pixels.

Preview width

Accessibility

Screen readers read the text once, from a visually hidden copy, never letter by letter. The effect only follows the pointer and changes no meaning, so keyboard and touch users miss nothing. Every letter keeps the width of its heaviest weight, so the text never reflows under the pointer; with reduced motion the weight follows the pointer without easing.

FAQ

Which font does it need?

A variable font with a weight axis, such as Inter, Geist, Hanken Grotesk or Roboto Flex, for the weight to change smoothly. With a static font the weights snap to the ones you've loaded, usually just regular and bold.

Can it change slant or another axis too?

Each letter's nearness, from 0 at the radius to 1 under the pointer, is the --variable-proximity-t variable on its .variable-proximity-glyph, so your stylesheet can drive any axis from it: .variable-proximity-glyph { font-variation-settings: "slnt" calc(-10 * var(--variable-proximity-t)); }. An axis that widens letters, such as wdth, will shift the line.

Why is the text a little wider than usual?

Each letter holds the width of its heaviest weight, so the line doesn't shift as letters thicken. A smaller maxWeight keeps it closer to its usual spacing.

Does it run on every frame?

No. It measures the letters once as the pointer comes over the text and then only writes the pointer's position on each move; the browser works out every letter's weight in CSS. Nothing runs while the pointer is elsewhere.

What happens on a touch screen?

A tap thickens the letters around it and they ease back when the finger lifts.

What happens with reduced motion?

The weight still follows the pointer, since it only answers what you do, but without easing between weights.

API Reference

VariableProximity

<span> data-slot="variable-proximity"

PropType
textstring

The text.

falloff?"linear" | "quadratic" | "smooth"

How the weight fades with distance: evenly, sharply near the pointer (quadratic), or in a soft bell with a wide peak (smooth).

Type
"linear" | "quadratic" | "smooth"
Default
"linear"
maxWeight?number

The weight right under the pointer. @default 900.

minWeight?number

The weight at rest, beyond the radius. @default 400.

radius?number

How far from the pointer letters are reached, in pixels. @default 120.

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
--variable-proximity-maxstring

The weight under the pointer (900).

--variable-proximity-minstring

The weight at rest (400).

--variable-proximity-radiusstring

How far letters are reached, in pixels, unitless (120).

  • Every detail deserves the spotlight

    Pro

    Spotlight Text

    Interactive

    Light the letters rather than thicken

  • Pro

    Text Pressure

    Interactive

    A word that swells across its column

  • Pro

    Magnify Text

    Interactive

    A lens that enlarges the letters

  • Pro

    Kerning Text

    Interactive

    Letters pushed apart near the pointer

  • Pro

    Erase Text

    Interactive

    Letters that fade under the pointer

  • Pro

    Magnet Text

    Interactive

    Letters pulled toward the pointer

All 97 text effects