Skip to content
shadcn.io

shadcn.io is not affiliated with official shadcn/ui

Text

Pro

Magnet Text for React

Text whose letters lean towards the pointer like iron filings to a magnet, and spring home when it leaves. For React with Base UI, when a headline should feel drawn to the pointer.

Framework

Magnet Text pulls letters towards the pointer as it passes, each by its own distance, like iron filings near a magnet: letters below the pointer rise to meet it, letters above it dip, and along the line they tip and gather in around it. When the pointer leaves, they spring home with a little overshoot.

Use it for a headline, a name or a call to action that should feel alive under the pointer. To stretch letters towards the pointer instead of moving them, use Elastic Text; to thicken them, Variable Proximity; to part them, 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 translate and rotate from its offset to the pointer and its nearness, capped, and a CSS transition with a slight overshoot carries it there. There's no animation library and no 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 { MagnetText } from "@/components/ui/magnet-text";
<h1>
  <MagnetText text="Magnetic" />
</h1>

Demos

Intensity

intensity is how hard the letters are pulled and the farthest they go: subtle for a twitch, medium, the default, for a headline, strong for letters that reach. radius is how far from the pointer letters feel the pull, 160 pixels by default.

Preview width

Inside a link or a button, keyboard focus draws each word's letters a little towards its middle, a still state that needs no pointer.

Preview width

Accessibility

Screen readers read the text once, from a visually hidden copy, never letter by letter. Words wrap whole, and the line keeps its direction on a right-to-left page. Letters move by a fraction of their size, 0.15em and 10° at most by default, and never into each other, so the text stays readable while it moves. With reduced motion the letters still follow the pointer, without the spring.

FAQ

Why doesn't the letter under the pointer move?

It's already where the pointer is. Pulling the letters right beside the pointer hardest would crush them into each other, so along the line the pull and the tip are gentlest at the pointer and strongest a little way out; above and below the line, where letters can't collide, the nearest move most.

How far does the pull reach?

radius sets it, in pixels: letters farther from the pointer don't move. A larger radius makes a wide, gentle field; a smaller one a tight, quick one.

How is it different from Elastic Text?

Magnet Text moves whole letters, rigid, towards the pointer. Elastic Text leaves each letter in place and stretches it towards the pointer like rubber, then lets it spring back with a wobble.

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 position in CSS. Nothing runs while the pointer is elsewhere.

What happens on a touch screen?

A tap tugs the letters around it, and they spring home when the finger lifts.

What happens with reduced motion?

The letters still lean towards the pointer, since that only answers what you do, but they go straight there, without the spring.

API Reference

MagnetText

<span> data-slot="magnet-text"

PropType
textstring

The text.

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

How hard the letters are pulled, and the farthest they go: subtle for a twitch, medium, or strong for letters that reach.

Type
"subtle" | "medium" | "strong"
Default
"medium"
radius?number

How far from the pointer letters feel the pull, in pixels. @default 160.

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
--magnet-text-maxstring

The farthest a letter moves (0.15em).

--magnet-text-pullstring

How much of the way to the pointer a letter leans, 0 to 1 (0.25).

--magnet-text-radiusstring

How far letters feel the pull, in pixels, unitless (160).

  • Pro

    Text Pressure

    Interactive

    Letters that swell and stretch instead

  • Pro

    Letters thicken near the pointer

  • Pro

    Kerning Text

    Interactive

    Letters pushed apart, not pulled in

  • Turn it over

    Pro

    Tilt Text

    Interactive

    The word turns to face the pointer

  • Pro

    Elastic Text

    Interactive

    Letters stretch as the pointer passes

  • Pro

    Inertia Text

    Interactive

    Throw the whole word, it springs home

All 97 text effects