Build websites 10x faster with HextaUI Blocks — Learn more
UI/UI

Sidebar

A flexible and responsive sidebar component with animations, collapsible behavior, and comprehensive customization options.

Advanced Dashboard

A comprehensive workspace with team management and analytics.

Projects

12

+2 this week

Tasks

48

12 pending

Team

8

members

import {
  Sidebar,
  SidebarBody,
  SidebarItem,
  SidebarContent,
  SidebarHeader,
  SidebarText,
} from "@/components/ui/Sidebar";
import { Home, Search, FileText, Settings } from "lucide-react";

function SidebarExample() {
  const [collapsed, setCollapsed] = useState(false);

  return (
    <div className="relative h-96 w-full overflow-hidden rounded-[var(--radius)] border">
      <Sidebar
        position="relative"
        collapsed={collapsed}
        onCollapsedChange={setCollapsed}
      >
        <SidebarHeader>
          <div className="h-8 w-8 rounded bg-primary">A</div>
          <SidebarText>App Name</SidebarText>
        </SidebarHeader>

        <SidebarBody>
          <SidebarItem id="home" label="Home" icon={Home} />
          <SidebarItem id="search" label="Search" icon={Search} />
          <SidebarItem id="documents" label="Documents" icon={FileText} />
          <SidebarItem id="settings" label="Settings" icon={Settings} />
        </SidebarBody>
      </Sidebar>

      <SidebarContent sidebarCollapsed={collapsed} position="relative" className="p-6">
        {/* Your main content here */}
      </SidebarContent>
    </div>
  );
}

Installation

Install following dependencies:

npm install motion class-variance-authority lucide-react
pnpm add motion class-variance-authority lucide-react
yarn add motion class-variance-authority lucide-react
bun add motion class-variance-authority lucide-react

Copy and paste the following code into your project.

components/ui/sidebar.tsx
"use client";

import * as React from "react";
import { motion, AnimatePresence } from "motion/react";
import { cva, type VariantProps } from "class-variance-authority";
import { cn } from "@/lib/utils";
import { ChevronLeft, ChevronRight, type LucideIcon } from "lucide-react";
import { Button } from "../button";
import { ScrollArea } from "../ScrollArea";
import { Separator } from "../separator";

const sidebarVariants = cva(
  "z-40 bg-[hsl(var(--hu-background))] border-r border-[hsl(var(--hu-border))] flex flex-col",
  {
    variants: {
      variant: {
        default: "bg-[hsl(var(--hu-background))]",
        elevated: "bg-[hsl(var(--hu-card))] shadow-lg",
        ghost: "bg-[hsl(var(--hu-background))]/95 backdrop-blur-sm",
      },
      size: {
        sm: "w-12",
        default: "w-64",
        lg: "w-72",
        xl: "w-80",
      },
      position: {
        fixed: "fixed top-0 left-0 h-screen",
        relative: "relative h-full",
      },
    },
    defaultVariants: {
      variant: "default",
      size: "default",
      position: "fixed",
    },
  },
);

const sidebarHeaderVariants = cva(
  "flex items-center border-b border-[hsl(var(--hu-border))] min-h-[3.5rem]",
  {
    variants: {
      collapsed: {
        true: "justify-center px-2",
        false: "justify-between px-4",
      },
    },
    defaultVariants: {
      collapsed: false,
    },
  },
);

const sidebarItemVariants = cva(
  "relative flex items-center rounded-[var(--radius)] text-sm font-medium cursor-pointer group",
  {
    variants: {
      variant: {
        default:
          "text-[hsl(var(--hu-muted-foreground))] hover:text-[hsl(var(--hu-foreground))] hover:bg-[hsl(var(--hu-accent))]",
        active:
          "text-[hsl(var(--hu-primary-foreground))] bg-[hsl(var(--hu-primary))] hover:bg-[hsl(var(--hu-primary))]/90",
        ghost:
          "text-[hsl(var(--hu-muted-foreground))] hover:text-[hsl(var(--hu-foreground))] hover:bg-[hsl(var(--hu-accent))]/50",
      },
      collapsed: {
        true: "w-10 h-10 justify-center px-0 py-0",
        false: "px-3 py-2.5",
      },
    },
    defaultVariants: {
      variant: "default",
      collapsed: false,
    },
  },
);

