Skip to content
shadcn.io

shadcn.io is not affiliated with official shadcn/ui

Text

Pro

Kerning Text for React

Text whose letters part around the pointer, as if it were kerning the line by hand. For React with Base UI, when a headline should feel carefully typeset.

Framework

Kerning Text opens a little space around the letter under the pointer: its neighbours step aside, the next ones a little less, and they close up again as the pointer moves on, so a gap slides through the word with the pointer. The word keeps its width, so nothing around it moves.

Use it for a typographic headline: a type foundry's specimen, a designer's name, an editorial title. To thicken letters instead, use Variable Proximity; to pull them towards the pointer, Magnet Text; to fade them away, Erase Text. It's CSS only: each letter knows from :hover, + and :has() which side of the hovered letter it's on and how far, and a CSS utility the install adds to your stylesheet moves it with translate. There's no JavaScript at all.

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 { KerningText } from "@/components/ui/kerning-text";
<h1 className="uppercase">
  <KerningText text="Typography" />
</h1>

Demos

Intensity

intensity is how far the letters beside the pointer step away: subtle, medium, the default, or strong for a wide gap.

Preview width

Inside a link or a button, keyboard focus tracks every word out a little from 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 in right-to-left text the letters part the right way round. The gap only opens where the device can hover, so a tap never leaves letters apart. With reduced motion the letters step aside without easing.

FAQ

Does it need JavaScript?

No. Each letter matches selectors such as :hover + * (right after the hovered letter) and :has(+ :hover) (right before it), each setting its own CSS variable, and the utility turns those into a translate. It works before any script has loaded.

Why does the gap stay inside one word?

Each word is kept whole on its line, so a letter can only see its neighbours in the same word. The word's first and last letters step half as far, so the spaces between words stay spaces.

Does it change the width of the line?

No. The letters move with translate, which never changes the layout: the letters beside the pointer step away and the next ones close in a little to make room, so the word keeps its width.

What happens on a touch screen?

Nothing moves: the gap opens only on devices with a pointer that can hover, so the text simply reads as it is.

Does it work in right-to-left text?

Yes. The direction comes from the text itself, so in Arabic or Hebrew the letters before the hovered one step right and the ones after it step left. Splitting text into letters breaks the joins of Arabic script, though, so it suits Hebrew and Latin text best.

What happens with reduced motion?

The gap still follows the pointer, since it only answers what you do, but the letters step there without easing.

API Reference

KerningText

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

PropType
textstring

The text.

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

How far the letters beside the pointer move apart: subtle, medium, or strong for a wide gap.

Type
"subtle" | "medium" | "strong"
Default
"medium"
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
--kerning-text-spreadstring

How far a letter beside the pointer moves (0.14em).

All 97 text effects