Sora UI

Dia Text Reveal

A gradient sweep that reveals text with a chromatic wash, powered by Motion.

Made by Axyl

Gradient sweep revealing a headline — scroll into view or refresh to replay.

Make interfaces feel smooth.

Installation

File Structure

dia-text-reveal.tsx

Usage

import { DiaTextReveal } from '@/components/sora-ui/texts/dia-text-reveal';

export default function Page() {
  return (
    <DiaTextReveal
      className="font-semibold text-3xl tracking-tight"
      text="Design systems that move with you."
    />
  );
}

Loop the wash:

<DiaTextReveal
  text="Always in motion."
  repeat
  repeatDelay={0.5}
  duration={1.5}
/>

Custom palette:

<DiaTextReveal
  text="Chromatic headline"
  colors={['#f0abfc', '#f472b6', '#fb923c', '#facc15', '#a3e635']}
/>

Cycle through multiple words (requires repeat):

<DiaTextReveal
  text={['smooth.', 'focused.', 'refined.']}
  repeat
  fixedWidth
  holdDuration={1}
  fadeDuration={0.6}
/>

Right-to-left sweep, custom color, and a completion callback:

<DiaTextReveal
  text="Reversed sweep."
  direction="rtl"
  textColor="#111111"
  onComplete={() => console.log('revealed')}
/>

Render as a different element and control it imperatively:

const handle = useRef<DiaTextRevealHandle>(null);

<DiaTextReveal ref={handle} as="h1" text="Controlled headline." startOnView={false} />
<button onClick={() => handle.current?.replay()}>Replay</button>

Props

PropTypeDefault
text?
string | string[]
-
colors?
string[]
["#f0abfc", "#f472b6", "#fb923c", "#facc15", "#a3e635"]
duration?
number
1.5
delay?
number
0
direction?
"ltr" | "rtl"
"ltr"
ease?
string | number[] | ((t: number) => number)
[0.23, 1, 0.32, 1]
fadeEase?
string | number[] | ((t: number) => number)
"easeInOut"
textColor?
string
"currentColor"
as?
React.ElementType
"span"
onComplete?
() => void
-
ref?
Ref<DiaTextRevealHandle>
-
repeat?
boolean
false
repeatDelay?
number
0.5
holdDuration?
number
1
fadeDuration?
number
0.6
fixedWidth?
boolean
false
startOnView?
boolean
true
once?
boolean
true
inViewMargin?
string
"0px"
className?
string
-

Accessibility

The revealed string is always in the DOM — the gradient sweep and opacity fade are visual only. Screen readers announce the current phrase as plain text.

When prefers-reduced-motion: reduce is set, useReducedMotion() skips the sweep, fade, and phrase rotation entirely: the first string in text renders fully visible at the final gradient position (background-position: 0%, opacity: 1). Imperative play() / replay() become no-ops. No extra configuration needed.

If you cycle phrases with repeat and an array, only the first phrase is shown under reduced motion — prefer a single string (or put the most important phrase first) when that static fallback matters for meaning.

Credits

Inspired by Dia Text. Reimplemented for Motion and React.

This is a from-scratch rebuild of the idea, not a port: the gradient-wash reveal and multi-phrase cycling are reimplemented in React with motion/react (motion values, useTransform, imperative animate() sequencing), and extended with a repeat fade-hold-reset cycle, direction, textColor, ease/fadeEase, polymorphic as, and an imperative play/replay control ref.

Built by Axyl. A motion-first component registry for React.

Last updated: 7/10/2026