Tool Approval

Asks the user to allow or deny an agent tool call.

Run rm -rf dist?The command runs in this project.. Read only.
Open a pull request?fix/invoice-rounding into main. Makes changes.

Installation

pnpm dlx shadcn@latest add @paneui/tool-approval

Usage

Examples

Risk Levels

Controlled

Outcomes

Remembered

Arguments

Accessibility

The item is a role="group" labelled "Permission request for {tool}". The risk is read out after the description, the arguments toggle sets aria-expanded, and the result line is a role="status" so the outcome is announced.

Layout

Below a 384px container width (512px with Always allow) the buttons wrap under the text. The result line hides the tool identifier at the same width.

Forgetting a remembered approval

Revoke clears the rememberKey entry, but a controlled parent that resets decision from "always" to null doesn't: the item would find the saved permission again on its next mount. Call forgetToolApproval(rememberKey) (or localStorage.removeItem(rememberKey)) alongside the reset.

Motion

Answering, undoing and showing the arguments animate the height on a spring while the contents cross-fade. A permission found under rememberKey on mount resolves without animating. Under reduced motion the height changes at once and only the opacity fades.

API Reference

ToolApproval

Permission request that collapses into a result line. Also accepts every prop of div.

tool*
string
Tool identifier, e.g. github.create_pull_request.
title= "Allow this tool to run?"
ReactNode
Question while pending. Inline <code> is styled.
description
ReactNode
One line under the title while pending. Defaults to tool in mono.
resultTitle
ReactNode
Text of the result line. Defaults to a string title without its question mark, or tool when title is the default.
icon
ReactNode
Icon in the tile. Defaults to a shield, or a warning sign for risk="high".
args
unknown
Arguments preview behind a toggle. Objects are pretty-printed as JSON; strings are shown as-is.
argsLanguage= "bash"
CodeLanguage
Highlight grammar for a string args.
risk= "medium"
"low" | "medium" | "high"
Sets the tile tone and the risk announced to screen readers.
decision
"once" | "always" | "deny" | null
Controlled decision; null is pending. Approve sets "once".
defaultDecision= null
"once" | "always" | "deny" | null
Initial decision when uncontrolled; revocable={false} then hides Undo.
onDecisionChange
(decision: "once" | "always" | "deny" | null) => void
Called on Approve, Always allow, Deny, Undo and when a remembered permission is found.
status
"running" | "done" | "failed"
Outcome of an approved call on the result line. Without it the line reads Approved or Always allowed.
allowAlways= rememberKey != null
boolean
Show Always allow between Deny and Approve.
rememberKey
string
localStorage key that remembers Always allow across sessions (stored as localStorage[rememberKey] = "always"), so the item mounts approved next time. Only Revoke clears it; a controlled parent resetting decision from "always" to null leaves it saved, so call forgetToolApproval(rememberKey) too.
revocable= true
boolean
Show Undo (after Approve / Deny) or Revoke (after Always allow) on the result line until a status arrives. Only Revoke clears rememberKey.
defaultArgsOpen= false
boolean
Show the arguments while pending, on mount and whenever the decision returns to null.
PropTypeDefaultDescription
tool*string—Tool identifier, e.g. github.create_pull_request.
titleReactNode"Allow this tool to run?"Question while pending. Inline <code> is styled.
descriptionReactNode—One line under the title while pending. Defaults to tool in mono.
resultTitleReactNode—Text of the result line. Defaults to a string title without its question mark, or tool when title is the default.
iconReactNode—Icon in the tile. Defaults to a shield, or a warning sign for risk="high".
argsunknown—Arguments preview behind a toggle. Objects are pretty-printed as JSON; strings are shown as-is.
argsLanguageCodeLanguage"bash"Highlight grammar for a string args.
risk"low" | "medium" | "high""medium"Sets the tile tone and the risk announced to screen readers.
decision"once" | "always" | "deny" | null—Controlled decision; null is pending. Approve sets "once".
defaultDecision"once" | "always" | "deny" | nullnullInitial decision when uncontrolled; revocable={false} then hides Undo.
onDecisionChange(decision: "once" | "always" | "deny" | null) => void—Called on Approve, Always allow, Deny, Undo and when a remembered permission is found.
status"running" | "done" | "failed"—Outcome of an approved call on the result line. Without it the line reads Approved or Always allowed.
allowAlwaysbooleanrememberKey != nullShow Always allow between Deny and Approve.
rememberKeystring—localStorage key that remembers Always allow across sessions (stored as localStorage[rememberKey] = "always"), so the item mounts approved next time. Only Revoke clears it; a controlled parent resetting decision from "always" to null leaves it saved, so call forgetToolApproval(rememberKey) too.
revocablebooleantrueShow Undo (after Approve / Deny) or Revoke (after Always allow) on the result line until a status arrives. Only Revoke clears rememberKey.
defaultArgsOpenbooleanfalseShow the arguments while pending, on mount and whenever the decision returns to null.
data-decision
pending, once, always or deny.
data-status
running, done or failed once approved and reported.
Data attributeDescription
data-decisionpending, once, always or deny.
data-statusrunning, done or failed once approved and reported.

forgetToolApproval

forgetToolApproval(rememberKey) removes a remembered Always allow (the same as localStorage.removeItem(rememberKey)). Call it when you reset a controlled decision to null; it doesn't change what a mounted item shows. A no-op on the server or with an undefined key.

rememberKey*
string | undefined
The rememberKey passed to the item.
PropTypeDefaultDescription
rememberKey*string | undefined—The rememberKey passed to the item.