Mischief

16 / Agent UI

Approval Card

The question an agent asks before it acts. Ordinary answers take one click; destructive ones have to be held.

Live previewSource

How many flavors should we launch with?

Installation

Copy the source into your project, or keep it behind a package.

Copy the component into your project and make it yours.

Usage

export function Confirm() {
  return (
    <ApprovalCard
      question="Delete 40 files the agent flagged as unused?"
      description="This cannot be undone from here."
      options={[
        { id: "delete", label: "Delete all 40", destructive: true },
        { id: "review", label: "Show me the list first" },
      ]}
      onApprove={handleApprove}
    />
  )
}

API

questionReactNodeWhat the agent is asking.
descriptionReactNodeSupporting detail below the question.
optionsApprovalOption[]Id, label, optional description, and a destructive flag.
answerId, defaultAnswerIdstringThe chosen option, controlled or uncontrolled.
holdDurationnumberHold time for destructive options in milliseconds. Defaults to 900, minimum 500.
freeformbooleanAdds a field for an answer you did not list.
onApprove(optionId: string) => voidRuns when an option is chosen.
onFreeformSubmit(value: string) => voidRuns when the freeform answer is sent.
onDismiss() => voidShows a dismiss control when supplied.

Accessibility

The card is a labelled region and the options are a group tied to the question. Ordinary options are ordinary buttons. A destructive option cannot be triggered by a stray tap: pointer input has to be held, and releasing early cancels. Keyboard and assistive technology users activate it once instead, since holding a key is not a fair requirement. The progress fill is decorative and is hidden under reduced motion.

Dependencies

lucide-react