Hero Video Dialog
PronewA video poster with a play button that opens an accessible player, growing out of the thumbnail or entering with one of eight animations.
Installation
npx shadcn@latest add @blank-pro/hero-video-dialogNeeds a Blank Pro licence key and the @blank-pro registry. Set up Pro access
Usage
import { HeroVideoDialog } from "@/components/ui/hero-video-dialog"<HeroVideoDialog
src="https://www.youtube.com/embed/VIDEO_ID"
thumbnailSrc="/product-tour.jpg"
title="Product tour"
label="Product tour · 2 min"
/>The player is a real dialog: focus moves into it and back to the poster when it
closes, the page stops scrolling underneath, and Escape or a click on the
backdrop dismisses it. title names both the play button and the dialog for
screen readers, so it is required.
Embeds and files are told apart by the URL. YouTube, Vimeo or Loom links render
an iframe with autoplay=1 added; .mp4, .webm and .mov render a native
video element, and when there is no thumbnailSrc the first frame of the file
becomes the poster. The media mounts once the entrance settles, with the blurred
poster and a spinner in its place until the first frame arrives — no black flash
mid-animation.
With prefers-reduced-motion, every animation becomes a short fade.
Examples
Animations
morph grows the player out of the thumbnail with a shared layout transition
and returns it there on close. The other seven slide or scale it in over the
backdrop.
Video file
A self-hosted file needs no poster: the first frame is used.
API Reference
HeroVideoDialog takes every div prop for its root, plus:
| Prop | Type | Default |
|---|---|---|
src | string | — |
title | string | — |
description | string | — |
thumbnailSrc | string | first frame of a file |
thumbnailAlt | string | "" |
type | "iframe" | "video" | inferred from src |
animation | "morph" | "from-center" | "from-bottom" | "from-top" | "from-left" | "from-right" | "fade" | "top-in-bottom-out" | "left-in-right-out" | "morph" |
autoPlay | boolean | true |
aspectRatio | number | 16 / 9 |
label | ReactNode | — |
open | boolean | — |
defaultOpen | boolean | false |
onOpenChange | (open: boolean) => void | — |
children | ReactNode | — |
children replaces the poster image with your own content — a composed
screenshot, a live component — while the play button, label and dialog stay.
Every part carries a data-slot: hero-video-dialog-trigger,
hero-video-dialog-thumbnail, hero-video-dialog-play,
hero-video-dialog-label, hero-video-dialog-content,
hero-video-dialog-player and hero-video-dialog-close.