export interface SidebarProps
  extends React.HTMLAttributes<HTMLDivElement>,
    VariantProps<typeof sidebarVariants> {
  collapsed?: boolean;
  onCollapsedChange?: (collapsed: boolean) => void;
  collapsible?: boolean;
  overlay?: boolean;
  onOverlayClick?: () => void;
  position?: "fixed" | "relative";
  children: React.ReactNode;
}

const SidebarContext = React.createContext<{
  collapsed: boolean;
  activeItem?: string;
  onItemClick?: (item: { id: string; label: string; href?: string }) => void;
  sidebarId: string;
}>({
  collapsed: false,
  sidebarId: "",
});

const useSidebar = () => {
  const context = React.useContext(SidebarContext);
  if (!context) {
    throw new Error("useSidebar must be used within a Sidebar");
  }
  return context;
};

const Sidebar = React.forwardRef<HTMLDivElement, SidebarProps>(
  (
    {
      className,
      variant = "default",
      size = "default",
      position = "fixed",
      collapsed: controlledCollapsed,
      onCollapsedChange,
      collapsible = true,
      overlay = false,
      onOverlayClick,
      children,
      ...props
    },
    ref,
  ) => {
    const [internalCollapsed, setInternalCollapsed] = React.useState(false);
    const [activeItem, setActiveItem] = React.useState<string>();
    const sidebarRef = React.useRef<HTMLDivElement>(null);
    const sidebarId = React.useId();

    const collapsed = controlledCollapsed ?? internalCollapsed;

    React.useImperativeHandle(ref, () => sidebarRef.current!);

    const handleToggleCollapse = () => {
      const newCollapsed = !collapsed;
      if (onCollapsedChange) {
        onCollapsedChange(newCollapsed);
      } else {
        setInternalCollapsed(newCollapsed);
      }
    };

    const handleItemClick = (item: {
      id: string;
      label: string;
      href?: string;
    }) => {
      setActiveItem(item.id);
    };

    // Auto-collapse on mobile
    React.useEffect(() => {
      const handleResize = () => {
        if (window.innerWidth < 768 && !collapsed) {
          handleToggleCollapse();
        }
      };

      window.addEventListener("resize", handleResize);
      handleResize();

      return () => window.removeEventListener("resize", handleResize);
    }, [collapsed]);

    // Keyboard navigation support
    React.useEffect(() => {
      const handleKeyDown = (event: KeyboardEvent) => {
        if (event.key === "Escape" && overlay && !collapsed) {
          onOverlayClick?.();
        }
      };

      if (overlay) {
        document.addEventListener("keydown", handleKeyDown);
        return () => document.removeEventListener("keydown", handleKeyDown);
      }
    }, [overlay, collapsed, onOverlayClick]);

    // Focus management for better keyboard navigation accessibility
    const focusableElementsRef = React.useRef<HTMLElement[]>([]);

    React.useEffect(() => {
      // Update focusable elements when sidebar state changes
      const updateFocusableElements = () => {
        if (sidebarRef.current) {
          const elements = sidebarRef.current.querySelectorAll(
            'button, a, [tabindex]:not([tabindex="-1"])',
          ) as NodeListOf<HTMLElement>;
          focusableElementsRef.current = Array.from(elements);
        }
      };

      updateFocusableElements();

      // Re-scan when collapsed state changes
      const timeoutId = setTimeout(updateFocusableElements, 300);
      return () => clearTimeout(timeoutId);
    }, [collapsed]);

    // Extract header, body and footer from children
    const headerChild = React.Children.toArray(children).find(
      (child) => React.isValidElement(child) && child.type === SidebarHeader,
    );
    const bodyChild = React.Children.toArray(children).find(
      (child) => React.isValidElement(child) && child.type === SidebarBody,
    );
    const footerChild = React.Children.toArray(children).find(
      (child) => React.isValidElement(child) && child.type === SidebarFooter,
    );

    const sidebarContent = (
      <SidebarContext.Provider
        value={{
          collapsed,
          activeItem,
          onItemClick: handleItemClick,
          sidebarId,
        }}
      >
        {" "}
        <motion.aside
          ref={(node) => {
            const divNode = node as HTMLDivElement | null;
            if (typeof ref === "function") {
              ref(divNode);
            } else if (ref) {
              ref.current = divNode;
            }
            sidebarRef.current = divNode;
          }}
          className={cn(
            sidebarVariants({
              variant,
              size: collapsed ? "sm" : size,
              position,
            }),
            className,
          )}
          initial={false}
          animate={{
            width: collapsed
              ? 57
              : size === "lg"
                ? 288
                : size === "xl"
                  ? 320
                  : 256,
          }}
          transition={{
            duration: 0.25,
            ease: [0.4, 0, 0.2, 1],
          }}
          style={props.style}
          id={props.id || sidebarId}
          role="complementary"
          aria-label={
            collapsed ? "Collapsed navigation sidebar" : "Navigation sidebar"
          }
          aria-expanded={!collapsed}
          aria-hidden={overlay && collapsed}
        >
          {/* Header */}
          {(headerChild || collapsible) && (
            <div className={cn(sidebarHeaderVariants({ collapsed }))}>
              {collapsed ? (
                // Show only toggle button when collapsed
                collapsible && (
                  <Button
                    variant="ghost"
                    size="icon"
                    onClick={handleToggleCollapse}
                    className="h-8 w-8 shrink-0"
                    aria-label="Expand sidebar"
                    aria-controls={sidebarId}
                    aria-expanded={false}
                  >
                    <ChevronRight size={16} />
                  </Button>
                )
              ) : (
                // Show header content and toggle button when expanded
                <>
                  <AnimatePresence mode="wait">
                    {headerChild && (
                      <motion.div
                        initial={{ opacity: 0 }}
                        animate={{ opacity: 1 }}
                        exit={{ opacity: 0 }}
                        transition={{ duration: 0.15 }}
                        className="flex-1"
                      >
                        {headerChild}
                      </motion.div>
                    )}
                  </AnimatePresence>

                  {collapsible && (
                    <Button
                      variant="ghost"
                      size="icon"
                      onClick={handleToggleCollapse}
                      className="h-8 w-8 shrink-0"
                      aria-label="Collapse sidebar"
                      aria-controls={sidebarId}
                      aria-expanded={true}
                    >
                      <ChevronLeft size={16} />
                    </Button>
                  )}
                </>
              )}
            </div>
          )}

          {/* Body */}
          {bodyChild}

          {/* Footer */}
          {footerChild && (
            <div
              className={cn(
                "border-t border-[hsl(var(--hu-border))]",
                collapsed ? "p-2" : "p-3",
              )}
            >
              {footerChild}
            </div>
          )}
        </motion.aside>
      </SidebarContext.Provider>
    );
    if (overlay) {
      return (
        <>
          {/* Overlay */}
          <AnimatePresence>
            {!collapsed && (
              <motion.div
                initial={{ opacity: 0 }}
                animate={{ opacity: 1 }}
                exit={{ opacity: 0 }}
                transition={{ duration: 0.2 }}
                className="fixed inset-0 z-30 bg-black/50 md:hidden"
                onClick={onOverlayClick}
                role="presentation"
                aria-hidden="true"
              />
            )}
          </AnimatePresence>
          {sidebarContent}
        </>
      );
    }

    return sidebarContent;
  },
);

