shadcn.io is not affiliated with official shadcn/ui
Shadcn Resizable for React and Tailwind
Divides the interface into resizable sections.
One
Two
Three
Installation
bunx --bun shadcn@latest add https://kit.dev/r/resizable.jsonpnpm dlx shadcn@latest add https://kit.dev/r/resizable.jsonnpx shadcn@latest add https://kit.dev/r/resizable.jsonyarn shadcn@latest add https://kit.dev/r/resizable.jsonInstall the following dependencies:
bun add @ark-ui/react lucide-reactpnpm add @ark-ui/react lucide-reactnpm install @ark-ui/react lucide-reactyarn add @ark-ui/react lucide-reactCopy and paste the following code into your project.
"use client";
import {
Splitter as ArkSplitter,
useSplitterContext,
} from "@ark-ui/react/splitter";
import { GripVertical } from "lucide-react";
import type React from "react";
import { cn } from "@/lib/utils";
export const useResizable = useSplitterContext;
export const Resizable = (
props: React.ComponentProps<typeof ArkSplitter.Root>
) => {
const { className, ...rest } = props;
return (
<ArkSplitter.Root
className={cn("flex size-full", className)}
data-slot="resizable"
{...rest}
/>
);
};
export const ResizablePanel = (
props: React.ComponentProps<typeof ArkSplitter.Panel>
) => <ArkSplitter.Panel data-slot="resizable-panel" {...props} />;
interface ResizableResizeTriggerProps
extends React.ComponentProps<typeof ArkSplitter.ResizeTrigger> {
/**
* Whether to show the handle
*
* @default false
*/
withHandle?: boolean;
}
export const ResizableResizeTrigger = (props: ResizableResizeTriggerProps) => {
const { withHandle = false, className, ...rest } = props;
return (
<ArkSplitter.ResizeTrigger
aria-label="Resize"
className={cn(
"relative bg-border",
"flex w-px items-center justify-center",
"after:-translate-x-1/2 data-[orientation=vertical]:after:-translate-y-1/2",
"after:absolute after:inset-s-1/2 after:inset-y-0 after:w-1",
"focus-visible:outline-hidden focus-visible:ring-1 focus-visible:ring-ring focus-visible:ring-offset-1",
"data-[orientation=vertical]:h-px data-[orientation=vertical]:w-full",
"data-[orientation=vertical]:after:inset-s-0 data-[orientation=vertical]:after:h-1 data-[orientation=vertical]:after:w-full",
"data-[orientation=vertical]:after:translate-x-0",
"[&[data-orientation=vertical]>div]:rotate-90",
className
)}
data-slot="resizable-resize-trigger"
{...rest}
>
{withHandle && (
<div
className={cn(
"z-10",
"h-4 w-3",
"flex items-center justify-center",
"bg-border",
"rounded-xs border"
)}
>
<GripVertical className="size-2.5" />
</div>
)}
</ArkSplitter.ResizeTrigger>
);
};Update the import paths to match your project setup.
Anatomy
Resizable
├── ResizablePanel
└── ResizableResizeTrigger
└── ResizableResizeTriggerIndicatorUsage
import {
Resizable,
ResizablePanel,
ResizableResizeTrigger,
} from "@/components/ui/resizable";<Resizable
className="rounded-md border"
defaultSize={[50, 50]}
panels={[
{ id: "1", minSize: 10 },
{ id: "2", minSize: 10 },
]}
>
<ResizablePanel className="flex h-full items-center justify-center" id="1">
One
</ResizablePanel>
<ResizableResizeTrigger id="1:2" />
<ResizablePanel id="2">
<Resizable
defaultSize={[50, 50]}
orientation="vertical"
panels={[
{ id: "3", minSize: 10 },
{ id: "4", minSize: 10 },
]}
>
<ResizablePanel className="flex items-center justify-center" id="3">
Two
</ResizablePanel>
<ResizableResizeTrigger id="3:4" />
<ResizablePanel className="flex items-center justify-center" id="4">
Three
</ResizablePanel>
</Resizable>
</ResizablePanel>
</Resizable>Accessibility
| Key | Description |
|---|---|
Enter | Activate the focused item. |
ArrowUp | Move up. |
ArrowDown | Move down. |
ArrowLeft | Move left. |
ArrowRight | Move right. |
Home | Go to the start. |
End | Go to the end. |
F6 | Handle the F6 key. |
Demos
Handle
Min Max
Multiple Panels
Orientation Horizontal
Orientation Vertical
API Reference
Resizable
div
PropType
AttributeType
ResizablePanel
div
PropType
AttributeType
ResizableResizeTrigger
button
PropType
AttributeType