Collaboration
Project Management
Finance
Reel
A composable, Instagram-style Reel component with progress indicators and navigation controls.
Installation
npx love-ui@latest add reelUsage
import { Reel, ReelContent, ReelItem, ReelVideo, ReelImage, ReelProgress, ReelControls, ReelPlayButton, ReelMuteButton, ReelPreviousButton, ReelNextButton, ReelNavigation, ReelOverlay, ReelHeader, ReelFooter } from "@/components/reel"<Reel items={reelItems}>
<ReelProgress />
<ReelContent>
{(item) => (
<ReelItem>
<ReelVideo src={item.videoUrl} />
<ReelOverlay>
<ReelHeader>{item.title}</ReelHeader>
<ReelFooter>{item.description}</ReelFooter>
</ReelOverlay>
</ReelItem>
)}
</ReelContent>
<ReelControls>
<ReelPlayButton />
<ReelMuteButton />
<ReelPreviousButton />
<ReelNextButton />
</ReelControls>
<ReelNavigation />
</Reel>Features
- Full-height, 9:16 aspect ratio container optimized for vertical video
- Progress indicators showing current and total reels
- Automatic video playback with seamless transitions
- Support for both video and image content
- Customizable controls for play/pause, mute/unmute, and navigation
- Touch-friendly navigation by tapping left/right sides
- Composable architecture for custom overlays and content
- Header and footer sections for metadata display
- Social media-style interactions support
- Keyboard accessibility for all controls
- Auto-advance to next reel when current finishes
- Responsive design that scales with viewport height
Examples
Reel with Images
Display a series of images with automatic timing and transitions.
Mountain Adventure
Exploring the peaks
"use client";
import {
Reel,
ReelContent,
ReelControls,
ReelFooter,
ReelImage,
ReelItem,
type ReelItem as ReelItemType,
ReelMuteButton,
ReelNavigation,
ReelNextButton,
ReelPlayButton,
ReelPreviousButton,
ReelProgress,
} from "../../../../../packages/reel";
const reels: ReelItemType[] = [
{
id: 1,
type: "image",
src: "https://images.unsplash.com/photo-1753731683731-1032f9457b02?w=1080&h=1920&fit=crop",
alt: "Mountain Adventure",
title: "Mountain Adventure",
description: "Exploring the peaks",
duration: 5,
},
{
id: 2,
type: "image",
src: "https://images.unsplash.com/photo-1506905925346-21bda4d32df4?w=1080&h=1920&fit=crop",
alt: "Ocean Waves",
title: "Ocean Waves",
description: "Sunset at the beach",
duration: 5,
},
{
id: 3,
type: "image",
src: "https://images.unsplash.com/photo-1441974231531-c6227db76b6e?w=1080&h=1920&fit=crop",
alt: "Forest Trail",
title: "Forest Trail",
description: "Into the woods",
duration: 5,
},
];
const Example = () => (
<Reel data={reels}>
<ReelProgress />
<ReelContent>
{(reel) => (
<ReelItem>
<ReelImage
alt={reel.alt ?? ""}
duration={reel.duration}
src={reel.src}
/>
<ReelFooter className="pb-16">
<div className="text-white">
<h3 className="font-semibold text-lg">{reel.title}</h3>
<p className="text-sm opacity-90">{reel.description}</p>
</div>
</ReelFooter>
</ReelItem>
)}
</ReelContent>
<ReelNavigation />
<ReelControls>
<ReelPreviousButton />
<div className="flex gap-2">
<ReelPlayButton />
<ReelMuteButton />
</div>
<ReelNextButton />
</ReelControls>
</Reel>
);
export default Example;
Custom Reel
Fully customized reel with social media-style interface including author info, likes, comments, and share buttons.
Check out this amazing view! #travel #adventure
"use client";
import {
Reel,
ReelContent,
ReelFooter,
ReelHeader,
ReelItem,
ReelProgress,
ReelVideo,
} from "../../../../../packages/reel";
import { Button } from "../../../../../packages/ui/src/ui/button";
import { Heart, MessageCircle, Share } from "lucide-react";
import Image from "next/image";
type CustomReelItem = ReelItem & {
author: string;
avatar: string;
description: string;
likes: string;
comments: string;
};
const reels: CustomReelItem[] = [
{
id: 1,
type: "video",
author: "Connor",
avatar:
"https://images.unsplash.com/photo-1472099645785-5658abf4ff4e?w=40&h=40&fit=crop&crop=face",
description: "Check out this amazing view! #travel #adventure",
likes: "12.5K",
comments: "234",
duration: 6,
src: "https://wajxiz6qhqyqkm0o.public.blob.vercel-storage.com/grok-imagine-1.mp4",
},
{
id: 2,
type: "video",
author: "Thomas",
avatar:
"https://images.unsplash.com/photo-1659691349345-f9e2e17248cb?w=40&h=40&fit=crop&crop=face",
description: "Living my best life 🌟 #happy #vibes",
likes: "8.3K",
comments: "156",
duration: 6,
src: "https://wajxiz6qhqyqkm0o.public.blob.vercel-storage.com/grok-imagine-2.mp4",
},
{
id: 3,
type: "video",
author: "Mike Nathan",
avatar:
"https://images.unsplash.com/photo-1500648767791-00dcc994a43e?w=40&h=40&fit=crop&crop=face",
description: "Creating magic every day ✨ #creativity",
likes: "15.2K",
comments: "412",
duration: 6,
src: "https://wajxiz6qhqyqkm0o.public.blob.vercel-storage.com/grok-imagine-3.mp4",
},
];
const Example = () => (
<Reel data={reels}>
<ReelProgress />
<ReelContent>
{(reel) => (
<ReelItem>
<ReelVideo src={reel.src} />
<ReelHeader>
<div className="flex items-center gap-2">
<Image
alt={(reel as CustomReelItem).author}
className="h-6 w-6 rounded-full border-2 border-white"
height={24}
src={(reel as CustomReelItem).avatar}
unoptimized
width={24}
/>
<span className="font-medium text-sm text-white">
{(reel as CustomReelItem).author}
</span>
<Button className="ml-auto rounded-full bg-white/20 px-3 py-1 text-sm text-white backdrop-blur-sm transition-colors hover:bg-white/30">
Follow
</Button>
</div>
</ReelHeader>
<ReelFooter>
<div className="flex flex-col gap-2">
<p className="text-sm text-white">{reel.description}</p>
<div className="flex gap-2">
<Button
className="h-auto p-2 text-white hover:bg-white/10 hover:text-white"
variant="ghost"
>
<Heart className="h-6 w-6" />
<span className="text-xs">
{(reel as CustomReelItem).likes}
</span>
</Button>
<Button
className="h-auto p-2 text-white hover:bg-white/10 hover:text-white"
variant="ghost"
>
<MessageCircle className="h-6 w-6" />
<span className="text-xs">
{(reel as CustomReelItem).comments}
</span>
</Button>
<Button
className="h-auto p-2 text-white hover:bg-white/10 hover:text-white"
variant="ghost"
>
<Share className="h-6 w-6" />
<span className="sr-only text-xs">Share</span>
</Button>
</div>
</div>
</ReelFooter>
</ReelItem>
)}
</ReelContent>
</Reel>
);
export default Example;
Minimal Reel
Simple reel with just video content, progress bar, and navigation.
"use client";
import {
Reel,
ReelContent,
ReelItem,
ReelNavigation,
ReelProgress,
ReelVideo,
} from "../../../../../packages/reel";
const reels: ReelItem[] = [
{
id: 1,
type: "video",
src: "https://wajxiz6qhqyqkm0o.public.blob.vercel-storage.com/grok-imagine-1.mp4",
duration: 6,
title: "Grok Imagine Demo 1",
description: "First demo video",
},
{
id: 2,
type: "video",
src: "https://wajxiz6qhqyqkm0o.public.blob.vercel-storage.com/grok-imagine-2.mp4",
duration: 6,
title: "Grok Imagine Demo 2",
description: "Second demo video",
},
{
id: 3,
type: "video",
src: "https://wajxiz6qhqyqkm0o.public.blob.vercel-storage.com/grok-imagine-3.mp4",
duration: 6,
title: "Grok Imagine Demo 3",
description: "Third demo video",
},
];
const Example = () => (
<Reel data={reels}>
<ReelProgress />
<ReelContent>
{(reel) => (
<ReelItem>
<ReelVideo src={reel.src} />
</ReelItem>
)}
</ReelContent>
<ReelNavigation />
</Reel>
);
export default Example;