Refined UI

An opinionated, customizable superset of shadcn/ui

AgentsPrimitivesSkillsSkins
Guides
  • Overview
  • Get started
  • Shadcn compatibility
  • Architecture
  • Agent surface
Primitives
  • Accordion
  • Alert
  • Alert dialog
  • Aspect ratio
  • Autocomplete
  • Avatar
  • Badge
  • Button
  • Button group
  • Calendar
  • Card
  • Checkbox
  • Checkbox Group
  • Code
  • Code Diff
  • Collapsible
  • Color Picker
  • Combobox
  • Command
  • Date Picker
  • Dialog
  • Drawer
  • Empty
  • Field
  • Form
  • Gradient Editor
  • Hover card
  • Input
  • Input group
  • Input OTP
  • Item
  • Kbd
  • Markdown
  • Menu
  • Menubar
  • Meter
  • Native select
  • Navigation menu
  • Number Field
  • Pagination
  • Popover
  • Progress
  • Radio group
  • Resizable
  • Scroll area
  • Select
  • Sidebar
  • Skeleton
  • Slider
  • Spinner
  • Switch
  • Table
  • Table of contents
  • Tabs
  • Textarea
  • Toast
  • Toggle
  • Toolbar
  • Tooltip
  • Tree
  • Trigger Menu
  • Typography
Hooks
  • Use Chat Message
  • Use Chat Input
  • Use User Ask
  • Use Audio Recorder
  • Use Environment Variables
  • Use Copy To Clipboard
  • Use Tool Call
  • Use Sidebar Resize
Utils
  • cn
  • Skin
  • Contracts
  • Serialize
Extensions
  • Control Effects
  • View Transition
  • Send Aurora
  1. Primitives
  2. Resizable
Primitives

Resizable

Accessible resizable panel groups and split layouts with keyboard support.

Composition

The preferred shape for composing the installed primitive from its exported parts.

Parts

Exported compound parts from the installed source.

ResizablePanelGroup
├── ResizablePanel
└── ResizableHandle

The refined source installs this primitive from src/registry/sources/refined/ui/resizable.tsx. Install it on its own with the command above, or inspect the source below.

Registry command
npx shadcn@latest add http://127.0.0.1:3000/r/refined/resizable.json
See registry manifest

Raw code

Primary installed primitive source

Resizable slot
src/registry/sources/refined/ui/resizable.tsx
"use client";
​
import { createContext, useContext } from "react";
import { Group, Panel, Separator } from "react-resizable-panels";
import type { ResizableHandleProps, ResizablePanelGroupProps, ResizablePanelProps } from "@/components/refined-ui/contracts";
import { cn } from "@/components/refined-ui/lib/cn";
import { skinSlot } from "@/components/refined-ui/skin";
​
// Refined skin slot, 100% react-resizable-panels v4 (Group/Panel/Separator): drag-to-resize on Refined UI tokens.
// Group = framed --radius-panel surface (lib forces overflow:hidden, clips flush); Panel className lands on lib's inner scroll box; Handle styled off lib's own data-separator state machine, no JS state of ours.
// Orientation flows via context so Handle draws right axis (horizontal group → vertical dividers, vice versa).
​
type Orientation = "horizontal" | "vertical";
const OrientationContext = createContext<Orientation>("horizontal");
​
export function ResizablePanelGroup({ className, orientation = "horizontal", children, ...props }: ResizablePanelGroupProps) {
return (
<OrientationContext.Provider value={orientation}>
<Group
data-ui="agent"
data-slot="resizable-panel-group"
orientation={orientation}
className={cn(
"flex h-full w-full rounded-[var(--radius-panel)] border border-border bg-card text-card-foreground shadow-sm",
skinSlot("resizable-panel-group", { orientation }),
className,
)}
{...props}
>
{children}
</Group>
</OrientationContext.Provider>
);
}
​
export function ResizablePanel({ className, ...props }: ResizablePanelProps) {
return <Panel data-ui="agent" data-slot="resizable-panel" className={cn(skinSlot("resizable-panel", {}), className)} {...props} />;
}
​
export function ResizableHandle({ className, withHandle, children, ...props }: ResizableHandleProps) {
const orientation = useContext(OrientationContext);
// A horizontal group stacks panels left↔right, so the separator between them is a vertical hairline.
const isVerticalDivider = orientation === "horizontal";
return (
<Separator
data-ui="agent"
data-slot="resizable-handle"
className={cn(
"relative flex shrink-0 items-center justify-center bg-border outline-none transition-colors duration-[var(--duration-fast)] ease-[var(--ease-standard)]",
isVerticalDivider ? "w-px" : "h-px",
"data-[separator=hover]:bg-foreground/25 data-[separator=active]:bg-foreground/40",
"data-[separator=focus]:bg-foreground/25 data-[separator=focus]:ring-2 data-[separator=focus]:ring-foreground/20",
"data-[separator=disabled]:opacity-50",
skinSlot("resizable-handle", { orientation }),
className,
)}
{...props}
>
{withHandle ? (
<span
data-ui="agent"
data-slot="resizable-handle-grip"
className={cn(
"z-10 flex items-center justify-center rounded-[var(--radius-control)] border border-border bg-card text-muted-foreground shadow-sm",
isVerticalDivider ? "h-5 w-3.5" : "h-3.5 w-5",
skinSlot("resizable-handle-grip", {}),
)}
>
<GripIcon className={isVerticalDivider ? undefined : "rotate-90"} />
</span>
) : null}
{children}
</Separator>
);
}
​
function GripIcon({ className }: { className?: string }) {
return (
<svg viewBox="0 0 4 16" width="4" height="16" fill="currentColor" aria-hidden="true" className={className}>
<circle cx="2" cy="3" r="1" />
<circle cx="2" cy="8" r="1" />
<circle cx="2" cy="13" r="1" />
</svg>
);
}
​

On this page

  • Preview
  • Composition
  • Installation
  • Source
SidebarDrag past the edge to collapse
Editor
ConsoleDrag the handle above to resize