Split Pane
LayoutDual-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