---
title: Interactive Components
icon: "lucide/MousePointer"
description: Register interactive React components that users can click, type into, or manipulate in the chat — results flow back to the agent as tool results.
hideTOC: true
snippet_framework: langgraph-python
snippet_cell: hitl-in-chat
---

## What is this?

Interactive generative UI extends display components with user interaction. Your agent renders components that users can click, type into, or manipulate — and the results flow back to the agent as tool results.

This is how you build **human-in-the-loop** flows: the agent requests a decision, the user responds, and the agent continues with that response as input.

<InlineDemo integration="langgraph-python" demo="hitl-in-chat" />

## When should I use this?

Use interactive generative UI when you want to:

- Let users confirm or modify agent suggestions inline
- Build form-like interactions within the chat
- Create approval workflows where users can accept/reject agent actions
- Add interactive controls (sliders, toggles, selectors) to agent outputs

## How it works in code

The primitive is `useHumanInTheLoop`. Unlike `useComponent` (display-only) or `useFrontendTool` (handler-driven), `useHumanInTheLoop` exposes a `respond` callback to your render function. When the user clicks a button or submits a form, you call `respond(value)` — that value becomes the tool's result and the agent continues the turn.

```tsx title="page.tsx"
import { z } from "zod";
import { useHumanInTheLoop } from "@copilotkit/react-core/v2";

useHumanInTheLoop({
  name: "humanApprovedCommand",
  description: "Ask a human for approval to run a command.",
  parameters: z.object({
    command: z.string().describe("The command to run"),
  }),
  render: ({ args, respond, status }) => {
    if (status !== "executing") return null;

    return (
      <div>
        <pre>{args.command}</pre>
        <button onClick={() => respond?.("Command is APPROVED")}>Approve</button>
        <button onClick={() => respond?.("Command is DENIED")}>Deny</button>
      </div>
    );
  },
});
```

Statuses:

- `"inProgress"` — the LLM is still streaming arguments; don't render anything irreversible yet.
- `"executing"` — the agent is waiting for the user's response. Show your form / buttons.
- `"complete"` — the user has responded (or the call was cancelled). Collapse to a confirmation view.

## Working with the Built-in Agent

No backend wiring needed — the Built-in Agent sees the interactive tool in its tool list the same way it sees a regular frontend tool, and `respond(value)` feeds the result straight back into the next agent turn.

## Pattern: approval flow

The cell above demonstrates a command-approval flow:

1. The agent proposes a command (e.g. `rm -rf ./cache`)
2. The UI renders an **Approve / Deny** pair
3. `respond(...)` sends `"APPROVED"` or `"DENIED"` back
4. The agent reads the result and either executes or bails

## Related

- [Display Components](./display-only) — when you don't need user interaction, just rich rendering.
- [Frontend Tools](../../frontend-tools) — handler-driven tools (no UI, just logic).
- [Tool Rendering](../tool-rendering) — wrap a real backend tool in custom UI.