Sidebar.displayName = "Sidebar";

// SidebarBody component
interface SidebarBodyProps {
  children: React.ReactNode;
  className?: string;
}

const SidebarBody: React.FC<SidebarBodyProps> = ({ children, className }) => {
  const { collapsed } = useSidebar();

  return (
    <ScrollArea
      className={cn("flex-1 py-2", collapsed ? "px-2" : "px-2", className)}
    >
      <nav role="navigation" aria-label="Main navigation">
        <ul className="space-y-1 list-none" role="list">
          {children}
        </ul>
      </nav>
    </ScrollArea>
  );
};

// SidebarItem component
interface SidebarItemProps {
  id: string;
  label: string;
  icon?: LucideIcon;
  href?: string;
  badge?: React.ReactNode;
  children?: React.ReactNode;
  level?: number;
  onClick?: () => void;
  className?: string;
}

const SidebarItem: React.FC<SidebarItemProps> = ({
  id,
  label,
  icon: Icon,
  href,
  badge,
  children,
  level = 0,
  onClick,
  className,
}) => {
  const { collapsed, activeItem, onItemClick } = useSidebar();
  const [expanded, setExpanded] = React.useState(false);
  const isActive = activeItem === id;
  const hasChildren = React.Children.count(children) > 0;
  const itemId = React.useId();

  const handleClick = () => {
    if (hasChildren && !collapsed) {
      setExpanded(!expanded);
    }
    onItemClick?.({ id, label, href });
    onClick?.();
  };

  const handleKeyDown = (e: React.KeyboardEvent) => {
    if (e.key === "Enter" || e.key === " ") {
      e.preventDefault();
      handleClick();
    } else if (
      e.key === "ArrowRight" &&
      hasChildren &&
      !expanded &&
      !collapsed
    ) {
      e.preventDefault();
      setExpanded(true);
    } else if (e.key === "ArrowLeft" && hasChildren && expanded && !collapsed) {
      e.preventDefault();
      setExpanded(false);
    }
  };

  const ItemContent = (
    <>
      {/* Static icon positioned always in the center-left area */}
      <div
        className={cn(
          "flex items-center justify-center shrink-0",
          collapsed ? "w-10 h-10" : "w-4 h-4 ml-0",
        )}
        aria-hidden="true"
      >
        {Icon && <Icon size={16} />}
      </div>

      {/* Text - simple conditional rendering, no animation */}
      {!collapsed && <span className="ml-3 truncate flex-1">{label}</span>}

      {/* Badge and chevron */}
      {!collapsed && (badge || hasChildren) && (
        <div className="flex items-center gap-2 ml-2">
          {badge}
          {hasChildren && (
            <ChevronRight
              size={14}
              className={cn(
                "shrink-0 transition-transform duration-200",
                expanded && "rotate-90",
              )}
              aria-hidden="true"
            />
          )}
        </div>
      )}

      {/* Tooltip for collapsed state */}
      {collapsed && (
        <div
          className="absolute left-full ml-2 px-2 py-1 bg-[hsl(var(--hu-popover))] text-[hsl(var(--hu-popover-foreground))] text-xs rounded-md border border-[hsl(var(--hu-border))] opacity-0 invisible group-hover:opacity-100 group-hover:visible transition-all duration-200 whitespace-nowrap z-50"
          role="tooltip"
          id={`${itemId}-tooltip`}
        >
          {label}
        </div>
      )}
    </>
  );

  return (
    <li role="none">
      {href ? (
        <a
          href={href}
          className={cn(
            sidebarItemVariants({
              variant: isActive ? "active" : "default",
              collapsed,
            }),
            level > 0 &&
              !collapsed &&
              "ml-0 border-[hsl(var(--hu-border))] pl-3 relative before:absolute before:left-[-2px] before:top-1/2 before:w-3 before:h-[1px] before:bg-[hsl(var(--hu-border))] before:-translate-y-1/2",
            "group relative no-underline",
            className,
          )}
          onClick={onClick}
          role="menuitem"
          aria-current={isActive ? "page" : undefined}
          aria-describedby={collapsed ? `${itemId}-tooltip` : undefined}
        >
          {ItemContent}
        </a>
      ) : (
        <button
          type="button"
          className={cn(
            sidebarItemVariants({
              variant: isActive ? "active" : "default",
              collapsed,
            }),
            level > 0 &&
              !collapsed &&
              "ml-0 border-[hsl(var(--hu-border))] pl-3 relative before:absolute before:left-[-2px] before:top-1/2 before:w-3 before:h-[1px] before:bg-[hsl(var(--hu-border))] before:-translate-y-1/2",
            "group relative w-full text-left border-none",
            !isActive && "bg-transparent",
            className,
          )}
          onClick={handleClick}
          onKeyDown={handleKeyDown}
          role="menuitem"
          aria-expanded={hasChildren ? expanded : undefined}
          aria-haspopup={hasChildren ? "menu" : undefined}
          aria-current={isActive ? "page" : undefined}
          aria-describedby={collapsed ? `${itemId}-tooltip` : undefined}
        >
          {ItemContent}
        </button>
      )}

      {/* Children */}
      <AnimatePresence>
        {hasChildren && expanded && !collapsed && (
          <motion.div
            initial={{ height: 0, opacity: 0 }}
            animate={{ height: "auto", opacity: 1 }}
            exit={{ height: 0, opacity: 0 }}
            transition={{
              duration: 0.25,
              ease: [0.4, 0, 0.2, 1],
            }}
            className="overflow-hidden"
          >
            <ul
              className="space-y-1 py-1 ml-2 border-l border-[hsl(var(--hu-border))]/50 pl-2 list-none"
              role="menu"
              aria-label={`${label} submenu`}
            >
              {React.Children.map(children, (child) => {
                if (React.isValidElement(child) && child.type === SidebarItem) {
                  return React.cloneElement(
                    child as React.ReactElement<SidebarItemProps>,
                    {
                      level: level + 1,
                      ...(child.props as SidebarItemProps),
                    },
                  );
                }
                return child;
              })}
            </ul>
          </motion.div>
        )}
      </AnimatePresence>
    </li>
  );
};

