A component that divides your interface into resizable sections.
import { Resizable, ResizableHandle, ResizablePanel, } from "@repo/tailwindcss/ui/resizable"; const ResizableDemo = () => { return ( <Resizable class="max-w-md rounded-lg border"> <ResizablePanel initialSize={0.3} minSize={0.2}> <div class="flex h-[200px] items-center justify-center"> <span class="font-semibold">A</span> </div> </ResizablePanel> <ResizableHandle /> <ResizablePanel initialSize={0.7} minSize={0.2}> <Resizable orientation="vertical"> <ResizablePanel initialSize={0.5} minSize={0.2}> <div class="flex h-full items-center justify-center"> <span class="font-semibold">B</span> </div> </ResizablePanel> <ResizableHandle /> <ResizablePanel initialSize={0.5} minSize={0.2}> <div class="flex h-full items-center justify-center"> <span class="font-semibold">C</span> </div> </ResizablePanel> </Resizable> </ResizablePanel> </Resizable> ); }; export default ResizableDemo;
npx shadcn-solid@latest add resizable
npm install @corvu/resizable
import { cn } from "@/libs/cn"; import type { DynamicProps, HandleProps, RootProps } from "@corvu/resizable"; import ResizablePrimitive from "@corvu/resizable"; import type { ValidComponent, VoidProps } from "solid-js"; import { Show, splitProps } from "solid-js"; export const ResizablePanel = ResizablePrimitive.Panel; type resizableProps<T extends ValidComponent = "div"> = RootProps<T> & { class?: string; }; export const Resizable = <T extends ValidComponent = "div">( props: DynamicProps<T, resizableProps<T>>, ) => { const [local, rest] = splitProps(props as resizableProps, ["class"]); return <ResizablePrimitive class={cn("size-full", local.class)} {...rest} />; }; type resizableHandleProps<T extends ValidComponent = "button"> = VoidProps< HandleProps<T> & { class?: string; withHandle?: boolean; } >; export const ResizableHandle = <T extends ValidComponent = "button">( props: DynamicProps<T, resizableHandleProps<T>>, ) => { const [local, rest] = splitProps(props as resizableHandleProps, [ "class", "withHandle", ]); return ( <ResizablePrimitive.Handle class={cn( "flex w-px items-center justify-center bg-border transition-shadow focus-visible:outline-none focus-visible:ring-[1.5px] focus-visible:ring-ring focus-visible:ring-offset-1 data-[orientation=vertical]:h-px data-[orientation=vertical]:w-full", local.class, )} {...rest} > <Show when={local.withHandle}> <div class="z-10 flex h-4 w-3 items-center justify-center rounded-sm border bg-border"> <svg xmlns="http://www.w3.org/2000/svg" class="h-2.5 w-2.5" viewBox="0 0 15 15" > <path fill="currentColor" fill-rule="evenodd" d="M5.5 4.625a1.125 1.125 0 1 0 0-2.25a1.125 1.125 0 0 0 0 2.25m4 0a1.125 1.125 0 1 0 0-2.25a1.125 1.125 0 0 0 0 2.25M10.625 7.5a1.125 1.125 0 1 1-2.25 0a1.125 1.125 0 0 1 2.25 0M5.5 8.625a1.125 1.125 0 1 0 0-2.25a1.125 1.125 0 0 0 0 2.25m5.125 2.875a1.125 1.125 0 1 1-2.25 0a1.125 1.125 0 0 1 2.25 0M5.5 12.625a1.125 1.125 0 1 0 0-2.25a1.125 1.125 0 0 0 0 2.25" clip-rule="evenodd" /> <title>Resizable handle</title> </svg> </div> </Show> </ResizablePrimitive.Handle> ); };
import { cn } from "@/libs/cn"; import type { DynamicProps, HandleProps, RootProps } from "@corvu/resizable"; import ResizablePrimitive from "@corvu/resizable"; import type { ValidComponent, VoidProps } from "solid-js"; import { Show, splitProps } from "solid-js"; export const ResizablePanel = ResizablePrimitive.Panel; type resizableProps<T extends ValidComponent = "div"> = RootProps<T> & { class?: string; }; export const Resizable = <T extends ValidComponent = "div">( props: DynamicProps<T, resizableProps<T>>, ) => { const [local, rest] = splitProps(props as resizableProps, ["class"]); return <ResizablePrimitive class={cn("size-full", local.class)} {...rest} />; }; type resizableHandleProps<T extends ValidComponent = "button"> = VoidProps< HandleProps<T> & { class?: string; withHandle?: boolean; } >; export const ResizableHandle = <T extends ValidComponent = "button">( props: DynamicProps<T, resizableHandleProps<T>>, ) => { const [local, rest] = splitProps(props as resizableHandleProps, [ "class", "withHandle", ]); return ( <ResizablePrimitive.Handle class={cn( "flex w-px items-center justify-center bg-border focus-visible:(outline-none ring-1.5 ring-ring ring-offset-1) data-[orientation=vertical]:(h-px w-full) transition-shadow", local.class, )} {...rest} > <Show when={local.withHandle}> <div class="z-10 flex h-4 w-3 items-center justify-center rounded-sm border bg-border"> <svg xmlns="http://www.w3.org/2000/svg" class="h-2.5 w-2.5" viewBox="0 0 15 15" > <path fill="currentColor" fill-rule="evenodd" d="M5.5 4.625a1.125 1.125 0 1 0 0-2.25a1.125 1.125 0 0 0 0 2.25m4 0a1.125 1.125 0 1 0 0-2.25a1.125 1.125 0 0 0 0 2.25M10.625 7.5a1.125 1.125 0 1 1-2.25 0a1.125 1.125 0 0 1 2.25 0M5.5 8.625a1.125 1.125 0 1 0 0-2.25a1.125 1.125 0 0 0 0 2.25m5.125 2.875a1.125 1.125 0 1 1-2.25 0a1.125 1.125 0 0 1 2.25 0M5.5 12.625a1.125 1.125 0 1 0 0-2.25a1.125 1.125 0 0 0 0 2.25" clip-rule="evenodd" /> <title>Resize handle</title> </svg> </div> </Show> </ResizablePrimitive.Handle> ); };
import { Resizable, ResizablePanel, ResizableHandle } from "@/components/ui/resizable";
<Resizable> <ResizablePanel>A</ResizablePanel> <ResizableHandle /> <ResizablePanel>B</ResizablePanel> </Resizable>
Use the orientation prop to set the orientation of the resizable panels.
orientation
import { Resizable, ResizableHandle, ResizablePanel, } from "@repo/tailwindcss/ui/resizable"; const ResizableVerticalDemo = () => { return ( <Resizable orientation="vertical" class="h-[200px] max-w-md rounded-lg border" > <ResizablePanel initialSize={0.3} minSize={0.2}> <div class="flex h-full items-center justify-center"> <span class="font-semibold">A</span> </div> </ResizablePanel> <ResizableHandle /> <ResizablePanel initialSize={0.7} minSize={0.2}> <div class="flex h-full items-center justify-center"> <span class="font-semibold">B</span> </div> </ResizablePanel> </Resizable> ); }; export default ResizableVerticalDemo;
You can set or hide the handle by using the withHandle prop on the ResizableHandle component.
withHandle
ResizableHandle
import { Resizable, ResizableHandle, ResizablePanel, } from "@repo/tailwindcss/ui/resizable"; const ResizableWithHandleDemo = () => { return ( <Resizable class="min-h-[200px] max-w-md rounded-lg border"> <ResizablePanel initialSize={0.3} minSize={0.2}> <div class="flex h-full items-center justify-center"> <span class="font-semibold">A</span> </div> </ResizablePanel> <ResizableHandle withHandle /> <ResizablePanel initialSize={0.7} minSize={0.2}> <div class="flex h-full items-center justify-center"> <span class="font-semibold">B</span> </div> </ResizablePanel> </Resizable> ); }; export default ResizableWithHandleDemo;