Video frame
A framed native video with controls and a poster image.
npx shadcn@latest add https://ui.goodtabs.co/r/video-frame.json
With the @goodtabs namespace in components.json: npx shadcn@latest add @goodtabs/video-frame
A 16 by 9 video showing its poster before playback.
Square
The same frame at a 1 by 1 ratio.
Usage
import { VideoFrame } from "@/components/ui/video-frame"
<VideoFrame poster="/poster.jpg" title="Product walkthrough">
<source src="/walkthrough.mp4" type="video/mp4" />
</VideoFrame>Props
| Prop | Type | Default | Description |
|---|---|---|---|
| poster | string | Poster image shown before playback. | |
| title | string | Accessible name for the video. | |
| ratio | "16/9" | "4/3" | "1/1" | Aspect ratio of the frame. Defaults to 16/9. | |
| maxWidth | string | Constrain the frame, for example "560px". |
Source
video-frame/video-frame.tsx
import * as React from "react";
import { cn } from "@/lib/utils";
type VideoFrameProps = Omit<React.ComponentProps<"video">, "title"> & {
/** Poster image shown before playback. */
poster: string;
/** Accessible name for the video. */
title: string;
/** Constrain the frame, for example "560px". */
maxWidth?: string;
/** Aspect ratio of the frame. */
ratio?: "16/9" | "4/3" | "1/1";
};
const ratios = { "16/9": "aspect-video", "4/3": "aspect-[4/3]", "1/1": "aspect-square" } as const;
/**
* A framed native video. The browser supplies the controls, so keyboard and
* screen reader support come for free. Pass sources as children.
*/
export function VideoFrame({
poster,
title,
maxWidth,
ratio = "16/9",
className,
style,
children,
...props
}: VideoFrameProps) {
return (
<div
className={cn("w-full overflow-hidden rounded-lg border bg-muted p-1", className)}
style={{ maxWidth }}
>
<video
controls
preload="none"
playsInline
poster={poster}
aria-label={title}
className={cn("block w-full rounded-md bg-background object-cover", ratios[ratio])}
style={style}
{...props}
>
{children}
</video>
</div>
);
}
For AI agents
Hand your agent this page, the markdown at /components/video-frame/prompt.md, or the Copy AI prompt button above.
When to use
- A product walkthrough or short demo on a landing page
- Any native video that needs a calm, bordered frame
When not to use
- Embeds from a video host, which want an iframe
- Autoplaying background video
Agent notes
- Server component; the native video element supplies the controls
- Pass sources and captions as children (source, track)
- preload is none, so the poster is the only request until play
- Other video props pass through to the element