Back to Copilotkit

Open, close, and feedback

showcase/shell-docs/src/content/docs/prebuilt-components/chat-controls.mdx

1.60.13.6 KB
Original Source

Two common controls for the prebuilt chat are opening it from your own UI and capturing thumbs-up / thumbs-down feedback on assistant messages.

Programmatically open or close the chat

The modal/open state for <CopilotPopup> and <CopilotSidebar> lives in the chat configuration context. Read it with useCopilotChatConfiguration() and call setModalOpen(true | false) from anywhere inside the provider:

tsx
import { useCopilotChatConfiguration } from "@copilotkit/react-core/v2";

function OpenChatButton() {
  const config = useCopilotChatConfiguration();

  // setModalOpen is only present when a provider in the tree owns modal state
  // (the prebuilt CopilotPopup / CopilotSidebar create it for you).
  if (!config?.setModalOpen) return null;

  return (
    <button onClick={() => config.setModalOpen(true)}>
      Ask the assistant
    </button>
  );
}

To toggle, read config.isModalOpen and flip it:

tsx
<button onClick={() => config.setModalOpen(!config.isModalOpen)}>
  {config.isModalOpen ? "Close chat" : "Open chat"}
</button>
<Callout type="info"> `setModalOpen` / `isModalOpen` are only defined when a provider in the tree owns modal state. The prebuilt `<CopilotPopup>` and `<CopilotSidebar>` create it automatically. If you compose chat yourself, wrap the relevant subtree in `<CopilotChatConfigurationProvider isModalDefaultOpen={false}>` so the modal state exists. See the [`useCopilotChatConfiguration` reference](/reference/hooks/useCopilotChatConfiguration#modal-state-management). </Callout>

You can also set the initial open state declaratively. The prebuilt surfaces accept a defaultOpen prop:

tsx
<CopilotSidebar defaultOpen />

Capture message feedback (thumbs up / down)

The assistant-message toolbar can show thumbs-up and thumbs-down buttons. In v2 you opt in by passing onThumbsUp / onThumbsDown to the assistant message slot. The buttons only render when a handler is provided: slot**. The buttons only render when a handler is provided:

tsx
import { CopilotChat } from "@copilotkit/react-core/v2";

<CopilotChat
  messageView={{
    assistantMessage: {
      onThumbsUp: (message) => {
        analytics.track("feedback", { messageId: message.id, value: "up" });
      },
      onThumbsDown: (message) => {
        analytics.track("feedback", { messageId: message.id, value: "down" });
      },
    },
  }}
/>;

Each handler receives the assistant message, so you can record the feedback against the specific response (message.id). The same messageView slot works on <CopilotPopup> and <CopilotSidebar> since they wrap <CopilotChat>.

The button labels come from the chat labels (assistantMessageToolbarThumbsUpLabel defaults to "Good response", assistantMessageToolbarThumbsDownLabel to "Bad response"); override them via chat labels.

<Callout type="info"> Building a fully custom message component instead of using the slot? The underlying [`CopilotChatAssistantMessage`](/reference/components/CopilotChatAssistantMessage) exposes the same `onThumbsUp` / `onThumbsDown` props directly. </Callout>