Browse docs
Browse docs
A thin, declarative wrapper over the native <video> — the moving-image twin of Image. It renders a URL you give it — no data fetching, no eval — and adds what a bare <video> lacks: it reserves the box before load (no layout shift), shows a poster / skeleton while loading, degrades to a graceful fallback on error, and supports access / visibleWhen gating like the form components.
The MUI twin of @dashforge/tw's Video — same public API, MUI internals.
<Video
src="https://mdn.github.io/shared-assets/videos/flower.mp4"
poster="https://picsum.photos/seed/dashforge-video/800/450"
aspectRatio={16 / 9}
rounded="lg"
/>An aspect-locked player with a poster. Because aspectRatio reserves the box, the layout doesn't shift while the video loads — and the poster fills the space until playback starts.
// Background-style loop — autoplay requires muted in most browsers.
<Video src={SRC} aspectRatio={16 / 9} rounded="lg" autoPlay loop muted playsInline controls={false} />A muted, looping, controls-free clip — the background-video pattern. Browsers only allow autoPlay when the video is muted; playsInline keeps it inline on iOS.
// on load error, a muted fallback replaces the player
<Video src="/missing.mp4" aspectRatio={16 / 9} rounded="md" fallback={<span>Video unavailable</span>} />When the source fails to load, Video replaces the player with a muted placeholder. Pass your own via fallback.
import { Video } from '@dashforge/ui';
// Player with a poster
<Video src={clip} poster={thumb} aspectRatio={16 / 9} rounded="lg" />
// Background-style loop (autoplay needs muted)
<Video src={loop} aspectRatio={1} autoPlay loop muted playsInline controls={false} />
// Multi-format delivery via <source> children
<Video aspectRatio={16 / 9}>
<source src="/clip.webm" type="video/webm" />
<source src="/clip.mp4" type="video/mp4" />
</Video>| Prop | Type | Default | Description |
|---|---|---|---|
src | string | — | Video source URL. Omit and pass <source> children for multi-format delivery. Same-origin / data: keeps it inside your boundary; an external host is egress. |
poster | string | — | Poster image shown before playback / while the first frame loads. Doubles as the anti-CLS + loading visual. |
aspectRatio | number | string | — | Locks the box shape before load (no layout shift). 16 / 9, 1, or a CSS string. |
fit | 'cover' | 'contain' | 'fill' | 'none' | 'scale-down' | 'cover' | How the video fills its box — CSS object-fit. |
rounded | 'none' | 'sm' | 'md' | 'lg' | 'full' | 'none' | Corner-radius token. |
controls | boolean | true | Show the native player controls. |
preload | 'none' | 'metadata' | 'auto' | 'metadata' | How much to preload. 'metadata' fetches dimensions/duration only. |
showSkeleton | boolean | true | Show a <Skeleton> while the first frame loads. Requires a reserved box and no poster, else skipped. |
fallback | ReactNode | — | Shown on load error. Defaults to a muted broken-media glyph. |
access | AccessRequirement | — | RBAC gate. hide → not rendered; disable / readonly → dimmed. Resolved against the nearest RbacProvider. |
visibleWhen | (engine: Engine) => boolean | — | Reactive visibility predicate against the form engine. No-op outside a <DashForm>. |
sx | SxProps<Theme> | — | MUI style override on the root wrapper. |
...rest | VideoHTMLAttributes | — | Native <video> attributes (autoPlay, loop, muted, playsInline, crossOrigin, …) forwarded to the element. |
aspectRatio, or width + height) — the poster/skeleton and the no-layout-shift guarantee both need a reserved box.poster is set it is the loading visual, so the skeleton is skipped; already-buffered video resolves on mount (no flash).autoPlay with muted (usually loop + playsInline) for the background-video pattern.<source> children instead of src to let the browser pick the best-supported format.src is fetched by the browser from that host. Self-host the asset to keep it inside your boundary.access and visibleWhen work exactly as on the form components (e.g. TextField).