Purbayan Pramanik

Snap Panels

Component

About

A resizable split-panel layout whose divider magnetically leans toward configured snap points and can be collapsed, used for sidebars, IDE-style layouts, and mail-client panes.

Built with React and Tailwind. Copy the prompt and paste it into Claude Code, Cursor or Lovable: your agent adds Snap Panels to your project and fits it to your theme.

Code

How Snap Panels is used: the demo's code. The component's own source comes with a free account.

Usage.tsx

"use client";

import {
  SnapPanel,
  SnapPanelGroup,
  SnapPanelHandle,
  type Size,
} from "@/components/ui/snap-panels";
import { useRef } from "react";
import { FileCode2 } from "lucide-react";
import { cn } from "@/lib/utils";

const FILES = [
  "client.ts",
  "errors.ts",
  "providers.ts",
  "retry.ts",
  "stream.ts",
  "tokens.ts",
  "types.ts",
  "index.ts",
];

const CODE = [
  "export async function retry<T>(",
  "  run: () => Promise<T>,",
  "  budget: Budget,",
  ") {",
  "  while (budget.hasRoom()) {",
  "    try { return await run(); }",
  "    catch (error) { budget.spend(error); }",
  "  }",
  "  throw budget.exhausted();",
  "}",
];

export default function SnapPanelsBasicExample() {
  const readoutRef = useRef<HTMLSpanElement>(null);

  // `onLayoutChanging` fires every frame, so it writes to the DOM directly.
  // Routing it through React state would hand back the per-frame render the
  // component's CSS custom property exists to avoid.
  const showWidth = (sizes: Size[]) => {
    if (readoutRef.current) readoutRef.current.textContent = String(sizes[0]);
  };

  return (
    <div className="h-72 w-full max-w-xl overflow-hidden rounded-lg border border-border bg-card">
      <SnapPanelGroup
        direction="horizontal"
        onLayoutChanging={showWidth}
        onLayoutChange={showWidth}
      >
        <SnapPanel
          id="sidebar"
          defaultSize="280px"
          minSize="200px"
          snapPoints={["280px", "380px"]}
          collapsible
        >
          <div className="flex h-full flex-col bg-background">
            <div className="flex h-9 shrink-0 items-center border-b border-border px-3.5">
              <span className="text-label text-muted-foreground uppercase">
                src
              </span>
            </div>
            <div className="flex flex-col gap-px p-1.5">
              {FILES.map((file) => (
                <span
                  key={file}
                  className={cn(
                    "flex items-center gap-2 truncate rounded-md px-2 py-1 font-mono text-2xs",
                    file === "retry.ts"
                      ? "bg-active text-foreground"
                      : "text-muted-foreground",
                  )}
                >
                  <FileCode2 className="size-3 shrink-0 opacity-60" />
                  {file}
                </span>
              ))}
            </div>
          </div>
        </SnapPanel>
        <SnapPanelHandle aria-label="Resize sidebar" />
        <SnapPanel id="content" minSize={25}>
          <div className="flex h-full flex-col">
            <div className="flex h-9 shrink-0 items-center justify-between gap-3 border-b border-border px-3">
              <span className="truncate font-mono text-2xs text-foreground">
                retry.ts
              </span>
              <span className="shrink-0 font-mono text-2xs text-muted-foreground">
                sidebar{" "}
                <span ref={readoutRef} className="tabular-nums text-foreground">
                  280px
                </span>
              </span>
            </div>
            <div className="flex flex-col overflow-hidden p-3">
              {CODE.map((line, index) => (
                <span
                  key={line}
                  className="flex gap-3 truncate whitespace-pre font-mono text-2xs leading-5"
                >
                  <span className="w-3 shrink-0 text-right text-muted-foreground/50 tabular-nums">
                    {index + 1}
                  </span>
                  <span className="text-muted-foreground">{line}</span>
                </span>
              ))}
            </div>
          </div>
        </SnapPanel>
      </SnapPanelGroup>
    </div>
  );
}

Dependencies

More by Purbayan Pramanik

View all
  • Notification Stack

    Notification Stack

    22
  • Proximity Accordion

    Proximity Accordion

    5
  • Plan Checklist

    Plan Checklist

  • Agent Activity

    Agent Activity

  • Checkbox Group

    Checkbox Group

  • Conversation

    Conversation