// Sidebar content wrapper for responsive behavior
export interface SidebarContentProps {
  children: React.ReactNode;
  sidebarCollapsed?: boolean;
  className?: string;
  position?: "fixed" | "relative";
}

const SidebarContent: React.FC<SidebarContentProps> = ({
  children,
  sidebarCollapsed = false,
  className,
  position = "fixed",
}) => {
  if (position === "relative") {
    return (
      <main className={cn("flex-1", className)} role="main">
        {children}
      </main>
    );
  }
  return (
    <motion.main
      className={cn("flex-1", className)}
      initial={false}
      animate={{
        marginLeft: sidebarCollapsed ? 48 : 256,
      }}
      transition={{
        duration: 0.25,
        ease: [0.4, 0, 0.2, 1],
      }}
      role="main"
    >
      <div className="md:hidden">
        <motion.div
          animate={{
            marginLeft: 0,
          }}
        >
          {children}
        </motion.div>
      </div>
      <div className="hidden md:block">{children}</div>
    </motion.main>
  );
};

// Utility components
const SidebarHeader: React.FC<{
  children: React.ReactNode;
  className?: string;
}> = ({ children, className }) => {
  return (
    <div className={cn("flex items-center gap-2", className)}>{children}</div>
  );
};

const SidebarFooter: React.FC<{
  children: React.ReactNode;
  className?: string;
}> = ({ children, className }) => {
  return <div className={cn("space-y-1", className)}>{children}</div>;
};

