One
Two
Three
import {
ResizableHandle,
ResizablePanel,
ResizablePanelGroup,
} from "@/components/ui/resizable"
export default function ResizableDemo() {
return (
<ResizablePanelGroup
direction="horizontal"
className="max-w-md rounded-lg border md:min-w-[450px]"
>
<ResizablePanel defaultSize={50}>
<div className="flex h-[200px] items-center justify-center p-6">
<span className="font-semibold">One</span>
</div>
</ResizablePanel>
<ResizableHandle withHandle />
<ResizablePanel defaultSize={50}>
<ResizablePanelGroup direction="vertical">
<ResizablePanel defaultSize={25}>
<div className="flex h-full items-center justify-center p-6">
<span className="font-semibold">Two</span>
</div>
</ResizablePanel>
<ResizableHandle withHandle />
<ResizablePanel defaultSize={75}>
<div className="flex h-full items-center justify-center p-6">
<span className="font-semibold">Three</span>
</div>
</ResizablePanel>
</ResizablePanelGroup>
</ResizablePanel>
</ResizablePanelGroup>
)
}Installation
npx logic2b@latest add resizableWorking with an AI assistant? Copy this prompt into Claude Code, Cursor or Copilot — it carries the install steps, a no-CLI fallback and a verification checklist.
Add the "resizable" item from the logic2b ui registry (https://ui.logic2b.com) to this project. Follow every step and verify at the end. ## Steps 1. If the project has no `components.json` yet, set up logic2b ui first: ```bash npx logic2b@latest init ``` 2. Install the item (the CLI resolves registry dependencies automatically): ```bash npx logic2b@latest add resizable ``` 3. Install any npm dependencies the command prints. ## If the CLI is not available Do it manually from the registry payload: 1. Fetch https://ui.logic2b.com/r/resizable.json. 2. Write every entry in `files[]` to its mapped project path (see below). 3. Repeat (recursively) for each name in `registryDependencies`. 4. Install every package listed in `dependencies` across those payloads. ## Registry reference - Index of every item: https://ui.logic2b.com/r/index.json - Item payload (full source): https://ui.logic2b.com/r/<name>.json - Usage examples per item: https://ui.logic2b.com/r/demos/index.json → https://ui.logic2b.com/r/demos/<demo>.json - Docs index for agents: https://ui.logic2b.com/llms.txt (full docs: https://ui.logic2b.com/llms-full.txt) - Every docs page is Markdown when you append `.md` to its URL. Registry file paths map to project paths like this: - `ui/*` → `@/components/ui/*` - `blocks/<name>/*` → `@/components/*` - `charts/*` → `@/components/charts/*` - `hooks/*` → `@/hooks/*` - `lib/utils.ts` → `@/lib/utils.ts` - `theme.css` → next to the project's Tailwind entry stylesheet ## Conventions (do not break these) - Tailwind CSS v4 (CSS-first config; no tailwind.config.js needed) and React 19. - All colors go through semantic tokens (`bg-primary`, `text-muted-foreground`, `border-border`, …). Never hardcode hex/oklch values in components. - Dark mode is class-based: toggle `.dark` on `<html>`. - Icons come from lucide-react. ## Verify before finishing 1. The dev server starts and the app renders without console errors. 2. TypeScript compiles (`tsc --noEmit` or the framework's check). 3. Components use the theme: a `<Button>` shows the primary token color, and toggling `.dark` on `<html>` switches the palette.
Install the dependencies:
npm install react-resizable-panels lucide-reactCopy into ui/resizable.tsx:
"use client"
import * as React from "react"
import { GripVerticalIcon } from "lucide-react"
import {
Group as ResizablePanelGroupPrimitive,
Panel as ResizablePanelPrimitive,
Separator as ResizableSeparatorPrimitive,
} from "react-resizable-panels"
import { cn } from "@/lib/utils"
const ResizableDirectionContext = React.createContext<
"horizontal" | "vertical"
>("horizontal")
function ResizablePanelGroup({
className,
direction = "horizontal",
...props
}: React.ComponentProps<typeof ResizablePanelGroupPrimitive> & {
direction?: "horizontal" | "vertical"
}) {
return (
<ResizableDirectionContext.Provider value={direction}>
<ResizablePanelGroupPrimitive
data-slot="resizable-panel-group"
orientation={direction}
className={cn(
"flex h-full w-full",
direction === "vertical" && "flex-col",
className
)}
{...props}
/>
</ResizableDirectionContext.Provider>
)
}
function ResizablePanel({
...props
}: React.ComponentProps<typeof ResizablePanelPrimitive>) {
return <ResizablePanelPrimitive data-slot="resizable-panel" {...props} />
}
function ResizableHandle({
withHandle,
className,
...props
}: React.ComponentProps<typeof ResizableSeparatorPrimitive> & {
withHandle?: boolean
}) {
const direction = React.useContext(ResizableDirectionContext)
const isVertical = direction === "vertical"
return (
<ResizableSeparatorPrimitive
data-slot="resizable-handle"
className={cn(
"bg-border focus-visible:ring-ring relative flex items-center justify-center after:absolute focus-visible:ring-1 focus-visible:ring-offset-1 focus-visible:outline-hidden",
isVertical
? "h-px w-full after:inset-x-0 after:top-1/2 after:h-1 after:-translate-y-1/2 after:translate-x-0"
: "w-px after:inset-y-0 after:left-1/2 after:w-1 after:-translate-x-1/2",
className
)}
{...props}
>
{withHandle && (
<div
className={cn(
"bg-border z-10 flex items-center justify-center rounded-xs border",
isVertical ? "h-3 w-4 rotate-90" : "h-4 w-3"
)}
>
<GripVerticalIcon className="size-2.5" />
</div>
)}
</ResizableSeparatorPrimitive>
)
}
export { ResizablePanelGroup, ResizablePanel, ResizableHandle }Usage
import {
ResizableHandle,
ResizablePanel,
ResizablePanelGroup,
} from "@/components/ui/resizable"
<ResizablePanelGroup direction="horizontal">
<ResizablePanel>One</ResizablePanel>
<ResizableHandle withHandle />
<ResizablePanel>Two</ResizablePanel>
</ResizablePanelGroup>
API
| Prop | Type | Default |
|---|---|---|
direction (ResizablePanelGroup) |
horizontal | vertical |
horizontal |
defaultSize / minSize / maxSize (ResizablePanel) |
number (percentage) |
— |
withHandle (ResizableHandle) |
boolean — shows a visible grip |
false |
Built on react-resizable-panels v4.
This registry wraps its Group/Panel/Separator exports as
ResizablePanelGroup/ResizablePanel/ResizableHandle and keeps the
familiar direction prop name (mapped internally to the library’s
orientation prop) for API stability across upstream versions.
Examples
Vertical
Header
Content
import {
ResizableHandle,
ResizablePanel,
ResizablePanelGroup,
} from "@/components/ui/resizable"
export default function ResizableVerticalDemo() {
return (
<ResizablePanelGroup
direction="vertical"
className="min-h-[200px] max-w-md rounded-lg border md:min-w-[450px]"
>
<ResizablePanel defaultSize={30}>
<div className="flex h-full items-center justify-center p-6">
<span className="font-semibold">Header</span>
</div>
</ResizablePanel>
<ResizableHandle withHandle />
<ResizablePanel defaultSize={70}>
<div className="flex h-full items-center justify-center p-6">
<span className="font-semibold">Content</span>
</div>
</ResizablePanel>
</ResizablePanelGroup>
)
}Constrained sizes
Sidebar
Main
import {
ResizableHandle,
ResizablePanel,
ResizablePanelGroup,
} from "@/components/ui/resizable"
// `minSize`/`maxSize` clamp how far the divider can travel (as percentages).
export default function ResizableConstrainedDemo() {
return (
<ResizablePanelGroup
direction="horizontal"
className="max-w-md rounded-lg border md:min-w-[450px]"
>
<ResizablePanel defaultSize={25} minSize={20} maxSize={40}>
<div className="flex h-[200px] items-center justify-center p-6">
<span className="font-semibold">Sidebar</span>
</div>
</ResizablePanel>
<ResizableHandle withHandle />
<ResizablePanel defaultSize={75}>
<div className="flex h-[200px] items-center justify-center p-6">
<span className="font-semibold">Main</span>
</div>
</ResizablePanel>
</ResizablePanelGroup>
)
}