Installation
Complete project setup with react/base, then install these components:
pnpm exec frontfriend download item button icon message bubble -f react --primitive base The example never runs a command. Each request accepts one decision; Reset creates another request. Keep the request ID when you connect the decision to a tool approval response. Do not run the tool before approval.
Usage
Complete example
import { Message, MessageContent } from "@/components/ui/message";
import { Bubble, BubbleContent } from "@/components/ui/bubble";
import {
Item,
ItemMedia,
ItemContent,
ItemTitle,
ItemDescription,
ItemActions,
} from "@/components/ui/item";
import { Icon } from "@/components/ui/icon";
import { Button } from "@/components/ui/button";
import * as React from "react";
export default function AiConfirmationExample() {
const [decision, setDecision] = React.useState<
"pending" | "approved" | "denied"
>("pending");
const resultRef = React.useRef<HTMLParagraphElement>(null);
React.useEffect(() => {
if (decision !== "pending") resultRef.current?.focus();
}, [decision]);
function decide(value: "approved" | "denied") {
setDecision(value);
}
return (
<div
style={{
width: "100%",
maxWidth: 560,
minWidth: 0,
marginInline: "auto",
display: "flex",
flexDirection: "column",
gap: 16,
paddingBlock: 16,
fontSize: "var(--text-sm)",
lineHeight: 1.5,
}}
>
<Message align="end">
<MessageContent>
<Bubble align="end" variant="muted">
<BubbleContent>
Run the build before I ship this change.
</BubbleContent>
</Bubble>
</MessageContent>
</Message>
{decision === "pending" && (
<Item variant="outline" size="sm">
<ItemMedia variant="icon">
<Icon name="Terminal" />
</ItemMedia>
<ItemContent>
<ItemTitle>Run {"pnpm build"}?</ItemTitle>
<ItemDescription>The command runs in this project.</ItemDescription>
</ItemContent>
<ItemActions>
<Button
size="sm"
variant="outline"
onClick={() => decide("denied")}
>
Deny
</Button>
<Button size="sm" onClick={() => decide("approved")}>
Approve
</Button>
</ItemActions>
</Item>
)}
{decision !== "pending" && (
<Message>
<MessageContent>
<p ref={resultRef} tabIndex={-1}>
{decision === "approved"
? `Build approved. Ready to run ${"pnpm build"}.`
: "Build cancelled. No command was run."}
</p>
</MessageContent>
</Message>
)}
<div>
<Button
size="sm"
variant="ghost"
onClick={() => setDecision("pending")}
>
Reset
</Button>
</div>
</div>
);
} Components and API
This composition has no separate component API. Use the APIs for its installed components.
| Component | Target reference |
|---|---|
item | Base UI API |
button | Base UI API |
icon | Base UI API |
message | Base UI API |
bubble | Base UI API |