const SidebarSeparator: React.FC<{
  className?: string;
  children?: React.ReactNode;
}> = ({ className, children }) => {
  const { collapsed } = useSidebar();

  if (collapsed && children) {
    // In collapsed mode, just show the separator without text
    return (
      <div className={cn("my-2", className)}>
        <Separator className="mx-2" />
      </div>
    );
  }

  return (
    <div className={cn("my-2", className)}>
      <Separator className="mx-2">{children}</Separator>
    </div>
  );
};

const SidebarText: React.FC<{
  children: React.ReactNode;
  className?: string;
  animation?: boolean;
}> = ({ children, className, animation = true }) => {
  const { collapsed } = useSidebar();

  if (!animation) {
    return !collapsed ? <span className={className}>{children}</span> : null;
  }

  return (
    <AnimatePresence mode="wait">
      {!collapsed && (
        <motion.span
          initial={{ opacity: 0, width: 0 }}
          animate={{ opacity: 1, width: "auto" }}
          exit={{ opacity: 0, width: 0 }}
          transition={{ duration: 0.15 }}
          className={cn("truncate", className)}
        >
          {children}
        </motion.span>
      )}
    </AnimatePresence>
  );
};

export {
  Sidebar,
  SidebarBody,
  SidebarItem,
  SidebarContent,
  SidebarHeader,
  SidebarFooter,
  SidebarSeparator,
  useSidebar,
  sidebarVariants,
  sidebarItemVariants,
  SidebarText,
};
npx hextaui@latest add sidebar
pnpm dlx hextaui@latest add sidebar
yarn dlx hextaui@latest add sidebar
bun x hextaui@latest add sidebar

Usage Guide

Basic Setup

The Sidebar component uses a compositional API that allows you to build flexible sidebar layouts:

import {
  Sidebar,
  SidebarBody,
  SidebarItem,
  SidebarContent,
  SidebarHeader,
  SidebarFooter,
} from "@/components/ui/Sidebar";

function Layout() {
  const [collapsed, setCollapsed] = useState(false);

  return (
    <div className="flex h-screen">
      <Sidebar collapsed={collapsed} onCollapsedChange={setCollapsed}>
        <SidebarHeader>
          <Logo />
          <SidebarText>My App</SidebarText>
        </SidebarHeader>

        <SidebarBody>
          <SidebarItem id="home" label="Home" icon={Home} />
          <SidebarItem id="settings" label="Settings" icon={Settings} />
        </SidebarBody>

        <SidebarFooter>
          <UserProfile />
        </SidebarFooter>
      </Sidebar>

      <SidebarContent sidebarCollapsed={collapsed}>
        <YourMainContent />
      </SidebarContent>
    </div>
  );
}

