Skip to content
shadcn.io

shadcn.io is not affiliated with official shadcn/ui

Text

Pro

Erase Text for React

Text you rub out with the pointer, its letters drifting back once the pointer has passed. For React with Base UI, when plain copy should feel like a surface to touch.

Framework

Erase Text lets the pointer rub the text out. The letter under the pointer fades away at once, and its neighbours with it, so sweeping across the line wipes a trail through it; once the pointer has passed, each letter lingers a moment, then drifts back, like chalk on a board that mends itself.

Use it for a playful headline or an interactive callout. To scramble the letters under the pointer instead, use Scrambled Text; to thicken them, Variable Proximity. It's CSS only: each letter knows whether it, or a neighbour one or two letters away, is under the pointer from sibling selectors (:hover + *, :has(+ :hover)), and a transition fades it out quickly and back slowly. No script runs, at rest or under the pointer.

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 { EraseText } from "@/components/ui/erase-text";
<h2>
  <EraseText text="Sweep across to wipe the board" />
</h2>

Demos

Reach

reach is how far the eraser reaches past the letter under the pointer: 0 for that letter alone, a fine pencil eraser; 1 for one more on each side; 2, the default, for two, the outer ones half erased, a wide felt duster.

Preview width

Words

by="words" erases whole words instead of letters, and suits scripts whose letters join, such as Arabic. duration is how long an erased letter or word takes to come back, 1200 ms by default.

Preview width

Accessibility

Screen readers read the text once, from a visually hidden copy, never letter by letter. The text is whole whenever the pointer isn't on it, so keyboard users miss nothing. On a touch screen, the letters under a finger fade while it presses on them, where the browser marks pressed elements (:active), and come back when it lifts; a tap never leaves letters stuck erased, and scrolling past erases nothing. Erasing is a fade rather than movement, so it's the same with reduced motion.

FAQ

How does it work without a script?

Each letter is its own element. The one under the pointer matches :hover; its neighbours match :hover + * (after it) or :has(+ :hover) (before it), and two away, the same with one more step. Each distance sets its own CSS variable, and the erase-text-unit utility the install adds to your stylesheet turns them into the letter's opacity.

Why does it erase fast and come back slowly?

The transition's length depends on whether a letter is under the eraser: 80 ms while it's being erased, so the eraser feels decisive, and duration once it's clear, easing in, so the letter lingers before it returns.

Does the eraser reach across words and lines?

Across words, yes: the letter after a space is the next one along. Across lines it follows the text, so the end of one line and the start of the next are neighbours, but letters stacked above and below each other aren't.

Does it work with Arabic and other joined scripts?

Use by="words": each word stays whole, so its letters keep joining, and whole words fade instead.

Does it need JavaScript?

No. It's markup and CSS, so it works before the page's script loads, and without it.

What happens with reduced motion?

The same: letters fade out and back without moving, which reduced motion allows.

API Reference

EraseText

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

PropType
textstring

The text.

by?"characters" | "words"

What the eraser takes: each character, or whole words (better for scripts whose letters join, such as Arabic).

Type
"characters" | "words"
Default
"characters"
duration?number

How long an erased letter takes to come back, in milliseconds.

Default
1200
reach?0 | 1 | 2

How far the eraser reaches past the letter under the pointer: that letter alone, one more on each side, or two (the outer ones half erased).

Type
0 | 1 | 2
Default
2
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

Forwarded to the part.

CSS variableType
--erase-text-durationstring

How long an erased letter takes to come back (1200ms).

All 97 text effects