Overview
The useComponent hook is a convenience wrapper around useFrontendTool that makes it easy to register React components as tools that AI agents can render in chat conversations. It automatically builds the tool description and wiring for you.
Usage
import { useComponent } from "@copilotkit/react" ;
import { z } from "zod" ;
function WeatherCard ({ city , temperature } : { city : string ; temperature : number }) {
return (
< div className = "weather-card" >
< h3 > { city } </ h3 >
< p > { temperature } °C </ p >
</ div >
);
}
function MyComponent () {
useComponent ({
name: "showWeather" ,
parameters: z . object ({
city: z . string (),
temperature: z . number (),
}),
render: WeatherCard ,
});
return < div > ... </ div > ;
}
Type Signature
function useComponent < TSchema extends z . ZodTypeAny | undefined >(
config : {
name : string ;
description ?: string ;
parameters ?: TSchema ;
render : ComponentType < InferRenderProps < TSchema >>;
agentId ?: string ;
},
deps ?: ReadonlyArray < unknown >
) : void
Parameters
Component configuration object with the following properties: Unique identifier for the component tool. Optional additional description of what the component displays. This is appended to the auto-generated description. The auto-generated description is: Use this tool to display the "{name}" component in the chat.
This tool renders a visual UI component for the user.
description : "Displays product information including image, price, and availability"
Full description sent to AI: Use this tool to display the "showProductCard" component in the chat.
This tool renders a visual UI component for the user.
Displays product information including image, price, and availability
Zod schema defining the component’s props. When provided, the render component receives typed props inferred from the schema. When omitted, the component can accept any props. parameters : z . object ({
productId: z . string (),
name: z . string (),
price: z . number (),
inStock: z . boolean (),
})
React component to render. Props are automatically inferred from the parameters schema. render : ProductCard
// or inline
render : ({ name , price }) => (
< div >
< h3 > { name } </ h3 >
< p > $ { price } </ p >
</ div >
)
Constrain this component to a specific agent. If specified, only that agent can render this component. agentId : "shopping-agent"
Optional dependency array (like useEffect). When dependencies change, the component is re-registered. useComponent ( config , [ theme , locale ]);
Return Value
This hook does not return a value. The component is registered as a tool and automatically unregistered on unmount.
Examples
Basic Component
import { useComponent } from "@copilotkit/react" ;
import { z } from "zod" ;
function GreetingCard ({ message } : { message : string }) {
return (
< div className = "greeting-card" >
< p > { message } </ p >
</ div >
);
}
function App () {
useComponent ({
name: "showGreeting" ,
parameters: z . object ({
message: z . string (). describe ( "The greeting message to display" ),
}),
render: GreetingCard ,
});
return < div > App content </ div > ;
}
Product Card Component
import { useComponent } from "@copilotkit/react" ;
import { z } from "zod" ;
interface ProductCardProps {
name : string ;
price : number ;
image : string ;
inStock : boolean ;
}
function ProductCard ({ name , price , image , inStock } : ProductCardProps ) {
return (
< div className = "product-card" >
< img src = { image } alt = { name } />
< h3 > { name } </ h3 >
< p className = "price" > $ { price } </ p >
< span className = { `stock ${ inStock ? "in-stock" : "out-of-stock" } ` } >
{ inStock ? "In Stock" : "Out of Stock" }
</ span >
</ div >
);
}
function ProductCatalog () {
useComponent ({
name: "showProduct" ,
description: "Displays a product card with image, pricing, and availability" ,
parameters: z . object ({
name: z . string (),
price: z . number (),
image: z . string (). url (),
inStock: z . boolean (),
}),
render: ProductCard ,
});
return < div > Catalog content </ div > ;
}
Inline Component
import { useComponent } from "@copilotkit/react" ;
import { z } from "zod" ;
function Dashboard () {
useComponent ({
name: "showMetric" ,
description: "Display a key metric card" ,
parameters: z . object ({
label: z . string (),
value: z . number (),
unit: z . string (),
trend: z . enum ([ "up" , "down" , "stable" ]),
}),
render : ({ label , value , unit , trend }) => {
const trendIcon = {
up: "📈" ,
down: "📉" ,
stable: "➡️" ,
}[ trend ];
return (
< div className = "metric-card" >
< div className = "label" > { label } </ div >
< div className = "value" >
{ value } { unit }
</ div >
< div className = "trend" > { trendIcon } </ div >
</ div >
);
},
});
return < div > Dashboard content </ div > ;
}
Component Without Parameters
For simple components that don’t need parameters:
import { useComponent } from "@copilotkit/react" ;
function LoadingSpinner () {
return < div className = "spinner" > Loading... </ div > ;
}
function App () {
useComponent ({
name: "showLoading" ,
description: "Display a loading spinner" ,
render: LoadingSpinner ,
// No parameters needed
});
return < div > App content </ div > ;
}
Chart Component
import { useComponent } from "@copilotkit/react" ;
import { z } from "zod" ;
import { BarChart , Bar , XAxis , YAxis , CartesianGrid , Tooltip } from "recharts" ;
interface ChartData {
label : string ;
value : number ;
}
function Chart ({ data , title } : { data : ChartData []; title : string }) {
return (
< div className = "chart-container" >
< h3 > { title } </ h3 >
< BarChart width = { 400 } height = { 300 } data = { data } >
< CartesianGrid strokeDasharray = "3 3" />
< XAxis dataKey = "label" />
< YAxis />
< Tooltip />
< Bar dataKey = "value" fill = "#8884d8" />
</ BarChart >
</ div >
);
}
function Analytics () {
useComponent ({
name: "showChart" ,
description: "Display a bar chart with provided data" ,
parameters: z . object ({
data: z . array ( z . object ({
label: z . string (),
value: z . number (),
})),
title: z . string (),
}),
render: Chart ,
});
return < div > Analytics dashboard </ div > ;
}
Agent-Specific Component
import { useComponent } from "@copilotkit/react" ;
import { z } from "zod" ;
function ResearchPaperCard ({ title , authors , year , abstract } : any ) {
return (
< div className = "paper-card" >
< h3 > { title } </ h3 >
< p className = "authors" > { authors . join ( ", " ) } </ p >
< p className = "year" > { year } </ p >
< p className = "abstract" > { abstract } </ p >
</ div >
);
}
function ResearchAgent () {
useComponent ({
name: "showPaper" ,
description: "Display academic paper information" ,
parameters: z . object ({
title: z . string (),
authors: z . array ( z . string ()),
year: z . number (),
abstract: z . string (),
}),
render: ResearchPaperCard ,
agentId: "research-agent" , // Only research agent can use this
});
return < div > Research interface </ div > ;
}
List Component
import { useComponent } from "@copilotkit/react" ;
import { z } from "zod" ;
interface Task {
id : string ;
title : string ;
completed : boolean ;
priority : "low" | "medium" | "high" ;
}
function TaskList ({ tasks } : { tasks : Task [] }) {
return (
< div className = "task-list" >
< h3 > Tasks ( { tasks . length } ) </ h3 >
< ul >
{ tasks . map (( task ) => (
< li key = { task . id } className = { task . completed ? "completed" : "" } >
< span className = { `priority priority- ${ task . priority } ` } >
{ task . priority }
</ span >
< span className = "title" > { task . title } </ span >
{ task . completed && < span className = "checkmark" > ✓ </ span > }
</ li >
)) }
</ ul >
</ div >
);
}
function TaskManager () {
useComponent ({
name: "showTasks" ,
description: "Display a list of tasks with their status and priority" ,
parameters: z . object ({
tasks: z . array ( z . object ({
id: z . string (),
title: z . string (),
completed: z . boolean (),
priority: z . enum ([ "low" , "medium" , "high" ]),
})),
}),
render: TaskList ,
});
return < div > Task manager interface </ div > ;
}
Dynamic Component with Dependencies
import { useComponent } from "@copilotkit/react" ;
import { z } from "zod" ;
import { useTheme } from "./hooks/useTheme" ;
function Alert ({ message , type } : { message : string ; type : string }) {
const theme = useTheme ();
const colors = {
info: theme === "dark" ? "#3b82f6" : "#2563eb" ,
warning: theme === "dark" ? "#f59e0b" : "#d97706" ,
error: theme === "dark" ? "#ef4444" : "#dc2626" ,
};
return (
< div
className = "alert"
style = { { backgroundColor: colors [ type as keyof typeof colors ] } }
>
{ message }
</ div >
);
}
function App () {
const theme = useTheme ();
useComponent ({
name: "showAlert" ,
description: "Display an alert message" ,
parameters: z . object ({
message: z . string (),
type: z . enum ([ "info" , "warning" , "error" ]),
}),
render: Alert ,
}, [ theme ]); // Re-register when theme changes
return < div > App content </ div > ;
}
Behavior
Auto-Generated Description
The hook automatically generates a description for the tool:
Use this tool to display the "{name}" component in the chat.
This tool renders a visual UI component for the user.
If you provide an additional description, it is appended:
Use this tool to display the "{name}" component in the chat.
This tool renders a visual UI component for the user.
{your description}
Type Safety
When parameters is provided, your render component’s props are automatically typed:
// TypeScript knows the exact prop types
useComponent ({
parameters: z . object ({
name: z . string (),
age: z . number (),
}),
render : ({ name , age }) => {
// name: string, age: number
return < div > { name } is { age } years old </ div > ;
},
});
No Handler Required
Unlike useFrontendTool, useComponent doesn’t require a handler function. It’s purely for rendering UI components based on parameters the agent provides.
Feature useComponent useFrontendTool Handler ❌ No ✅ Yes Custom rendering ✅ Yes ✅ Yes (optional) Auto-description ✅ Yes ❌ Manual Purpose Display UI Execute logic + UI Simpler API ✅ Yes ❌ More config
Use useComponent when:
You only need to render UI, no backend logic
You want a simpler API for component rendering
The agent just needs to display information
Use useFrontendTool when:
You need to execute logic when the tool is called
You need access to the handler context
You want more control over the tool definition
Notes
useComponent is built on top of useFrontendTool. It’s a convenience wrapper that simplifies the common case of rendering components without handler logic.
If you’re passing an inline config object, wrap it in useMemo to avoid unnecessary re-registrations: const config = useMemo (() => ({
name: "myComponent" ,
parameters: z . object ({ ... }),
render: MyComponent ,
}), [ /* dependencies */ ]);
useComponent ( config );