shadcn-resizable-sidebar

repository·main·Indexed 42 days ago

https://github.com/lumpinif/shadcn-resizable-sidebar

A drop-in enhancement for the shadcn/ui Sidebar (v0.2.0) that adds drag-to-resize functionality, persistent width and state via cookies, and smooth pointer-driven interactions. It includes the SidebarRail component for resizing and a SidebarProvider for state management and server-side restoration in Next.js.

Tokens
2.2K
Snippets
6
Records
10
Agent score
53%

What's inside shadcn-resizable-sidebar

  1. Core Sidebar Components and Hooks

    main

    The following files contain the custom logic that differentiates this project from the standard shadcn/ui sidebar. Modifications to these files must be handled with extreme caution to avoid breaking the resizing and persistence features:

    • components/ui/sidebar.tsx: The main sidebar component containing the custom drag-to-resize logic and layout.
    • hooks/use-sidebar-resize.ts: The hook managing the resizing state and width calculations.
  2. Steal the code (Integration Guide)

    main

    This project is designed as an enhanced fork of the shadcn/ui Sidebar. To integrate it into your project, you should copy the following core files:

    • components/ui/sidebar.tsx (The enhanced sidebar components)
    • hooks/use-sidebar-resize.ts (The resizing logic)
    • components/providers/index.tsx (Use this if you want the server-side cookie restore behavior)
    • app/globals.css (Copy this if you want the same shadcn/ui neutral theme tokens)
  3. Install and setup shadcn-resizable-sidebar

    main

    To use this project as a reference or to run the demo locally, clone the repository, install dependencies using Bun, and start the development server.

    git clone https://github.com/lumpinif/shadcn-resizable-sidebar.git
    cd shadcn-resizable-sidebar
    bun install
    bun dev
  4. Restore sidebar state on the server

    main

    To prevent layout shift and ensure a smooth user experience, you can restore the sidebar's width and collapse state on the server using cookies.

    By default, the provider writes to sidebar:state and sidebar:width. You can pass a custom cookieKey to SidebarProvider to manage multiple independent sidebars on the same page.

    In Next.js, read the cookies in a server component (like a provider wrapper) and pass them as defaultOpen and defaultWidth to the SidebarProvider.

    import { cookies } from "next/headers"
    import { SidebarProvider } from "@/components/ui/sidebar"
    
    const SIDEBAR_COOKIE_KEY = "sidebar"
    
    export async function Providers({ children }: { children: React.ReactNode }) {
      const cookieStore = await cookies()
    
      const sidebarState = cookieStore.get(`${SIDEBAR_COOKIE_KEY}:state`)?.value
      const sidebarWidth = cookieStore.get(`${SIDEBAR_COOKIE_KEY}:width`)?.value
    
      return (
        <SidebarProvider
          cookieKey={SIDEBAR_COOKIE_KEY}
          defaultOpen={sidebarState ? sidebarState === "true" : true}
          defaultWidth={sidebarWidth}
        >
          {children}
        </SidebarProvider>
      )
    }
  5. Maintain project integrity and guardrails

    main

    When working with this repository, adhere to the following constraints to prevent breaking the custom resizable sidebar functionality:

    • Package Manager: Use bun exclusively (bun install, bun add, bun remove, bun update, and bunx).
    • Lockfiles: Do not create package-lock.json, pnpm-lock.yaml, or yarn.lock. Only bun.lockb is permitted.
    • Sidebar Protection:
      • DO NOT run bunx shadcn@latest add sidebar as this will overwrite the custom resizable implementation.
      • Treat components/ui/sidebar.tsx and hooks/use-sidebar-resize.ts as the core fork. Any changes to these files require manual diff review to ensure drag-to-resize behavior and cookie persistence are not lost.
    • State Persistence: Ensure existing sidebar cookies sidebar:state and sidebar:width are preserved, along with server-side cookie seeding in components/providers/index.tsx.
  6. Implement basic resizable sidebar usage

    main

    This project is an enhanced version of the shadcn/ui Sidebar. To implement it, wrap your sidebar content in a SidebarProvider and include a SidebarRail inside your Sidebar.

    SidebarRail provides the interaction surface for:

    • Dragging to resize the sidebar.
    • Clicking to collapse or expand the sidebar.
    • Releasing a drag to persist the new width.

    Note: SidebarProvider requires a defaultWidth (e.g., 16rem) to initialize correctly.

    import {
      Sidebar,
      SidebarContent,
      SidebarProvider,
      SidebarRail,
    } from "@/components/ui/sidebar"
    
    export function AppSidebar() {
      return (
        <SidebarProvider defaultWidth="16rem">
          <Sidebar collapsible="icon">
            <SidebarContent>{/* Your existing sidebar content */}</SidebarContent>
            <SidebarRail />
          </Sidebar>
        </SidebarProvider>
      )
    }
  7. Configure SidebarRail props

    main

    The SidebarRail component provides the drag/click interaction surface. It accepts the following props:

    PropPurpose
    enableDragEnables or disables drag resize. Defaults to true.
    directionSet to "right" for a left sidebar, or "left" for a right sidebar.

    Example: Right-side sidebar

    <Sidebar side="right">
      <SidebarRail direction="left" />
    </Sidebar>
    <Sidebar side="left">
      <SidebarRail direction="right" />
    </Sidebar>
    
    <Sidebar side="right">
      <SidebarRail direction="left" />
    </Sidebar>
  8. Public API stability for Sidebar Resizing

    main

    Despite internal modernization of the resize hook, the public API for controlling and observing sidebar width remains unchanged. You can continue to use the following props, state, and hooks to manage the sidebar:

    Props and State

    • defaultWidth: The initial width of the sidebar.
    • width: The current width.
    • setWidth: Function to manually set the width.
    • isDraggingRail: Boolean indicating if the user is currently dragging the resize rail.
    • setIsDraggingRail: Function to update the dragging state.
    • enableDrag: Boolean to enable or disable resizing.

    Components and Hooks

    • SidebarRail: The component used to trigger resizing.
    • useSidebarResize: The hook for managing resize logic.
    • sidebar:state: State identifier.
    • sidebar:width: State identifier for width.

    Data Attributes and Constants

    • data-dragging: Attribute applied during drag operations.
    • duration-0: Attribute used to manage transition timing during drag.
    • MIN_SIDEBAR_WIDTH: Constant defining the minimum allowed width.
    • MAX_SIDEBAR_WIDTH: Constant defining the maximum allowed width.
    // The following public tokens remain stable:
    // defaultWidth, width, setWidth, isDraggingRail, setIsDraggingRail, 
    // SidebarRail, enableDrag, useSidebarResize, sidebar:state, 
    // sidebar:width, data-dragging, duration-0, MIN_SIDEBAR_WIDTH, MAX_SIDEBAR_WIDTH
  9. Use the Providers component to wrap your application

    main

    The Providers component is an asynchronous React Server Component that sets up the application's theme and sidebar state. It handles reading sidebar state and width from cookies to ensure server-side restoration of the sidebar's appearance.

    It wraps the application in:

    1. ThemeProvider (from next-themes) for dark/light mode support.
    2. SidebarProvider for managing sidebar state and resizing.
    3. AppSidebar and AppSidebarInset to define the layout structure.

    Because it is an async component, it must be used within a Server Component context (like a layout file in Next.js).

    import { Providers } from "./components/providers";
    
    export default async function RootLayout({ children }: { children: React.ReactNode }) {
      return (
        <html>
          <body>
            <Providers>{children}</Providers>
          </body>
        </html>
      );
    }