WebberUI

Slide Over Panel

A non-modal narrow floating panel that can be dragged and magnetically snapped to either side, and flicked away to collapse into an edge handle — springs tracking the pointer throughout.

Loading preview…
npx shadcn@latest add https://webberui.com/r/slide-over-panel.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
<SlideOverPanel />

Installation

npx shadcn@latest add https://webberui.com/r/slide-over-panel.json

Or, once registries are configured in components.json, install it as @webberui/slide-over-panel.

Usage

The panel is absolute-positioned, and with anchor="container" (the default) it hugs the nearest positioned ancestor, so make sure the outer container is position: relative:

import { SlideOverPanel } from "@/components/ui/slide-over-panel";

<div className="relative h-[480px] overflow-hidden">
  {/* your main content */}
  <SlideOverPanel title="Recent activity">
    <p>Panel content…</p>
  </SlideOverPanel>
</div>

To float the panel over the whole viewport, use anchor="viewport" instead (which uses fixed positioning and needs no positioned ancestor).

Props

PropTypeDefaultDescription
childrenReact.ReactNodePanel content
titleReact.ReactNodePanel heading, which also serves as the source of the accessible label
side"left" | "right"Controlled snap side
defaultSide"left" | "right""right"Uncontrolled default snap side
onSideChange(side) => voidSnap-side change callback
collapsedbooleanControlled collapsed state
defaultCollapsedbooleanfalseUncontrolled default collapsed state
onCollapsedChange(collapsed) => voidCollapsed-state change callback
panelWidthnumber300Width of the panel body (px, excluding the handle)
anchor"container" | "viewport""container"Positioning basis
labelstringAccessible label; falls back to title when not provided
classNamestringAppended to the panel body's className

How it works

  • Magnetic snapping: after a drop, whichever half of the container the panel's center lands in is the side it springs to and expands on.
  • Flick to collapse: if the horizontal velocity on release exceeds the threshold (600 px/s), it collapses into an edge handle in the direction of the flick; pulling the handle back out expands it again.
  • Tracks the pointer throughout: dragging, spring back, snapping, and collapsing all run on the same spring set, so it settles crisply rather than stiffly.
  • Two controlled axes: both side and collapsed support controlled and uncontrolled modes, and each can be controlled independently.

Accessibility

  • The panel is a role="region" using title or label as its aria-label.
  • The edge handle is a native button: Enter / Space toggle collapse, and / snap it to the left or right side and expand it, filling the gap where dragging cannot be done from the keyboard.
  • The handle reflects the expanded state through aria-expanded; when collapsed, the panel body carries aria-hidden and interaction is disabled.
  • The panel is non-modal: it does not lock scrolling and does not intercept interaction with the content beneath (pointer-events only apply to the panel itself).
  • When the user has "reduce motion" enabled at the system level, dragging is disabled and the spring offsets are replaced with instant positioning.

On this page