Docs Kickstarter

Sidebar

The Sidebar component provides navigation for documentation sites and dashboards. It supports responsive behavior, collapsible sections, and various styling options.

Basic Usage

import { Sidebar } from "@/components/docs/Sidebar"

const navigation = [
  {
    title: "Getting Started",
    items: [
      {
        title: "Introduction",
        href: "/docs/introduction",
      },
      {
        title: "Installation",
        href: "/docs/installation",
      },
    ],
  },
  {
    title: "Components",
    items: [
      {
        title: "Button",
        href: "/docs/components/button",
      },
    ],
  },
]

<Sidebar items={navigation} />

Component Implementation

Here’s a basic implementation of the Sidebar component:

// components/docs/Sidebar.tsx
import { cn } from "@/lib/utils"
import { useState } from "react"
import { ChevronDown } from "lucide-react"

interface SidebarProps {
  items: {
    title: string
    items: {
      title: string
      href: string
    }[]
  }[]
  className?: string
  currentPath?: string
}

export function Sidebar({ items, className, currentPath }: SidebarProps) {
  const [expanded, setExpanded] = useState<string[]>([])

  const toggleSection = (title: string) => {
    setExpanded(current => 
      current.includes(title)
        ? current.filter(t => t !== title)
        : [...current, title]
    )
  }

  return (
    <nav className={cn("w-full", className)}>
      {items.map((section) => (
        <div key={section.title} className="pb-4">
          <button
            onClick={() => toggleSection(section.title)}
            className="flex w-full items-center justify-between px-2 py-1 text-sm font-semibold"
          >
            {section.title}
            <ChevronDown 
              className={cn(
                "h-4 w-4 transition-transform",
                expanded.includes(section.title) && "rotate-180"
              )}
            />
          </button>
          
          {expanded.includes(section.title) && (
            <div className="grid grid-flow-row auto-rows-max text-sm">
              {section.items.map((item) => (
                <a
                  key={item.href}
                  href={item.href}
                  className={cn(
                    "flex w-full items-center rounded-md p-2 hover:underline",
                    currentPath === item.href && "bg-accent"
                  )}
                >
                  {item.title}
                </a>
              ))}
            </div>
          )}
        </div>
      ))}
    </nav>
  )
}

With Icons

Add icons to sidebar items:

const navigationWithIcons = [
  {
    title: "Getting Started",
    icon: <BookIcon className="h-4 w-4" />,
    items: [
      {
        title: "Introduction",
        href: "/docs/introduction",
        icon: <FileTextIcon className="h-4 w-4" />,
      },
    ],
  },
]

<Sidebar items={navigationWithIcons} />

Collapsible Sections

Implement collapsible sections with animation:

<div
  className={cn(
    "grid overflow-hidden transition-all",
    expanded.includes(section.title)
      ? "grid-rows-[1fr]"
      : "grid-rows-[0fr]"
  )}
>
  <div className="min-h-0">
    {/* Section content */}
  </div>
</div>

Mobile Navigation

Add a mobile navigation drawer:

import { Sheet, SheetContent, SheetTrigger } from "@/components/ui/sheet"
import { Button } from "@/components/ui/button"
import { Menu } from "lucide-react"

export function MobileNav({ items }) {
  return (
    <Sheet>
      <SheetTrigger asChild>
        <Button variant="ghost" className="md:hidden">
          <Menu className="h-6 w-6" />
        </Button>
      </SheetTrigger>
      <SheetContent side="left" className="w-[300px] p-0">
        <Sidebar items={items} className="p-6" />
      </SheetContent>
    </Sheet>
  )
}

Add a search input to the sidebar:

<div className="sticky top-0 bg-background p-4 backdrop-blur">
  <div className="relative">
    <Search className="absolute left-2 top-2.5 h-4 w-4 text-muted-foreground" />
    <input
      placeholder="Search..."
      className="w-full rounded-md border pl-8 text-sm"
    />
  </div>
</div>

Nested Navigation

Support multiple levels of navigation:

interface NestedItem {
  title: string
  href?: string
  items?: NestedItem[]
}

function renderItems(items: NestedItem[], depth = 0) {
  return items.map((item) => (
    <div key={item.title} style={{ paddingLeft: `${depth * 12}px` }}>
      {item.href ? (
        <a href={item.href}>{item.title}</a>
      ) : (
        <span>{item.title}</span>
      )}
      {item.items?.length && renderItems(item.items, depth + 1)}
    </div>
  ))
}

Best Practices

  1. Navigation Structure

    • Keep hierarchy clear
    • Limit nesting levels
    • Group related items
  2. Responsive Design

    • Handle mobile views
    • Consider tablet layouts
    • Smooth transitions
  3. Accessibility

    • Keyboard navigation
    • ARIA labels
    • Focus management
  4. State Management

    • Remember expanded sections
    • Highlight current page
    • Handle deep linking
  5. Performance

    • Optimize animations
    • Lazy load content
    • Cache expanded state
  6. Visual Design

    • Clear visual hierarchy
    • Consistent spacing
    • Proper indentation