Docked Inspector Rail
A contextual inspector panel docked to the right that expands by pushing, so the main content reflows with it; sections collapse and the width can be dragged.
npx shadcn@latest add https://webberui.com/r/docked-inspector-rail.jsonPlayground
Tune the props live — the code snippet updates as you go, so you can dial in the look you want before copying it.
<DockedInspectorRail />
Installation
npx shadcn@latest add https://webberui.com/r/docked-inspector-rail.jsonOr, once registries are configured in components.json, install it as @webberui/docked-inspector-rail.
Usage
DockedInspectorRail wraps the main content (DockedInspectorMain) and the docked panel (DockedInspector). The panel opens with a width animation, and because the main content is flex-1 it reflows alongside instead of being covered by an overlay. Put InspectorTrigger anywhere in the main content to toggle it open.
import {
DockedInspector,
DockedInspectorMain,
DockedInspectorRail,
InspectorSection,
InspectorTrigger,
} from "@/components/ui/docked-inspector-rail";
export function Example() {
return (
<DockedInspectorRail defaultOpen className="h-[420px]">
<DockedInspectorMain>
<InspectorTrigger>Toggle inspector</InspectorTrigger>
{/* main content */}
</DockedInspectorMain>
<DockedInspector title="Inspector">
<InspectorSection title="Appearance" defaultOpen>
{/* fields */}
</InspectorSection>
<InspectorSection title="Layout">{/* fields */}</InspectorSection>
</DockedInspector>
</DockedInspectorRail>
);
}Controlled mode: pass open and onOpenChange to own the expanded state yourself; onWidthChange lets you persist the width the user dragged to.
Anatomy
| Component | Description |
|---|---|
DockedInspectorRail | Outermost container; provides the state and lays out the main content and panel with flex |
DockedInspectorMain | The main content area, which reflows as the panel width changes |
DockedInspector | The right-docked panel; animates its width to push, and its left edge can be dragged |
InspectorSection | A collapsible section inside the panel |
InspectorTrigger | The trigger that toggles the panel open |
InspectorClose | A button that closes the panel (the title header already includes one) |
Props
DockedInspectorRail
| Prop | Type | Default | Description |
|---|---|---|---|
open | boolean | — | Expanded state in controlled mode |
onOpenChange | (open: boolean) => void | — | Expanded-state change callback |
defaultOpen | boolean | false | Initial expanded state in uncontrolled mode |
defaultWidth | number | 300 | Initial panel width (px) |
minWidth | number | 220 | Smallest width dragging can reach (px) |
maxWidth | number | 440 | Largest width dragging can reach (px) |
onWidthChange | (width: number) => void | — | Width change callback |
className | string | — | Appended to the container; set the height here |
DockedInspector
| Prop | Type | Default | Description |
|---|---|---|---|
title | React.ReactNode | — | When provided, renders a header with a close button |
className | string | — | Appended to the panel container |
InspectorSection
| Prop | Type | Default | Description |
|---|---|---|---|
title | React.ReactNode | — | Section title |
icon | React.ReactNode | — | Optional icon to the left of the title |
defaultOpen | boolean | true | Whether it starts expanded |
className | string | — | Appended to the section container |
How it works
- Push, don't cover: the panel expands with a
widthanimation and the main content reflows with it thanks tomin-w-0 flex-1— there is no overlay at any point. - Drag to resize: the handle on the panel's left edge accepts pointer drags; the upper bound is clamped by both
maxWidthand the container's available width, so a minimum width is always reserved for the main content. While dragging, the animation tracks the pointer instantly and the global cursor and text selection are locked. - Section collapsing:
InspectorSectionexpands and collapses with a height animation, and the arrow rotates in step. - Set an explicit height in
DockedInspectorRail'sclassName; when the panel content is long, the section area scrolls on its own.
Accessibility
- The trigger carries
aria-expandedandaria-controlspointing at the panel; focus returns to the trigger after it closes. - The panel is a non-modal
complementaryregion: it does not lock background scrolling and does not steal focus; pressingEscwhile focus is inside the panel collapses it. - When collapsed, the panel content is
inert, which removes it from the Tab order and the accessibility tree. - The drag handle is a
role="separator"that can be focused withTab; arrow keys adjust the width andHome/Endjump to the widest / narrowest. - When the user has "reduce motion" enabled at the system level, the width and collapse animations become instant changes.
Tri-Pane Workspace Shell
A nav + list + detail master-detail application shell with built-in collapsing, an overlay mode, and a page-by-page responsive state machine, its transitions choreographed as a spring sequence.
Anchored Settings Shell
An anchored settings-page frame — scroll-spy navigation on the left, two-column settings sections on the right, an indicator that glides along with the scroll, and a save bar that springs in when there are unsaved changes.