Components/ApprovalCard

ApprovalCard

A questionnaire an agent walks through before it acts.

VerifiedSince 0.3.9

Usage

Multi-Question Walkthrough

One question at a time. A single choice advances after autoAdvanceDelay; a multiple choice waits for the send control.

Loading demo...

Best Practices

  • This is a questionnaire, not an authorization gate; for allowing or denying one tool call, use ToolConfirmation.
  • Persist on answer, not only on submit, so earlier answers survive a reader dismissing the card halfway.
  • Keep it to three to five questions; beyond that, use a form page.
  • For a non-English UI, override every label prop together to avoid mixed-language chrome.
  • When the card can be remounted (as in a streaming transcript), hold the answers, index, and sent in the host.

API Reference

Props

PropTypeDefaultDescription
questionsApprovalQuestion[]—The questions. Required.
modelValueRecord<string, ApprovalAnswer>—Answer map keyed by question.id; omit to let the card own it.
indexnumber—The visible question, for v-model:index; omit to let the card own it.
sentboolean—Whether the answers were submitted, for v-model:sent.
openboolean—For v-model:open; false collapses the card to a reopen button.
autoAdvancebooleantrueAdvances after a single-choice pick; off under reduced motion.
autoAdvanceDelaynumber480Delay before the advance, in ms.
dismissiblebooleantrueRenders the dismiss control.
ariaLabelstring'Approval questions'Accessible name of the whole card.
sendLabelstring'Send answers'Accessible name of the send control on the last question.
nextQuestionLabelstring'Next question'Accessible name of the send control on other questions.
prevLabel / nextLabelstring'Previous' / 'Next'Accessible names of the pager arrows.
dismissLabelstring'Dismiss'Accessible name of the dismiss control.
reopenLabelstring'Open approval'Text of the collapsed button.
sentLabelstring'Answers sent'Confirmation text.
startOverLabelstring'Start over'Text of the restart control.
customPlaceholderstring'Type something…'Placeholder of the free-text field; a question may override it.
customLabelstring'Custom answer'Accessible name of the free-text field.
pagerLabelFormatter(position: number) => stringn => `Go to question ${n}`Accessible name of each pager dot.
skippablebooleanfalseRenders a skip control; off by default, since a required questionnaire shouldn't offer a way out.
skipLabelstring'Skip'Text of the skip control.

Events

EventArgumentsDescription
update:modelValue(answers: Record<string, ApprovalAnswer>)Fires when the answer map changes.
update:index(index: number)Fires when the page changes.
update:sent(sent: boolean)Fires when the submitted state changes.
update:open(open: boolean)Fires on collapse or reopen.
answer(answer: ApprovalAnswer)Fires as each question is answered, for incremental saving.
submit(answers: ApprovalAnswer[])Fires on submit with the answered items in questions order.
skip({ questionId, index })Fires on a skip; nothing is recorded, so the host can tell declined from answered.
dismiss()Fires when the card is dismissed.
reopen()Fires when the card is reopened.

Slots

SlotScopeDescription
question{ question, index }Replaces the question prompt.
sent{ answers }Replaces the confirmation panel.
footer-extra—Inserted in the footer, before the send control.

Exposed Methods

MethodDescription
next() / prev() / goTo(index)Paging.
submit()Same as pressing send; does nothing without an answer.
reset()Clears answers, returns to the first question, leaves the submitted state, and reopens.

Types

ApprovalQuestion

FieldTypeDescription
idstringQuestion id, also the key in the answer map.
questionstringThe prompt.
type'radio' | 'check'Single or multiple choice; defaults to 'radio'.
optionsApprovalOption[]{ value, label } choices; answers key on value, so reordering is safe.
allowCustombooleanfalse drops the free-text row; defaults to true.
customPlaceholderstringOverrides customPlaceholder for this question.

ApprovalAnswer

FieldTypeDescription
questionIdstringThe id of the answered question.
valuesstring[]Selected option.values; at most one on a single-choice question.
customstringFree-text answer.

Overview

  • modelValue, index, sent, and open follow the prop when one is passed; otherwise the card owns them.
  • On a single-choice question, an option and free text exclude each other, and the later one clears the earlier; on multiple choice they coexist.
  • Send is enabled once there is a selection or non-empty free text: it submits on the last question and advances elsewhere. On the last question, auto-advance and skip also submit.
  • A filled dot means the question is answered, not that it was passed.
  • Dismissing swaps the card for a reopen button and keeps its state; only reset() or the restart control clears it.
  • Options are button elements with aria-pressed, grouped in a role="group" whose aria-labelledby points at the prompt.

Technologies

  • Adapted from Beautiful UI (© 2026 Shane Levine, MIT).
  • Source: packages/tuffex/packages/components/src/approval-card/.
查看源码
packages/tuffex/packages/components/src/approval-card/index.ts