Video Bubble
wa-ui/video-bubbleFreeComponent
WhatsApp-style video message bubble with play/pause, duration badge, caption, and read receipts.
Install it
npx shadcn@latest add https://ui.meta-cloud-api.site/r/video-bubble.jsonSource
1"use client";23import * as React from "react";4import { cn } from "@/lib/utils";5import { type MessageStatus, MessageStatusIcon } from "./message-status";6import "@/components/ui/whatsapp/styles/whatsapp.css";78interface VideoBubbleProps extends React.HTMLAttributes<HTMLDivElement> {9 variant?: "incoming" | "outgoing";10 src: string;11 caption?: string;12 /** e.g. "0:42" */13 duration?: string;14 timestamp?: string;15 status?: MessageStatus;16 showTail?: boolean;17}1819const VideoBubble = React.forwardRef<HTMLDivElement, VideoBubbleProps>(20 (21 {22 className,23 variant = "incoming",24 src,25 caption,26 duration,27 timestamp,28 status,29 showTail = false,30 ...props31 },32 ref33 ) => {34 const isOutgoing = variant === "outgoing";35 const videoRef = React.useRef<HTMLVideoElement>(null);36 const [loaded, setLoaded] = React.useState(false);37 const [playing, setPlaying] = React.useState(false);3839 const togglePlay = () => {40 const video = videoRef.current;41 if (!video) return;42 if (video.paused) {43 video.play();44 setPlaying(true);45 } else {46 video.pause();47 setPlaying(false);48 }49 };5051 const handleEnded = () => setPlaying(false);5253 return (54 <div55 className={cn(56 "flex w-full",57 isOutgoing ? "justify-end" : "justify-start",58 showTail ? "mb-[6px]" : "mb-[2px]",59 className60 )}61 {...props}62 ref={ref}63 >64 <div65 className={cn(66 "font-wa relative max-w-[336px] overflow-hidden rounded-lg",67 showTail && (isOutgoing ? "rounded-br-[3px]" : "rounded-bl-[3px]")68 )}69 >70 {/* Video */}71 <div className="relative cursor-pointer bg-wa-gray-800" onClick={togglePlay}>72 {!loaded && (73 <div className="flex h-[200px] w-[336px] items-center justify-center">74 <div className="animate-pulse bg-wa-gray-700 absolute inset-0" />75 </div>76 )}7778 <video79 ref={videoRef}80 src={src}81 onLoadedData={() => setLoaded(true)}82 onEnded={handleEnded}83 playsInline84 preload="metadata"85 className={cn(86 "w-full max-h-[330px] object-cover transition-opacity duration-300",87 loaded ? "opacity-100" : "opacity-0"88 )}89 />9091// … truncated
Files it writes
More from wa-ui
All 29 items| Component | Registry | Kind | Access | Installs | Command |
|---|---|---|---|---|---|
| Action Buttonaction-button | wa-ui | Components | Free | 1 dep · 2 files | |
| Call Permissioncall-permission | wa-ui | Components | Free | 1 dep · 2 files | |
| Carousel Templatecarousel-template | wa-ui | Components | Free | 1 dep · 3 files | |
| Chat Bubblechat-bubble | wa-ui | Components | Free | no deps · 2 files | |
| Chat Headerchat-header | wa-ui | Components | Free | no deps · 2 files | |
| Chat List Itemchat-list-item | wa-ui | Components | Free | no deps · 2 files | |
| Chat Menuchat-menu | wa-ui | Components | Free | 1 dep · 2 files | |
| Contact Bubblecontact-bubble | wa-ui | Components | Free | 1 dep · 3 files |
