Sidebar Drop Zones
The two renderers behind a zone definition: a full-height strip pinned to an edge of the panel, and an inline strip that opens in the scroll flow.
Installation
npx shadcn@latest add miskibin/chat-components/sidebar-drop-zonesAlso installs sidebar-dnd.
Usage
"use client"
import {
SidebarDropZone,
useSidebarDnd,
} from "@/components/ui/chat-sidebar"
export function ArchiveZone() {
const { activeId } = useSidebarDnd()
return (
<SidebarDropZone
id="archive-zone"
label="Drop here to archive"
icon={<Archive className="size-3.5" />}
tone="muted"
visible={!!activeId}
/>
)
}Examples
Edge zones without lifting a finger
Declare zones with an edge and let ChatSidebar mount and unmount them around the drag.
<ChatSidebarDnd
zones={[
pinDropZone(),
trashDropZone({ label: "Move to trash" }),
]}
onDrop={handleDrop}
>
<ChatSidebar collapsed={collapsed} onCollapsedChange={setCollapsed} edgeZones>
…
</ChatSidebar>
</ChatSidebarDnd>Restyle a zone
tone covers the three standard treatments; surfaceClassName reaches the dashed surface itself for anything else.
<SidebarDropZone
id="archive-zone"
label="Archive"
tone="muted"
visible={!!activeId}
surfaceClassName="rounded-full border-solid py-2 text-[11px] uppercase tracking-wide"
/>API reference
SidebarDropZone (inline)
id*string- Must match the
idof a zone declared on the provider, or the drop resolves askind: "custom". visible*boolean- Collapses to zero height when false. Drive it from useSidebarDnd().activeId.
label*React.ReactNode- Zone text.
iconReact.ReactNode- Leading icon.
tone"accent" | "danger" | "muted" = "accent"- Color treatment, including drag-over.
className / surfaceClassNamestring- Merged onto the wrapper, and onto the dashed surface.
SidebarEdgeDropZone
edge"top" | "bottom" = "top"- Which edge of the sidebar panel it anchors to.
id / label / icon / tonesame as above- Mount it only while a drag is active — it animates itself in.
ChatSidebar edgeZonesdoes this for you.
Helper
dropZoneProps(zone){ id, label, icon, tone }- Turns a zone definition into the props both components take.
Data slots
Every part below is addressable from a parent, so you can restyle internals without forking the component.
sidebar-drop-zonesidebar-edge-drop-zone