Aura Design System

Resizable

Panels that resize by drag or keyboard.

Preview

Loading...
import {
  ResizableHandle,
  ResizablePanel,
  ResizablePanelGroup,
} from "@/components/ui/Resizable";

export function ResizableDemo() {
  return (
    <div className="h-16 w-full overflow-hidden rounded-md border border-gray-6">
    <ResizablePanelGroup direction="horizontal" className="h-full">
      <ResizablePanel defaultSize={50} minSize={20}>
        <div className="flex h-full items-center justify-center p-1 text-sm text-gray-12">
          One
        </div>
      </ResizablePanel>
      <ResizableHandle withHandle />
      <ResizablePanel defaultSize={50} minSize={20}>
        <div className="flex h-full items-center justify-center p-1 text-sm text-gray-12">
          Two
        </div>
      </ResizablePanel>
    </ResizablePanelGroup>
    </div>
  );
}

Installation

Make sure that namespace is set in your component.json file. Namespace docs: Learn more about namespaces

pnpm dlx shadcn@latest add @aura/resizable

Manual

Install the following dependencies:

pnpm install @radix-ui/react-icons react-resizable-panels

Copy and paste the class names utility into your utils/class-names.ts file.

import { clsx, type ClassValue } from "clsx"
import { twMerge } from "tailwind-merge"

export function cn(...inputs: ClassValue[]) {
  return twMerge(clsx(inputs))
}

Copy and paste the Resizable component into your components/ui/Resizable.tsx file.

"use client";
/**
 * @description Resizable panels. Drag the handle; keyboard users resize from the focused separator.
 */
import * as React from "react";
import { DragHandleDots2Icon } from "@radix-ui/react-icons";
import * as ResizablePrimitive from "react-resizable-panels";

import { cn } from "@/utils/class-names";

function ResizablePanelGroup({
  className,
  ...props
}: React.ComponentProps<typeof ResizablePrimitive.PanelGroup>) {
  return (
    <ResizablePrimitive.PanelGroup
      data-slot="resizable-panel-group"
      className={cn(
        "flex h-full w-full data-[panel-group-direction=vertical]:flex-col",
        className,
      )}
      {...props}
    />
  );
}

const ResizablePanel = ResizablePrimitive.Panel;

function ResizableHandle({
  withHandle,
  className,
  ...props
}: React.ComponentProps<typeof ResizablePrimitive.PanelResizeHandle> & {
  withHandle?: boolean;
}) {
  return (
    <ResizablePrimitive.PanelResizeHandle
      data-slot="resizable-handle"
      className={cn(
        "relative flex w-px items-center justify-center bg-gray-6 before:absolute before:inset-y-0 before:left-1/2 before:w-1 before:-translate-x-1/2 focus-visible:outline-2 focus-visible:outline-accent-8 data-[panel-group-direction=vertical]:h-px data-[panel-group-direction=vertical]:w-full data-[panel-group-direction=vertical]:before:left-0 data-[panel-group-direction=vertical]:before:h-1 data-[panel-group-direction=vertical]:before:w-full data-[panel-group-direction=vertical]:before:translate-x-0 data-[panel-group-direction=vertical]:before:-translate-y-1/2 data-[panel-group-direction=vertical]:[&>div]:rotate-90",
        className,
      )}
      {...props}
    >
      {withHandle ? (
        <div className="z-10 flex h-3 w-2 items-center justify-center rounded-sm border border-gray-6 bg-gray-2">
          <DragHandleDots2Icon className="icon" />
        </div>
      ) : null}
    </ResizablePrimitive.PanelResizeHandle>
  );
}

export { ResizablePanelGroup, ResizablePanel, ResizableHandle };

Usage

Vertical

export const Vertical = () => {
  return (
    <div className="h-16 w-full overflow-hidden rounded-md border border-gray-6">
    <ResizablePanelGroup direction="vertical" className="h-full">
      <ResizablePanel defaultSize={50}>
        <div className="flex h-full items-center justify-center p-1 text-sm">
          Top
        </div>
      </ResizablePanel>
      <ResizableHandle withHandle />
      <ResizablePanel defaultSize={50}>
        <div className="flex h-full items-center justify-center p-1 text-sm">
          Bottom
        </div>
      </ResizablePanel>
    </ResizablePanelGroup>
    </div>
  );
};