Skip to content

Video Text

Large text that shows a video you supply through its letters. The text stays real text; a gradient fallback shows until the video plays.

Motionv0.1.0experimentalWCAG 2.2 AAView spec

Optional, and kept apart.

Nothing here is included in a project unless you add it, and the plain component it builds on is unchanged. This effect is decoration: it is hidden from screen readers, stands still for visitors who prefer reduced motion, and can be paused. Use Still on a preview to see that version.

Motion
import { VideoText } from "@rdloom/react";

// A public sample video (CC0) shows through the letters. Pass your own src. Until it loads, or for reduced motion,
// the letters show a gradient.
export default function VideoTextBasicExample() {
  return (
    <div className="flex w-full justify-center py-6">
      <VideoText src="https://interactive-examples.mdn.mozilla.net/media/cc0-videos/flower.mp4" className="px-4 text-8xl font-bold sm:text-9xl">Motion</VideoText>
    </div>
  );
}

Installation

npx rdloom add video-text

Copies the source into src/components/rdloom. Edit it freely: rdloom upgrade merges later versions into your changes.

It also adds rdloom-motion.css next to your tokens and imports it from the tokens file, once: no setup, and no inline styles. The plain components you already use are untouched.

Use another registry client
npx shadcn@latest add https://rdloom.vimalbhatt.com/r/video-text.json

Works, but without upgrade tracking, and you import the motion CSS yourself.

Usage

import { VideoText } from "@rdloom/react";

<div className="flex w-full justify-center py-6">
  <VideoText src="https://interactive-examples.mdn.mozilla.net/media/cc0-videos/flower.mp4" className="px-4 text-8xl font-bold sm:text-9xl">Motion</VideoText>
</div>

Dark

Night
import { VideoText } from "@rdloom/react";

export default function VideoTextDarkExample() {
  return (
    <div className="flex w-full justify-center bg-black py-6">
      <VideoText tone="dark" src="https://interactive-examples.mdn.mozilla.net/media/cc0-videos/flower.mp4" fallback="linear-gradient(90deg, #f472b6, #facc15)" className="px-4 text-8xl font-bold sm:text-9xl">
        Night
      </VideoText>
    </div>
  );
}

Paused

Still
import { VideoText } from "@rdloom/react";

export default function VideoTextPausedExample() {
  return (
    <div className="flex w-full justify-center py-6">
      <VideoText isPaused src="https://interactive-examples.mdn.mozilla.net/media/cc0-videos/flower.mp4" className="px-4 text-8xl font-bold sm:text-9xl">
        Still
      </VideoText>
    </div>
  );
}

API Reference

Defined by the spec. Components also accept the props of the React Aria component they wrap.

PropTypeDefault
childrenrequired

The text.

stringnone
src

URL of the video you supply. Without it the fallback gradient is shown.

stringnone
poster

URL of a poster image for the video.

stringnone
fallback

CSS background shown through the letters until the video plays, or instead of it.

string"linear-gradient(120deg, var(--rd-color-action-primary), var(--rd-color-feedback-info))"
tone

The surface the video box sits on: light draws a white box, dark a black one.

"light" | "dark""light"
isPaused

Pauses the video and shows the fallback gradient instead. Moving content that lasts more than five seconds should be stoppable.

booleanfalse

Accessibility

Role text, WCAG 2.2 AA. Tested with axe and keyboard tests; screen reader checks are in the audit checklist.

Keyboard

Not interactive.

Screen readers announce

  • Read as ordinary text: the effect is purely visual

What your code must do

  • The text is ordinary text in the page from the server render, readable with no JavaScript, and read once by screen readers
  • Decoration only: the animated layers are hidden from assistive technology and never take focus
  • Stands still for visitors who ask for less motion (prefers-reduced-motion), and can also be shown still with the rdm-still class or isPaused
  • In forced-colors (high contrast) mode the text is drawn in the system colours with no effect
  • Does not flash: nothing changes more than three times in a second (WCAG 2.3.1)
  • Optional: it is a separate component, so projects that do not add it carry none of its code
  • No video is included: you supply src. The video is muted, plays inline, loops and is hidden from assistive technology
  • Until the video has loaded, and whenever it is paused, stopped by reduced motion or unavailable, the letters show the fallback gradient
  • A video behind letters has no guaranteed contrast: keep the text large and bold, and do not use it for text people must read to act
  • Decorative video needs no captions; if the video carries meaning, give that meaning in nearby text

Guidelines

Use it when

  • A large hero word over a short looping video

Avoid it when

  • Small text
  • Text people must read to act
  • Slow connections where the video is large

Don't

  • Autoplaying video with sound
  • Long videos with fast cuts or flashing

Design tokens

The semantic tokens this component uses. Change them once and every component follows; see Design tokens.

  • --rd-color-text-default
  • --rd-color-action-primary
  • --rd-color-feedback-info