Split Pane

Layout

Dual-pane layout with adjustable divider.

Preview

Usage

example.jsx
import { SplitPane } from "@/components/ui/split-pane";

export default function Example() {
  return <SplitPane />;
}

Source Code

Copy this file into components/ui/split-pane.jsx in your project.

split-pane.jsx
"use client";

import { forwardRef, useState, useRef, useCallback } from "react";
import { cn } from "@/lib/utils";

const SplitPane = forwardRef(({ className, left, right, defaultPosition = 50, direction = "horizontal", ...props }, ref) => {
  const [pos, setPos] = useState(defaultPosition);
  const containerRef = useRef(null);

  const onMouseDown = useCallback((e) => {
    e.preventDefault();
    const onMouseMove = (e) => {
      const rect = containerRef.current.getBoundingClientRect();
      const newPos = direction === "horizontal"
        ? ((e.clientX - rect.left) / rect.width) * 100
        : ((e.clientY - rect.top) / rect.height) * 100;
      setPos(Math.min(90, Math.max(10, newPos)));
    };
    const onMouseUp = () => { window.removeEventListener("mousemove", onMouseMove); window.removeEventListener("mouseup", onMouseUp); };
    window.addEventListener("mousemove", onMouseMove);
    window.addEventListener("mouseup", onMouseUp);
  }, [direction]);

  const isH = direction === "horizontal";

  return (
    <div ref={(el) => { containerRef.current = el; if (typeof ref === "function") ref(el); else if (ref) ref.current = el; }}
      className={cn("flex overflow-hidden rounded-md border", isH ? "flex-row" : "flex-col", className)}
      {...props}
    >
      <div style={isH ? { width: `${pos}%` } : { height: `${pos}%` }} className="overflow-auto">{left}</div>
      <div onMouseDown={onMouseDown} className={cn("shrink-0 bg-border hover:bg-primary/20 transition-colors", isH ? "w-1 cursor-col-resize" : "h-1 cursor-row-resize")} />
      <div className="flex-1 overflow-auto">{right}</div>
    </div>
  );
});
SplitPane.displayName = "SplitPane";

export { SplitPane };

Quick Install

Make sure you have the cn() utility set up. It requires clsx and tailwind-merge.

npm install clsx tailwind-merge