Vertical Tabs
uselayouts/vertical-tabsFreeComponent
A vertical tab interaction with smooth content switching.
Live preview
live · rendered by the registry
Rendered by uselayouts on their own page — this is the component running, not a screenshot of it.Install it
npx shadcn@latest add https://uselayouts.com/r/vertical-tabs.jsonSource
1"use client";23import React, { useState, useEffect, useCallback } from "react";4import { motion, AnimatePresence } from "motion/react";5import { cn } from "@/lib/utils";6import { ArrowLeft01Icon, ArrowRight01Icon } from "@hugeicons/core-free-icons";7import { HugeiconsIcon } from "@hugeicons/react";89// Change Here10const SERVICES = [11 {12 id: "01",13 title: "Web Design",14 description:15 "Creating beautiful, functional, and user-centric digital experiences.",16 image:17 "https://images.unsplash.com/photo-1550745165-9bc0b252726f?q=80&w=1200",18 },19 {20 id: "02",21 title: "Framer Development",22 description: "Building high-performance, animated websites with Framer.",23 image:24 "https://images.unsplash.com/photo-1581291518633-83b4ebd1d83e?q=80&w=1200",25 },26 {27 id: "03",28 title: "Branding",29 description:30 "Defining your brand's visual identity and voice for a lasting impression.",31 image:32 "https://images.unsplash.com/photo-1555066931-4365d14bab8c?q=80&w=1200",33 },34];3536const AUTO_PLAY_DURATION = 5000;3738export default function VerticalTabs() {39 const [activeIndex, setActiveIndex] = useState(0);40 const [direction, setDirection] = useState(0);41 const [isPaused, setIsPaused] = useState(false);4243 const handleNext = useCallback(() => {44 setDirection(1);45 setActiveIndex((prev) => (prev + 1) % SERVICES.length);46 }, []);4748 const handlePrev = useCallback(() => {49 setDirection(-1);50 setActiveIndex((prev) => (prev - 1 + SERVICES.length) % SERVICES.length);51 }, []);5253 const handleTabClick = (index: number) => {54 if (index === activeIndex) return;55 setDirection(index > activeIndex ? 1 : -1);56 setActiveIndex(index);57 setIsPaused(false);58 };5960 useEffect(() => {61 if (isPaused) return;6263 const interval = setInterval(() => {64 handleNext();65 }, AUTO_PLAY_DURATION);6667 return () => clearInterval(interval);68 }, [activeIndex, isPaused, handleNext]);6970 const variants = {71 enter: (direction: number) => ({72 y: direction > 0 ? "-100%" : "100%",73 opacity: 0,74 }),75 center: {76 zIndex: 1,77 y: 0,78 opacity: 1,79 },80 exit: (direction: number) => ({81 zIndex: 0,82 y: direction > 0 ? "100%" : "-100%",83 opacity: 0,84 }),85 };8687 return (88 <section className="w-full bg-background py-8 md:py-16 lg:py-24">89 <div className="w-full px-4 md:px-8 lg:px-12 xl:px-20 mx-auto">90// … truncated
What it pulls in
npm packages
Files it writes
More from uselayouts
All 26 items| Component | Registry | Kind | Access | Installs | Command |
|---|---|---|---|---|---|
| 3D Book3d-book | uselayouts | Components | Free | 3 deps | |
| Animated Collectionanimated-collection | uselayouts | Components | Free | 5 deps | |
| Bento Cardbento-card | uselayouts | Components | Free | 5 deps | |
| Bottom Menubottom-menu | uselayouts | Components | Free | 6 deps | |
| Bucketbucket | uselayouts | Components | Free | 5 deps · 2 files | |
| Day Pickerday-picker | uselayouts | Components | Free | 5 deps | |
| Delete Buttondelete-button | uselayouts | Components | Free | 5 deps | |
| Discover Buttondiscover-button | uselayouts | Components | Free | 5 deps |
