showcase/shell-docs/src/content/docs/frontends/vue/guides/threads-and-drawer.mdx
CopilotChat covers the common conversation path. Use the thread APIs when you
want conversations that survive a reload, and CopilotThreadsDrawer when you
want a thread switcher beside the chat without wiring active-thread state
yourself.
Threads are persisted by CopilotKit Intelligence.
The drawer reads the platform's threads license feature and renders its
locked state instead of a thread list when that feature is unavailable.
Pass threadId to connect the chat to an existing conversation:
<script setup lang="ts">
import { ref } from "vue";
import { CopilotChat } from "@copilotkit/vue";
const selectedThreadId = ref<string | undefined>(undefined);
</script>
<template>
<CopilotChat agentId="support" :threadId="selectedThreadId" />
</template>
CopilotThreadsDrawer lists, switches, starts, archives and deletes threads.
Put the drawer and chat under the same CopilotChatConfigurationProvider so
selection and new-thread actions update the chat:
<script setup lang="ts">
import {
CopilotChat,
CopilotChatConfigurationProvider,
CopilotThreadsDrawer,
} from "@copilotkit/vue";
</script>
<template>
<CopilotChatConfigurationProvider agentId="support">
<div class="flex">
<CopilotThreadsDrawer :limit="20" />
<CopilotChat />
</div>
</CopilotChatConfigurationProvider>
</template>
| Prop | Type | Default | What it does |
|---|---|---|---|
agentId | string | the default agent | Which agent's threads the drawer lists. |
limit | number | the element's own default | How many threads to list. |
label | string | the element's own default | Accessible label for the drawer. |
recentLabel | string | "Recent Conversations" | Heading above the thread list. |
collapsible | boolean | true | Whether the drawer offers a collapse toggle. |
onThreadSelect | (threadId: string) => void | — | Called when a thread is selected. |
onNewThread | () => void | — | Called when a new thread is started. |
licenseUrl | string | — | Where the locked state sends a developer without Intelligence. |
onLicensed | () => void | — | Called when the locked state's action is taken. |
The drawer wraps a custom element, which needs a DOM. @copilotkit/vue imports
that element lazily on mount, so importing the component is safe under Nuxt and
other SSR setups; the drawer renders on the client.
useThreads exposes the same data and actions headlessly when you want your own
interface:
<script setup lang="ts">
import { useThreads } from "@copilotkit/vue";
const { threads, isLoading } = useThreads({ agentId: "support" });
</script>
<template>
<ul v-if="!isLoading">
<li v-for="thread in threads" :key="thread.id">{{ thread.name ?? "Untitled conversation" }}</li>
</ul>
</template>