Meet Frontfriend.Your brand. Your rules. Your agents, connected.Explore what’s new

Confirmation

A confirmation request that presents a tool action and records a clear decision.

Interactive preview

The shared preview uses React Base. The source below uses Base UI. Each example runs with local data.

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.

ComponentTarget reference
item Base UI API
button Base UI API
icon Base UI API
message Base UI API
bubble Base UI API