Advanced Features

Nested Navigation

<SidebarItem id="projects" label="Projects" icon={Folder}>
  <SidebarItem id="active" label="Active Projects" />
  <SidebarItem id="archived" label="Archived Projects" />
</SidebarItem>

With Badges and Actions

<SidebarItem
  id="notifications"
  label="Notifications"
  icon={Bell}
  badge={<Badge variant="destructive">3</Badge>}
  onClick={() => handleNotificationClick()}
/>

Mobile Responsive

<Sidebar
  overlay={true}
  onOverlayClick={() => setCollapsed(true)}
  collapsed={collapsed}
  onCollapsedChange={setCollapsed}
>
  {/* Sidebar content */}
</Sidebar>

Text Hiding Behavior

The sidebar automatically hides text content when collapsed. Use the SidebarText component for text that should animate in and out:

// Text that animates with smooth transitions
<SidebarText className="font-medium">
  Dashboard
</SidebarText>

// Text that appears/disappears instantly
<SidebarText animation={false}>
  <ChevronDown size={14} />
</SidebarText>

Examples

Basic Sidebar

Welcome to HextaUI

This is the main content area. The sidebar will affect the width of this content.

Card 1

Some content here

Card 2

Some content here

"use client";

import * as React from "react";
import {
Sidebar,
SidebarBody,
SidebarItem,
SidebarContent,
SidebarHeader,
SidebarText,
} from "./sidebar";
import { cn } from "@/lib/utils";
import { Home, Search, Settings, FileText } from "lucide-react";

export function SidebarBasic() {
const [collapsed, setCollapsed] = React.useState(false);

return (

<div className="relative h-screen w-full flex overflow-hidden rounded-[var(--radius)] border border-[hsl(var(--hu-border))]">
<Sidebar
    position="relative"
    collapsed={collapsed}
    onCollapsedChange={setCollapsed}
  >
<SidebarHeader>
<img
        className="rounded-[var(--radius)] bg-[hsl(var(--hu-background))] border border-[hsl(var(--hu-border))] shrink-0"
        src="https://api.dicebear.com/9.x/micah/svg?seed=Sara"
        width={35}
        height={35}
      />
<SidebarText className="font-semibold text-lg">HextaUI</SidebarText>
</SidebarHeader>

    <SidebarBody>
      <SidebarItem id="home" label="Home" icon={Home} />
      <SidebarItem id="search" label="Search" icon={Search} />
      <SidebarItem id="documents" label="Documents" icon={FileText} />
      <SidebarItem id="settings" label="Settings" icon={Settings} />
    </SidebarBody>
  </Sidebar>

  <SidebarContent
    sidebarCollapsed={collapsed}
    position="relative"
    className="p-6"
  >
    <div className="space-y-4">
      <h1 className="text-2xl font-bold">Welcome to HextaUI</h1>
      <p className="text-[hsl(var(--hu-muted-foreground))]">
        This is the main content area. The sidebar will affect the width of this content.
      </p>
    </div>
  </SidebarContent>
</div>

);
}

With Profile Dropdown

Dashboard

Welcome back! Here's your dashboard overview.

Projects

12

Tasks

24

"use client";

import * as React from "react";
import {
Sidebar,
SidebarBody,
SidebarItem,
SidebarContent,
SidebarHeader,
SidebarFooter,
SidebarText,
} from "./sidebar";
import { Badge } from "../badge";
import { Button } from "../button";
import { Avatar, AvatarImage, AvatarFallback } from "../avatar";
import { cn } from "@/lib/utils";
import {
Home,
BarChart3,
Calendar,
Mail,
Folder,
ChevronDown,
LogOut,
User,
Settings,
Bell,
} from "lucide-react";

