Tool Approval
Asks the user to allow or deny an agent tool call.
Installation
pnpm dlx shadcn@latest add @paneui/tool-approvalUsage
Examples
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.
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
toolin mono. - resultTitle
- ReactNode
- Text of the result line. Defaults to a string
titlewithout its question mark, ortoolwhentitleis 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;
nullis 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
localStoragekey that remembers Always allow across sessions (stored aslocalStorage[rememberKey] = "always"), so the item mounts approved next time. Only Revoke clears it; a controlled parent resettingdecisionfrom"always"tonullleaves it saved, so callforgetToolApproval(rememberKey)too.- revocable= true
- boolean
- Show Undo (after Approve / Deny) or Revoke (after Always allow) on the result line until a
statusarrives. Only Revoke clearsrememberKey. - defaultArgsOpen= false
- boolean
- Show the arguments while pending, on mount and whenever the decision returns to
null.
| Prop | Type | Default | Description |
|---|---|---|---|
| tool* | string | — | Tool identifier, e.g. github.create_pull_request. |
| title | ReactNode | "Allow this tool to run?" | 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 | CodeLanguage | "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" | null | 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 | boolean | rememberKey != null | 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 | boolean | true | Show Undo (after Approve / Deny) or Revoke (after Always allow) on the result line until a status arrives. Only Revoke clears rememberKey. |
| defaultArgsOpen | boolean | false | Show the arguments while pending, on mount and whenever the decision returns to null. |
- data-decision
pending,once,alwaysordeny.- data-status
running,doneorfailedonce approved and reported.
| Data attribute | Description |
|---|---|
| data-decision | pending, once, always or deny. |
| data-status | running, 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
rememberKeypassed to the item.
| Prop | Type | Default | Description |
|---|---|---|---|
| rememberKey* | string | undefined | — | The rememberKey passed to the item. |