useComponent

Register a React component as a frontend tool renderer in chat

Open your coding agent in your project's folder, or in an empty folder for a new app.This runs in a coding agent on your computer.

Overview

useComponent is a convenience hook built on top of useFrontendTool. It registers a tool and renders a React component in chat using the tool call parameters.

This is part of the v2 tool rendering hook set with useRenderTool, useDefaultRenderTool, and useRenderToolCall.

Use this when you want a visual component renderer without writing a full frontend tool config manually.

Signature

import { z } from "zod";
import type { ComponentType } from "react";
import { useComponent } from "@copilotkit/react-core/v2";

function useComponent<TSchema extends z.ZodTypeAny | undefined = undefined>(
  config: {
    name: string;
    description?: string;
    parameters?: TSchema;
    // When parameters is provided, props are inferred via z.infer.
    // When omitted, render accepts any props.
    render: ComponentType<InferRenderProps<TSchema>>;
    agentId?: string;
    followUp?: boolean;
  },
  deps?: ReadonlyArray<unknown>,
): void;

Parameters

  • config.name: tool name used by the agent to invoke this component tool.
  • config.description: optional extra description for model guidance.
  • config.parameters: optional Zod schema for the tool's parameters. When provided, render props are inferred from the schema. When omitted, the tool is advertised with an empty parameter schema ({ "type": "object", "properties": {} }), so the agent invokes it with no arguments.
  • config.render: React component rendered with the tool call's arguments as props. While the call streams, the props are the partially parsed JSON of the arguments, not a schema-parsed result, so fields can be missing (see Behavior). Accepts any props when parameters is omitted.
  • config.agentId: optional agent scope for the registration.
  • config.followUp: whether the agent should continue after rendering the component. Defaults to true; set it to false to stop after the tool call.
  • deps: optional dependency array for refreshing registration.

Behavior

  • Prepends a default instruction to the description: "Use this tool to display the "<name>" component in the chat...".
  • Calls useFrontendTool internally with a render function that spreads the tool parameters as component props.
  • Props arrive partial while the tool call streams. The component renders as soon as the agent starts the tool call, and again as each argument streams in. Until the call completes, any field can be missing. The props are the arguments the agent sent, not a parsed schema result, so schema defaults such as .default("c") are not filled in. The render type shows the complete parameters, so TypeScript does not warn you. Treat every prop as optional in the component and render a placeholder for missing fields.
  • Inherits useFrontendTool lifecycle behavior: duplicate-name override warning, tool removal on unmount, and renderer retention for chat history.
  • Tracks updates by config.name plus deps (include any changing captured values in deps).
  • deps comparison: compares plain data (strings, numbers, booleans, null, dates, and plain objects and arrays of those) by value, so an inline literal such as [{ status }] re-registers only when its contents change. A function never counts as changed, as before, so keep a changing callback in a ref. Class instances and other objects compare by identity, so a circular value such as the agent from useAgent is safe to pass. Adding or removing an entry counts as a change.

Usage

const weatherCardSchema = z.object({
  city: z.string().describe("City name"),
  unit: z.enum(["c", "f"]).default("c"),
});

type WeatherCardProps = z.infer<typeof weatherCardSchema>;

// Props are partial while the tool call streams, so read each field as optional.
function WeatherCard({ city, unit }: Partial<WeatherCardProps>) {
  return (
    <div className="rounded border p-3">
      <div className="text-sm text-zinc-500">Weather request</div>
      <div className="font-medium">
        {city ?? "…"} ({(unit ?? "c").toUpperCase()})
      </div>
    </div>
  );
}

function App() {
  useComponent(
    {
      name: "showWeatherCard",
      description: "Render a weather card in chat for the requested city.",
      parameters: weatherCardSchema,
      render: WeatherCard,
    },
    [],
  );

  return null;
}

Related