export function SidebarWithProfile() {
const [collapsed, setCollapsed] = React.useState(false);

return (
<div className="relative h-screen w-full flex overflow-hidden rounded-[var(--radius)] border border-[hsl(var(--hu-border))]">
<Sidebar
      position="relative"
      collapsed={collapsed}
      onCollapsedChange={setCollapsed}
    >
<SidebarHeader>
<img
          className="rounded-[var(--radius)] bg-[hsl(var(--hu-background))] border border-[hsl(var(--hu-border))] shrink-0"
          src="https://api.dicebear.com/9.x/micah/svg?seed=Sara"
          width={35}
          height={35}
        />
<SidebarText className="font-semibold text-lg">HextaUI</SidebarText>
</SidebarHeader>

      <SidebarBody>
        <SidebarItem id="dashboard" label="Dashboard" icon={Home} />
        <SidebarItem
          id="projects"
          label="Projects"
          icon={Folder}
          badge={
            <Badge variant="secondary" size="sm">
              12
            </Badge>
          }
        />
        <SidebarItem id="analytics" label="Analytics" icon={BarChart3} />
        <SidebarItem id="calendar" label="Calendar" icon={Calendar} />
        <SidebarItem
          id="mail"
          label="Mail"
          icon={Mail}
          badge={
            <Badge variant="destructive" size="sm">
              3
            </Badge>
          }
        />
      </SidebarBody>

      <SidebarFooter>
        {/* Profile dropdown implementation */}
      </SidebarFooter>
    </Sidebar>
  </div>

);
}

With Team Selector

HextaUI Overview

Manage your team projects and settings.

"use client";

import * as React from "react";
import {
Sidebar,
SidebarBody,
SidebarItem,
SidebarContent,
SidebarHeader,
SidebarText,
} from "./sidebar";
import { Button } from "../button";
import { cn } from "@/lib/utils";
import {
Home,
Folder,
Users,
BarChart3,
CheckCircle,
Archive,
FileText,
ChevronDown,
} from "lucide-react";

export function SidebarWithTeamSelector() {
const [collapsed, setCollapsed] = React.useState(false);
const [selectedTeam, setSelectedTeam] = React.useState("HextaUI");

const teams = [
{ id: "Personal", name: "Personal", role: "Owner" },
{ id: "HextaStudio", name: "HextaStudio", role: "Member" },
{ id: "HextaUI", name: "HextaUI", role: "Admin" },
];

return (

<div className="relative h-screen w-full flex overflow-hidden rounded-[var(--radius)] border border-[hsl(var(--hu-border))]">
  <Sidebar
    position="relative"
    collapsed={collapsed}
    onCollapsedChange={setCollapsed}
  >
    <SidebarHeader>
      {/* Team selector dropdown */}
    </SidebarHeader>

    <SidebarBody>
      <SidebarItem id="overview" label="Overview" icon={Home} />
      <SidebarItem id="projects" label="Projects" icon={Folder}>
        <SidebarItem id="active-projects" label="Active" icon={CheckCircle} />
        <SidebarItem id="archived-projects" label="Archived" icon={Archive} />
        <SidebarItem id="draft-projects" label="Drafts" icon={FileText} />
      </SidebarItem>
      <SidebarItem id="team" label="Team" icon={Users} />
      <SidebarItem id="analytics" label="Analytics" icon={BarChart3} />
    </SidebarBody>
  </Sidebar>

</div>
);
}

Advanced Sidebar

Advanced Dashboard

A comprehensive workspace with team management and analytics.

Projects

12

+2 this week

Tasks

48

12 pending

Team

8

members

"use client";

import * as React from "react";
import {
Sidebar,
SidebarBody,
SidebarItem,
SidebarContent,
SidebarHeader,
SidebarFooter,
SidebarSeparator,
SidebarText,
} from "./sidebar";
import { Badge } from "../badge";
import { Button } from "../button";
import { Avatar, AvatarImage, AvatarFallback } from "../avatar";
import { cn } from "@/lib/utils";
import {
Home,
Briefcase,
Folder,
CheckCircle,
FileText,
BarChart3,
Users,
Shield,
Settings,
HelpCircle,
ChevronDown,
User,
Bell,
Moon,
LogOut,
} from "lucide-react";

