Circle Menu
Dialog Form
Dominoes List Scroll
Dominoes Scroll Indicator
Eagle Vision
Electric AI Input
File Input
Flip Scroll
Glowing Scroll Indicator
Horizontal Scroll
Icon Wheel
Image Pile
Interactive CTA
Interactive Folder
Interest Picker
Jelly Loader
Leave Rating
Mask Cursor Effect
Magnet Tabs
Masonry Grid
OTP Input
Photo Gallery
Pixelated Carousel
Rolling Ball Scroll Indicator
Rubik Cube
Sidebar
Sine Wave
Skeumorphic Music Card
Social Media Card
Stacked Input Form
Stack Scroll
Trading Card
Sidebar
A collapsible navigation sidebar with smooth expand/collapse animations and hover previews. Features icon-based navigation with animated content panels that slide in and out seamlessly.
Install dependencies
npm i framer-motion lucide-react    Utility function
Create a file lib/utils.ts and paste this code
import { ClassValue, clsx } from 'clsx';
import { twMerge } from 'tailwind-merge';
export function cn(...inputs: ClassValue[]) {
  return twMerge(clsx(inputs));
}Component
Create a file sidebar.tsx in your components folder and paste this code
'use client';
import { Cloud, Folder, Home, Menu, PanelLeftClose, PanelsTopLeft, Star } from 'lucide-react';
import React, { useState } from 'react';
import { AnimatePresence, motion } from 'framer-motion';
import { cn } from '@/lib/utils';
const HomeChildren = () => {
  return (
    <div className="w-full h-full bg-zinc-900 p-6">
      <div className="mb-8">
        <div className="h-8 bg-zinc-700 rounded w-24 animate-pulse"></div>
      </div>
      <div className="space-y-3 mb-8">
        <div className="w-full bg-gray-600 px-4 py-3 rounded-lg flex items-center gap-3">
          <div className="h-4 bg-gray-500 rounded w-4 animate-pulse"></div>
          <div className="h-4 bg-gray-500 rounded w-36 animate-pulse"></div>
        </div>
      </div>
      <div className="mb-6">
        <div className="flex items-center justify-between mb-3">
          <div className="h-4 bg-zinc-700 rounded w-12 animate-pulse"></div>
          <div className="h-4 bg-gray-500 rounded w-4 animate-pulse"></div>
        </div>
        <div className="space-y-2">
          <div className="w-full bg-purple-800 px-4 py-3 rounded-lg flex items-center gap-3">
            <div className="h-4 bg-purple-600 rounded w-4 animate-pulse"></div>
            <div className="h-4 bg-purple-600 rounded w-20 animate-pulse"></div>
          </div>
        </div>
      </div>
      <div>
        <div className="flex items-center justify-between mb-3">
          <div className="h-4 bg-zinc-700 rounded w-16 animate-pulse"></div>
        </div>
        <div className="space-y-2">
          <div className="w-full hover:bg-zinc-800 py-3 rounded-lg flex items-center gap-3">
            <div className="h-4 bg-zinc-600 rounded w-4 animate-pulse"></div>
            <div className="h-4 bg-zinc-600 rounded w-40 animate-pulse"></div>
          </div>
        </div>
      </div>
    </div>
  );
};
const ProjectsChildren = () => {
  return (
    <div className="w-full h-full bg-zinc-800 p-6">
      <div className="mb-8">
        <div className="h-6 bg-blue-600 rounded w-32 animate-pulse mb-2"></div>
        <div className="h-4 bg-zinc-700 rounded w-48 animate-pulse"></div>
      </div>
      <div className="grid grid-cols-2 gap-4 mb-6">
        <div className="bg-zinc-900 rounded-lg p-4 border-zinc-700">
          <div className="h-4 bg-zinc-600 rounded w-20 animate-pulse mb-2"></div>
          <div className="h-3 bg-zinc-700 rounded w-16 animate-pulse"></div>
        </div>
        <div className="bg-zinc-900 rounded-lg p-4 border-zinc-700">
          <div className="h-4 bg-zinc-600 rounded w-24 animate-pulse mb-2"></div>
          <div className="h-3 bg-zinc-700 rounded w-20 animate-pulse"></div>
        </div>
        <div className="bg-zinc-900 rounded-lg p-4 border-zinc-700">
          <div className="h-4 bg-zinc-600 rounded w-18 animate-pulse mb-2"></div>
          <div className="h-3 bg-zinc-700 rounded w-14 animate-pulse"></div>
        </div>
        <div className="bg-zinc-900 rounded-lg p-4 border-zinc-700">
          <div className="h-4 bg-zinc-600 rounded w-22 animate-pulse mb-2"></div>
          <div className="h-3 bg-zinc-700 rounded w-18 animate-pulse"></div>
        </div>
      </div>
      <div>
        <div className="h-4 bg-zinc-700 rounded w-24 animate-pulse mb-3"></div>
        <div className="space-y-2">
          <div className="flex items-center gap-3 p-2 hover:bg-zinc-800 rounded">
            <div className="h-3 bg-zinc-600 rounded-full w-3 animate-pulse"></div>
            <div className="h-3 bg-zinc-600 rounded w-32 animate-pulse"></div>
          </div>
          <div className="flex items-center gap-3 p-2 hover:bg-zinc-800 rounded">
            <div className="h-3 bg-zinc-600 rounded-full w-3 animate-pulse"></div>
            <div className="h-3 bg-zinc-600 rounded w-28 animate-pulse"></div>
          </div>
          <div className="flex items-center gap-3 p-2 hover:bg-zinc-800 rounded">
            <div className="h-3 bg-zinc-600 rounded-full w-3 animate-pulse"></div>
            <div className="h-3 bg-zinc-600 rounded w-36 animate-pulse"></div>
          </div>
        </div>
      </div>
    </div>
  );
};
const TemplatesChildren = () => {
  return (
    <div className="w-full h-full bg-zinc-900 p-6">
      <div className="mb-8">
        <div className="h-6 bg-green-600 rounded w-28 animate-pulse mb-2"></div>
        <div className="h-4 bg-zinc-700 rounded w-40 animate-pulse"></div>
      </div>
      <div className="space-y-4 mb-6">
        <div className="flex items-center gap-3 p-3 bg-zinc-800 rounded-lg">
          <div className="h-4 bg-zinc-600 rounded-full w-4 animate-pulse"></div>
          <div className="h-4 bg-zinc-600 rounded w-24 animate-pulse"></div>
        </div>
        <div className="flex items-center gap-3 p-3 bg-zinc-800 rounded-lg">
          <div className="h-4 bg-zinc-600 rounded-full w-4 animate-pulse"></div>
          <div className="h-4 bg-zinc-600 rounded w-20 animate-pulse"></div>
        </div>
      </div>
      <div>
        <div className="h-4 bg-zinc-700 rounded w-32 animate-pulse mb-3"></div>
        <div className="space-y-2">
          <div className="h-16 bg-gradient-to-r from-pink-500/20 to-purple-500/20 rounded-lg animate-pulse"></div>
          <div className="h-16 bg-gradient-to-r from-blue-500/20 to-cyan-500/20 rounded-lg animate-pulse"></div>
          <div className="h-16 bg-gradient-to-r from-green-500/20 to-emerald-500/20 rounded-lg animate-pulse"></div>
        </div>
      </div>
    </div>
  );
};
const AIChildren = () => {
  return (
    <div className="w-full h-full bg-zinc-800 p-6">
      <div className="mb-8">
        <div className="h-6 bg-purple-600 rounded w-20 animate-pulse mb-2"></div>
        <div className="h-4 bg-zinc-700 rounded w-36 animate-pulse"></div>
      </div>
      <div className="grid grid-cols-2 gap-3 mb-6">
        <div className="bg-gradient-to-br from-purple-600/20 to-pink-600/20 rounded-lg p-4">
          <div className="h-5 bg-purple-500/50 rounded w-5 animate-pulse mb-2"></div>
          <div className="h-3 bg-purple-500/50 rounded w-16 animate-pulse"></div>
        </div>
        <div className="bg-gradient-to-br from-blue-600/20 to-cyan-600/20 rounded-lg p-4">
          <div className="h-5 bg-blue-500/50 rounded w-5 animate-pulse mb-2"></div>
          <div className="h-3 bg-blue-500/50 rounded w-20 animate-pulse"></div>
        </div>
        <div className="bg-gradient-to-br from-green-600/20 to-emerald-600/20 rounded-lg p-4 ">
          <div className="h-5 bg-green-500/50 rounded w-5 animate-pulse mb-2"></div>
          <div className="h-3 bg-green-500/50 rounded w-18 animate-pulse"></div>
        </div>
        <div className="bg-gradient-to-br from-orange-600/20 to-red-600/20 rounded-lg p-4">
          <div className="h-5 bg-orange-500/50 rounded w-5 animate-pulse mb-2"></div>
          <div className="h-3 bg-orange-500/50 rounded w-22 animate-pulse"></div>
        </div>
      </div>
      <div>
        <div className="h-4 bg-zinc-700 rounded w-28 animate-pulse mb-3"></div>
        <div className="space-y-2">
          <div className="flex items-center gap-3 p-2 bg-zinc-900 rounded">
            <div className="h-3 bg-zinc-600 rounded w-40 animate-pulse"></div>
          </div>
          <div className="flex items-center gap-3 p-2 bg-zinc-900 rounded">
            <div className="h-3 bg-zinc-600 rounded w-36 animate-pulse"></div>
          </div>
        </div>
      </div>
    </div>
  );
};
const CloudChildren = () => {
  return (
    <div className="w-full h-full bg-zinc-900 p-6">
      <div className="mb-8">
        <div className="h-6 bg-cyan-600 rounded w-24 animate-pulse mb-2"></div>
        <div className="h-4 bg-zinc-700 rounded w-32 animate-pulse"></div>
      </div>
      <div className="bg-zinc-800 rounded-lg p-4 mb-6">
        <div className="flex items-center justify-between mb-3">
          <div className="h-4 bg-zinc-600 rounded w-20 animate-pulse"></div>
          <div className="h-4 bg-zinc-600 rounded w-16 animate-pulse"></div>
        </div>
        <div className="w-full bg-zinc-700 rounded-full h-2 mb-2">
          <div className="bg-cyan-500 h-2 rounded-full w-3/4 animate-pulse"></div>
        </div>
        <div className="h-3 bg-zinc-600 rounded w-24 animate-pulse"></div>
      </div>
      <div className="space-y-3 mb-6">
        <div className="flex items-center gap-3 p-3 bg-zinc-800 rounded-lg hover:bg-zinc-700 transition-colors">
          <div className="h-4 bg-green-500/50 rounded w-4 animate-pulse"></div>
          <div className="h-4 bg-zinc-600 rounded w-20 animate-pulse"></div>
        </div>
        <div className="flex items-center gap-3 p-3 bg-zinc-800 rounded-lg hover:bg-zinc-700 transition-colors">
          <div className="h-4 bg-blue-500/50 rounded w-4 animate-pulse"></div>
          <div className="h-4 bg-zinc-600 rounded w-24 animate-pulse"></div>
        </div>
        <div className="flex items-center gap-3 p-3 bg-zinc-800 rounded-lg hover:bg-zinc-700 transition-colors">
          <div className="h-4 bg-purple-500/50 rounded w-4 animate-pulse"></div>
          <div className="h-4 bg-zinc-600 rounded w-28 animate-pulse"></div>
        </div>
      </div>
      <div>
        <div className="h-4 bg-zinc-700 rounded w-24 animate-pulse mb-3"></div>
        <div className="space-y-2">
          <div className="flex items-center gap-3 p-2 hover:bg-zinc-800 rounded">
            <div className="h-4 bg-cyan-500/50 rounded w-4 animate-pulse"></div>
            <div className="h-3 bg-zinc-600 rounded w-32 animate-pulse"></div>
          </div>
          <div className="flex items-center gap-3 p-2 hover:bg-zinc-800 rounded">
            <div className="h-4 bg-gray-500/50 rounded w-4 animate-pulse"></div>
            <div className="h-3 bg-zinc-600 rounded w-28 animate-pulse"></div>
          </div>
        </div>
      </div>
    </div>
  );
};
const SidebarToggle = ({
  isOpen,
  setIsOpen
}: {
  isOpen: string | false;
  setIsOpen: (isOpen: string | false) => void;
}) => {
  const renderIcon = () => {
    switch (isOpen !== false) {
      case true:
        return <PanelLeftClose size={24} />;
      case false:
        return <Menu size={24} />;
    }
  };
  return (
    <li
      onClick={() => {
        if (isOpen) {
          setIsOpen(false);
        } else {
          setIsOpen('Home');
        }
      }}
      className="flex flex-col items-center justify-center gap-1 mb-2 cursor-pointer hover:bg-zinc-800 my-3 py-2.5 mx-4 rounded-md m-1.5"
    >
      <AnimatePresence mode="popLayout" initial={false}>
        <motion.span
          initial={{ opacity: 0.3, scale: 0.5, filter: 'blur(4px)' }}
          animate={{ opacity: 1, scale: 1, filter: 'blur(0px)' }}
          exit={{ opacity: 0.3, scale: 0.5, filter: 'blur(4px)' }}
          key={`sidebar-toggle-${isOpen ? true : false}`}
        >
          {renderIcon()}
        </motion.span>
      </AnimatePresence>
    </li>
  );
};
const Sidebar = () => {
  const [isOpen, setIsOpen] = useState<string | false>(false);
  const [hovering, setHovering] = useState<string | null>(null);
  const options = [
    {
      name: 'Home',
      icon: <Home size={24} />,
      children: <HomeChildren />
    },
    {
      name: 'Projects',
      icon: <Folder size={24} />,
      children: <ProjectsChildren />
    },
    {
      name: 'Templates',
      icon: <PanelsTopLeft size={24} />,
      children: <TemplatesChildren />
    },
    {
      name: 'AI',
      icon: <Star size={24} />,
      children: <AIChildren />
    },
    {
      name: 'Cloud',
      icon: <Cloud size={24} />,
      children: <CloudChildren />
    }
  ];
  return (
    <div className="h-full flex items-start">
      <ul className="h-full w-20 bg-zinc-900 flex flex-col gap-1 border-r border-zinc-800">
        <SidebarToggle isOpen={isOpen} setIsOpen={setIsOpen} />
        {options.map((option) => {
          const isActive = isOpen === option.name;
          return (
            <li
              onMouseEnter={() => {
                if (!isOpen) setHovering(option.name);
              }}
              onMouseLeave={(e) => {
                if (!isOpen) {
                  setHovering(null);
                }
              }}
              onClick={() => {
                setIsOpen(option.name);
              }}
              className="group px-1.5 gap-1 py-1 flex flex-col items-center justify-center cursor-pointer select-none"
            >
              <div
                className={cn(
                  'flex flex-col items-center justify-center gap-1 group-hover:bg-zinc-800 p-2.5 rounded-md text-white/90',
                  isActive && 'bg-zinc-800 text-blue-400'
                )}
              >
                {option.icon}
              </div>
              <p className="text-xs">{option.name}</p>
            </li>
          );
        })}
      </ul>
      <AnimatePresence mode="popLayout" initial={false}>
        {(hovering || isOpen) && (
          <motion.section
            id="sidebar-children"
            initial={{ clipPath: 'inset(100% 0 0 0)' }}
            animate={{ clipPath: 'inset(0 0 0 0)' }}
            exit={{ clipPath: 'inset(0 0 100% 0)', transition: { delay: 0.06 } }}
            transition={{
              duration: 0.2,
              type: 'spring',
              bounce: 0
            }}
            onMouseEnter={() => {
              if (!isOpen) setHovering(isOpen || hovering);
            }}
            onMouseLeave={() => {
              if (!isOpen) setHovering(null);
            }}
            key={isOpen ? isOpen : hovering}
            className="h-full bg-zinc-900"
          >
            <div className="w-[300px] h-full">
              {(isOpen || hovering) &&
                options.find((opt) => opt.name === (isOpen || hovering))?.children}
            </div>
          </motion.section>
        )}
      </AnimatePresence>
    </div>
  );
};
export default Sidebar;Usage
<Sidebar />