Resizable

Layout

Container with draggable resize handle.

Preview

Drag the edge to resize this container →

Usage

example.jsx
import { Resizable } from "@/components/ui/resizable";

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

Source Code

Copy this file into components/ui/resizable.jsx in your project.

resizable.jsx
"use client";

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

const Resizable = forwardRef(({ className, children, minWidth = 100, minHeight = 100, ...props }, ref) => {
  const containerRef = useRef(null);
  const [size, setSize] = useState({ width: "100%", height: "auto" });
  const dragging = useRef(false);

  const onMouseDown = useCallback((e) => {
    e.preventDefault();
    dragging.current = true;
    const startX = e.clientX;
    const startY = e.clientY;
    const rect = containerRef.current.getBoundingClientRect();
    const startW = rect.width;
    const startH = rect.height;

    const onMouseMove = (e) => {
      if (!dragging.current) return;
      setSize({
        width: Math.max(minWidth, startW + e.clientX - startX),
        height: Math.max(minHeight, startH + e.clientY - startY),
      });
    };

    const onMouseUp = () => { dragging.current = false; window.removeEventListener("mousemove", onMouseMove); window.removeEventListener("mouseup", onMouseUp); };
    window.addEventListener("mousemove", onMouseMove);
    window.addEventListener("mouseup", onMouseUp);
  }, [minWidth, minHeight]);

  return (
    <div ref={(el) => { containerRef.current = el; if (typeof ref === "function") ref(el); else if (ref) ref.current = el; }}
      className={cn("relative overflow-auto rounded-md border", className)}
      style={{ width: size.width, height: size.height }}
      {...props}
    >
      {children}
      <div onMouseDown={onMouseDown} className="absolute bottom-0 right-0 h-4 w-4 cursor-se-resize" >
        <svg className="h-4 w-4 text-muted-foreground" viewBox="0 0 24 24" fill="currentColor"><path d="M22 22H20V20H22V22ZM22 18H18V22H16V16H22V18ZM22 14H14V22H12V12H22V14Z" /></svg>
      </div>
    </div>
  );
});
Resizable.displayName = "Resizable";

export { Resizable };

Quick Install

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

npm install clsx tailwind-merge