export function SidebarAdvanced() {
const [collapsed, setCollapsed] = React.useState(false);

const adminItems = [
{ id: "admin", label: "Admin", icon: Shield },
{ id: "settings", label: "Settings", icon: Settings },
{ id: "help", label: "Help & Support", icon: HelpCircle },
];

return (

<div className="relative h-screen w-full flex overflow-hidden rounded-[var(--radius)] border border-[hsl(var(--hu-border))]">
  <Sidebar
    position="relative"
    collapsed={collapsed}
    onCollapsedChange={setCollapsed}
  >
    <SidebarHeader>
      <img
        className="rounded-[var(--radius)] bg-[hsl(var(--hu-background))] border border-[hsl(var(--hu-border))] shrink-0"
        src="https://api.dicebear.com/9.x/micah/svg?seed=Sara"
        width={35}
        height={35}
      />
      <SidebarText className="font-semibold text-lg">HextaUI</SidebarText>
    </SidebarHeader>

    <SidebarBody>
      <SidebarItem id="dashboard" label="Dashboard" icon={Home} />
      <SidebarItem id="workspace" label="Workspace" icon={Briefcase}>
        <SidebarItem
          id="projects"
          label="Projects"
          icon={Folder}
          badge={
            <Badge variant="secondary" size="sm">
              8
            </Badge>
          }
        />
        <SidebarItem
          id="tasks"
          label="Tasks"
          icon={CheckCircle}
          badge={
            <Badge variant="destructive" size="sm">
              3
            </Badge>
          }
        />
        <SidebarItem id="documents" label="Documents" icon={FileText} />
      </SidebarItem>
      <SidebarItem id="analytics" label="Analytics" icon={BarChart3} />
      <SidebarItem id="team" label="Team" icon={Users} />
    </SidebarBody>

    <SidebarFooter>
      {/* Admin items and profile dropdown */}
    </SidebarFooter>
  </Sidebar>

</div>
);
}

Mobile Responsive

Mobile Layout

This layout is optimized for mobile devices with overlay sidebar.

"use client";

import * as React from "react";
import {
Sidebar,
SidebarBody,
SidebarItem,
SidebarContent,
SidebarHeader,
SidebarText,
} from "./sidebar";
import { Badge } from "../badge";
import { Button } from "../button";
import { Home, Search, Bell, User, Settings } from "lucide-react";

export function SidebarMobile() {
const [collapsed, setCollapsed] = React.useState(true);

return (

<div className="relative h-screen w-full flex overflow-hidden rounded-[var(--radius)] border border-[hsl(var(--hu-border))]">
  <Sidebar
    position="relative"
    collapsed={collapsed}
    onCollapsedChange={setCollapsed}
    overlay={true}
    onOverlayClick={() => setCollapsed(true)}
  >
    <SidebarHeader>
      <img
        className="rounded-[var(--radius)] bg-[hsl(var(--hu-background))] border border-[hsl(var(--hu-border))] shrink-0"
        src="https://api.dicebear.com/9.x/micah/svg?seed=Sara"
        width={35}
        height={35}
      />
      <SidebarText className="font-semibold text-lg">HextaUI</SidebarText>
    </SidebarHeader>

    <SidebarBody>
      <SidebarItem id="home" label="Home" icon={Home} />
      <SidebarItem id="search" label="Search" icon={Search} />
      <SidebarItem
        id="notifications"
        label="Notifications"
        icon={Bell}
        badge={
          <Badge variant="destructive" size="sm">
            5
          </Badge>
        }
      />
      <SidebarItem id="profile" label="Profile" icon={User} />
      <SidebarItem id="settings" label="Settings" icon={Settings} />
    </SidebarBody>
  </Sidebar>

</div>
);
}

Props

PropTypeDefault
children?
React.ReactNode
undefined
overlay?
boolean
false
position?
"fixed" | "relative"
"fixed"
size?
"sm" | "default" | "lg" | "xl"
"default"
variant?
"default" | "elevated" | "ghost"
"default"
collapsible?
boolean
true
onCollapsedChange?
(collapsed: boolean) => void
undefined
collapsed?
boolean
false

SidebarItem

PropTypeDefault
onClick?
() => void
undefined
children?
React.ReactNode
undefined
badge?
React.ReactNode
undefined
href?
string
undefined
icon?
LucideIcon
undefined
label?
string
undefined
id?
string
undefined

SidebarContent

PropTypeDefault
className?
string
undefined
children?
React.ReactNode
undefined
position?
"fixed" | "relative"
"fixed"
sidebarCollapsed?
boolean
false

SidebarText

PropTypeDefault
animation?
boolean
true
className?
string
undefined
children?
React.ReactNode
undefined
Edit on GitHub

Last updated on