Video
tool-ui/videoFreeBlock
Video playback with controls and poster.
See it running
Open the demo on tool-ui
www.tool-ui.com/components/videoInstall it
npx shadcn@latest add https://www.tool-ui.com/r/video.jsonSource
1"use client";23import * as React from "react";4import { ExternalLink, Play } from "lucide-react";5import { cn, Button } from "./_adapter";67import {8 formatDuration,9 getFitClass,10 openSafeNavigationHref,11 OVERLAY_GRADIENT,12 RATIO_CLASS_MAP,13} from "../shared/media";14import { VideoProvider, useVideo } from "./context";15import type { SerializableVideo } from "./schema";16import {17 getMuteMediaEvent,18 normalizeVideoDataForCallback,19 resolveVideoNavigation,20} from "./video-helpers";2122const FALLBACK_LOCALE = "en-US";2324export interface VideoProps extends SerializableVideo {25 className?: string;26 // Keep behavior flags intentionally minimal; prefer explicit variants over more booleans.27 autoPlay?: boolean;28 defaultMuted?: boolean;29 onNavigate?: (href: string, video: SerializableVideo) => void;30 onMediaEvent?: (type: "play" | "pause" | "mute" | "unmute") => void;31}3233function VideoRoot(props: VideoProps) {34 const { defaultMuted = true, ...rest } = props;3536 return (37 <VideoProvider defaultState={{ muted: defaultMuted }}>38 <VideoInner {...rest} />39 </VideoProvider>40 );41}4243function VideoInner(props: Omit<VideoProps, "defaultMuted">) {44 const {45 className,46 autoPlay = true,47 onNavigate,48 onMediaEvent,49 ...serializable50 } = props;5152 const {53 id,54 src,55 poster,56 title,57 description,58 href: rawHref,59 domain,60 durationMs,61 ratio = "16:9",62 fit = "cover",63 createdAt,64 source,65 locale: providedLocale,66 } = serializable;6768 const locale = providedLocale ?? FALLBACK_LOCALE;69 const { sanitizedHref, sanitizedSourceUrl, primaryHref } =70 resolveVideoNavigation(rawHref, source?.url);7172 const videoData: SerializableVideo = normalizeVideoDataForCallback(73 serializable,74 {75 ratio,76 fit,77 locale,78 sanitizedHref,79 sanitizedSourceUrl,80 },81 );8283 const { state, setState, setVideoElement } = useVideo();84 const videoRef = React.useRef<HTMLVideoElement | null>(null);85 const previousMutedRef = React.useRef(state.muted);8687 React.useEffect(() => {88 setVideoElement(videoRef.current);89 return () => setVideoElement(null);90 }, [setVideoElement]);9192 React.useEffect(() => {93 const video = videoRef.current;94 if (!video) return;95 if (video.muted !== state.muted) {96 video.muted = state.muted;97 }98 }, [state.muted]);99100 React.useEffect(() => {101 const video = videoRef.current;102 if (!video) return;103 if (state.playing && video.paused) {104// … truncated
What it pulls in
npm packages
Other registry items
Files it writes
More from tool-ui
All 27 items| Component | Registry | Kind | Access | Installs | Command |
|---|---|---|---|---|---|
| Approval Cardapproval-card | tool-ui | Blocks | Free | 2 deps · 11 files | |
| Audioaudio | tool-ui | Blocks | Free | 2 deps · 9 files | |
| Chartchart | tool-ui | Blocks | Free | 2 deps · 8 files | |
| Citationcitation | tool-ui | Blocks | Free | 2 deps · 15 files | |
| Code Blockcode-block | tool-ui | Blocks | Free | 3 deps · 11 files | |
| Code Diffcode-diff | tool-ui | Blocks | Free | 3 deps · 10 files | |
| Data Tabledata-table | tool-ui | Blocks | Free | 1 dep · 17 files | |
| Geo Mapgeo-map | tool-ui | Blocks | Free | 4 deps · 12 files |
