WebberUI

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.

Loading preview…
npx shadcn@latest add https://webberui.com/r/docked-inspector-rail.json

Playground

Tune the props live — the code snippet updates as you go, so you can dial in the look you want before copying it.

300
220
440
<DockedInspectorRail />

Installation

npx shadcn@latest add https://webberui.com/r/docked-inspector-rail.json

Or, 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

ComponentDescription
DockedInspectorRailOutermost container; provides the state and lays out the main content and panel with flex
DockedInspectorMainThe main content area, which reflows as the panel width changes
DockedInspectorThe right-docked panel; animates its width to push, and its left edge can be dragged
InspectorSectionA collapsible section inside the panel
InspectorTriggerThe trigger that toggles the panel open
InspectorCloseA button that closes the panel (the title header already includes one)

Props

DockedInspectorRail

PropTypeDefaultDescription
openbooleanExpanded state in controlled mode
onOpenChange(open: boolean) => voidExpanded-state change callback
defaultOpenbooleanfalseInitial expanded state in uncontrolled mode
defaultWidthnumber300Initial panel width (px)
minWidthnumber220Smallest width dragging can reach (px)
maxWidthnumber440Largest width dragging can reach (px)
onWidthChange(width: number) => voidWidth change callback
classNamestringAppended to the container; set the height here

DockedInspector

PropTypeDefaultDescription
titleReact.ReactNodeWhen provided, renders a header with a close button
classNamestringAppended to the panel container

InspectorSection

PropTypeDefaultDescription
titleReact.ReactNodeSection title
iconReact.ReactNodeOptional icon to the left of the title
defaultOpenbooleantrueWhether it starts expanded
classNamestringAppended to the section container

How it works

  • Push, don't cover: the panel expands with a width animation and the main content reflows with it thanks to min-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 maxWidth and 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: InspectorSection expands and collapses with a height animation, and the arrow rotates in step.
  • Set an explicit height in DockedInspectorRail's className; when the panel content is long, the section area scrolls on its own.

Accessibility

  • The trigger carries aria-expanded and aria-controls pointing at the panel; focus returns to the trigger after it closes.
  • The panel is a non-modal complementary region: it does not lock background scrolling and does not steal focus; pressing Esc while 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 with Tab; arrow keys adjust the width and Home / End jump to the widest / narrowest.
  • When the user has "reduce motion" enabled at the system level, the width and collapse animations become instant changes.

On this page