Marketing

Hero Video Dialog

Pronew

A 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-dialog

Needs 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:

PropTypeDefault
srcstring—
titlestring—
descriptionstring—
thumbnailSrcstringfirst frame of a file
thumbnailAltstring""
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"
autoPlaybooleantrue
aspectRationumber16 / 9
labelReactNode—
openboolean—
defaultOpenbooleanfalse
onOpenChange(open: boolean) => void—
childrenReactNode—

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.