showcase/shell-docs/src/content/snippets/shared/basics/copilot-threads-drawer.mdx
<CopilotThreadsDrawer> gives your app a ready-made conversation sidebar. Users can
list, switch, start, archive, and delete their threads, and you wire up
no active-thread state to make it work. Drop it next to your chat and it
connects automatically.
If your project was created from a CopilotKit CLI starter, the Drawer and its shared chat configuration are already included. Otherwise, use the setup below to add it to an existing CopilotKit application. This guide also covers Drawer customization and component options.
<Frame description="CopilotThreadsDrawer beside a CopilotChat. Selecting a thread replays its conversation with no active-thread wiring."> </Frame>Under the hood it's a thin React wrapper around the self-contained
copilotkit-threads-drawer web component, fed by useThreads
and your chat configuration.
Prefer to build your own thread UI? The same data and actions are available
headlessly through the useThreads hook (see
Headless Threads). Thread rename is one of those headless
actions: the prebuilt drawer's row menu covers archive/unarchive and delete, so
wire up rename with useThreads and your own UI if you need it.
Use the drawer when you want:
It requires the Enterprise Intelligence Platform (threads are stored and synced server-side). <SignupLink surface="docs_drawer">Get a free developer account</SignupLink> to set that up.
For multi-user applications, configure the Runtime to scope Rich Threads to the signed-in user.
<OpsPlatformCTA variant="inline" title="Threads run on the Enterprise Intelligence Platform" body="Get persistent threads and realtime sync on the free Developer tier." surface="docs_drawer" />
Place <CopilotThreadsDrawer> next to <CopilotChat> and wrap both in a
shared <CopilotChatConfigurationProvider>. If you are using a CLI-created
starter, this structure is already in place. That shared
configuration is what lets the Drawer drive the chat: with no callbacks,
selecting a row connects the chat to that thread and replays its history; the
"New Conversation" row resets the chat to a fresh welcome screen. The following
example shows the essential structure to add to an existing app or preserve
while customizing a starter.
import {
CopilotKitProvider,
CopilotChatConfigurationProvider,
CopilotChat,
CopilotThreadsDrawer,
} from "@copilotkit/react-core/v2";
import "@copilotkit/react-core/v2/styles.css";
export default function Page() {
return (
<CopilotKitProvider runtimeUrl="/api/copilotkit" publicLicenseKey="ck_pub_...">
<CopilotChatConfigurationProvider>
<div style={{ display: "flex", height: "100dvh" }}>
<CopilotThreadsDrawer />
<CopilotChat />
</div>
</CopilotChatConfigurationProvider>
</CopilotKitProvider>
);
}
That's the whole integration. A hand-rolled sidebar would have you track the
active threadId in your own state and pass selection/new-thread handlers
between the list and the chat; here the drawer and the
CopilotChatConfigurationProvider share that state, so there is none of that
wiring to write.
<CopilotThreadsDrawer> works with zero props. The optional ones:
| Prop | Description |
|---|---|
agentId | Agent whose threads to list (defaults to the chat configuration's agent). |
label | Accessible name for the drawer region and thread listbox. Defaults to "Threads". The redesigned header has no visible title. |
recentLabel | Section heading shown above the thread list. Defaults to "Recent Conversations". |
onThreadSelect | Escape hatch to take over thread selection yourself. |
onNewThread | Escape hatch to handle the "New Conversation" row yourself. |
renderRow | Render custom content per row (keeps the row chrome around it). |
limit | Page size for pagination. Shows a "Load more" control while more threads remain. Omit to load all at once. |
See the Threads Drawer reference for the full prop and type list.
The drawer renders in a shadow root with self-contained, theme-inheriting styles, so it looks correct in any app (including dark mode) with no config. Three bounded escape hatches pierce the boundary:
Slots: project children with a slot attribute (header, empty, footer, memories, launcher-icon):
<CopilotThreadsDrawer>
<span slot="header">My conversations</span>
</CopilotThreadsDrawer>
Per-row content: the renderRow prop projects custom content into each row while the element keeps selection, archived styling, and the per-row kebab menu (Archive/Delete).
CSS parts + variable tokens: restyle structural ::part()s or override --cpk-drawer-* tokens. The full list is in the reference.
Threads require CopilotKit Intelligence. Without a license key, the drawer shows a locked view in place of the list.
useThreads data layer