Skip to content
shadcn.io

shadcn.io is not affiliated with official shadcn/ui

Text

Pro

Xray Text for React

Text with a secret beneath it, shown through a round hole that opens and follows the pointer. For React with Base UI, when a headline hides a second message.

Framework

Xray Text hides a second message under the text. Where the pointer goes, a round hole opens in the text and shows the secret beneath it, in a colour of its own, like an x-ray passing over a poster. The hole glides after the pointer and closes where it leaves, and the text reads normally again.

Use it for a teaser: what's coming next, the truth behind a slogan, a before and after in one headline. To wipe from one message to the other along the line, use Text Reveal; to light the text itself rather than swap it, Spotlight Text. The text and the secret are two copies stacked in one place and masked by opposite CSS radial gradients, centred on two registered CSS properties that each move of the pointer writes and a transition eases, with no animation library.

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 { XrayText } from "@/components/ui/xray-text";
<h2>
  <XrayText secret="The future" text="The present" />
</h2>

Demos

Radius

radius is the hole's radius in pixels: small for a pinhole peek, large for a lens. By default it's one and a half times the text's size, so it grows with the text.

Preview width

Inside a link, keyboard focus shows the whole secret in place of the text, since a keyboard can't point at part of it.

Preview width

Accessibility

Screen readers read the text, then the secret, each once, from visually hidden copies; end the text with a full stop if they should sound like two sentences. Keyboard focus on a link around it shows the whole secret. On a touch screen, a touch opens the hole under the finger, and it closes when the finger lifts. With reduced motion the hole opens and follows the pointer at once.

FAQ

Does the secret need to be as long as the text?

About as long reads best: the two are stacked in one place, so each part of the secret sits under the part of the text it replaces. They needn't match exactly; the box fits whichever is wider.

Where does the hole come from?

It grows in where the pointer comes in, glides after it as it moves, and shrinks away where the pointer leaves. At rest it's closed, so the text is whole.

Can I change the secret's colour?

Pass revealColor, any CSS colour, including your theme's variables such as var(--primary), or set --xray-text-color in your stylesheet. By default it's a vivid blue, deeper on a light page and lighter on a dark one.

Do screen readers hear the secret?

Yes, right after the text, so someone who can't point at it doesn't miss what the text hides. Write the secret to make sense read aloud after the text.

How is the hole made?

The text's mask is clear inside a circle and solid outside it; the secret's is the opposite. Both are centred on --xray-text-x and --xray-text-y, which the pointer writes, and sized by one registered number that a transition opens and closes, so the two copies always meet in the same soft rim.

What happens with reduced motion?

The hole opens at full size under the pointer and follows it without gliding, and closes at once when the pointer leaves.

API Reference

XrayText

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

PropType
secretstring

The message hidden under the text, shown through the hole; keep it about as long as the text, so it lines up beneath it.

textstring

The text.

radius?number

The hole's radius, in pixels. By default one and a half times the text's size (1.5em), so it scales with the text.

revealColor?string

The secret's colour, any CSS colour. By default a vivid blue.

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
--xray-text-colorstring

The secret's colour.

--xray-text-radiusstring

The hole's radius (1.5em).

  • Pro

    Text Reveal

    Interactive

    Wipe between messages along the line

  • Every detail deserves the spotlight

    Pro

    Spotlight Text

    Interactive

    Light the text instead of swapping it

  • Pro

    Magnify Text

    Interactive

    A lens that enlarges the letters

  • Pro

    A secret kept under black bars

  • Pro

    Password Text

    Interactive

    Dots that turn into a secret

  • Pro

    Iris Text

    Entrance

    Letters opened through a circle

All 97 text effects