Sidebar
- Source
- Aceternity UI ↗
- Author
- Aceternity UI
- Licence
- Aceternity UI licence (free component)
Loading…
A collapsed icon sidebar expands to show labels on hover.
Code
"use client";
import React, { useState } from "react";
import { Sidebar, SidebarBody, SidebarLink } from "@/lab/aceternity/ui/sidebar";
import { IconArrowLeft, IconBrandTabler, IconSettings, IconUserBolt } from "@tabler/icons-react";
import { motion } from "motion/react";
const links = [
{
label: "Dashboard",
href: "#",
icon: <IconBrandTabler className="h-5 w-5 shrink-0 text-neutral-700 dark:text-neutral-200" />,
},
{
label: "Profile",
href: "#",
icon: <IconUserBolt className="h-5 w-5 shrink-0 text-neutral-700 dark:text-neutral-200" />,
},
{
label: "Settings",
href: "#",
icon: <IconSettings className="h-5 w-5 shrink-0 text-neutral-700 dark:text-neutral-200" />,
},
{
label: "Logout",
href: "#",
icon: <IconArrowLeft className="h-5 w-5 shrink-0 text-neutral-700 dark:text-neutral-200" />,
},
];
export default function SidebarDemo() {
const [open, setOpen] = useState(false);
return (
<div className="@container relative h-full w-full p-[3%]">
<div className="relative flex h-full w-full flex-col overflow-hidden rounded-md border border-neutral-200 bg-gray-100 @2xs:flex-row dark:border-neutral-700 dark:bg-neutral-800">
<Sidebar open={open} setOpen={setOpen}>
<SidebarBody className="justify-between gap-10">
<div className="flex flex-1 flex-col overflow-x-hidden overflow-y-auto">
{open ? <Logo /> : <LogoIcon />}
<div className="mt-8 flex flex-col gap-2">
{links.map((link, idx) => (
<SidebarLink key={idx} link={link} />
))}
</div>
</div>
<div>
<SidebarLink
link={{
label: "Manu Arora",
href: "#",
icon: (
// eslint-disable-next-line @next/next/no-img-element
<img
src="https://assets.aceternity.com/manu.png"
className="h-7 w-7 shrink-0 rounded-full"
width={50}
height={50}
alt="Avatar"
/>
),
}}
/>
</div>
</SidebarBody>
</Sidebar>
<Dashboard />
</div>
</div>
);
}
const Logo = () => {
return (
<a
href="#"
onClick={(e) => e.preventDefault()}
className="relative z-20 flex items-center space-x-2 py-1 text-sm font-normal text-black"
>
<div className="h-5 w-6 shrink-0 rounded-tl-lg rounded-tr-sm rounded-br-lg rounded-bl-sm bg-black dark:bg-white" />
<motion.span
initial={{ opacity: 0 }}
animate={{ opacity: 1 }}
className="font-medium whitespace-pre text-black dark:text-white"
>
Acet Labs
</motion.span>
</a>
);
};
const LogoIcon = () => {
return (
<a
href="#"
onClick={(e) => e.preventDefault()}
className="relative z-20 flex items-center space-x-2 py-1 text-sm font-normal text-black"
>
<div className="h-5 w-6 shrink-0 rounded-tl-lg rounded-tr-sm rounded-br-lg rounded-bl-sm bg-black dark:bg-white" />
</a>
);
};
// Dummy dashboard component with content
const Dashboard = () => {
return (
<div className="flex min-h-0 flex-1">
<div className="flex h-full w-full flex-1 flex-col gap-2 rounded-tl-2xl border border-neutral-200 bg-white p-2 @md:p-6 dark:border-neutral-700 dark:bg-neutral-900">
<div className="flex gap-2">
{[0, 1, 2, 3].map((idx) => (
<div
key={"first-array-demo-1" + idx}
className="h-[clamp(2.5rem,10cqw,5rem)] w-full animate-pulse rounded-lg bg-gray-100 dark:bg-neutral-800"
></div>
))}
</div>
<div className="flex flex-1 gap-2">
{[0, 1].map((idx) => (
<div
key={"second-array-demo-1" + idx}
className="h-full w-full animate-pulse rounded-lg bg-gray-100 dark:bg-neutral-800"
></div>
))}
</div>
</div>
</div>
);
}
Prompt
Build "Sidebar", a navigation animation. What it does: A collapsed icon sidebar expands to show labels on hover. Write it as a single self-contained React component in TypeScript that fills its parent (w-full h-full), styled with Tailwind CSS, using @tabler/icons-react, motion. Technique: the Motion library. It sits on a light background, in a 16:10 frame. Respect prefers-reduced-motion with a still state, pause work when the element is off screen, and keep it accessible. Original: https://ui.aceternity.com/components/sidebar (Aceternity UI, Aceternity UI licence (free component)).