PixelDosa UI

Response Feedback

Thumbs with a reason that goes somewhere, and a confirmation that says where.

The client ignores your 30-second config and aborts every request after 5 seconds. Passconfig.requestTimeoutinto the abort timer.

Was this answer useful?

Installation

bash
npx shadcn@latest add @pixeldosa/response-feedback

Requires `cn` at `@/lib/utils`. Route `onSubmit` somewhere a person actually reads.

Usage

"use client";

import { ResponseFeedback } from "@/components/ui/response-feedback";

<ResponseFeedback
  destination="the team that trains this assistant"
  reasons={[
    { id: "wrong", label: "Something is wrong" },
    { id: "source", label: "Wrong or missing source" },
  ]}
  onSubmit={(feedback) => report(feedback)}
/>

Why it exists

A bare thumbs-down tells a team that something was wrong and nothing about what. Asking for the reason costs the user two seconds and turns a shrug into something a team can act on.

Features

  • A thumbs up sends on its own. Praise shouldn't cost a form. askOnUp changes that when you want it.
  • Reasons are multi-select, in your users' words, because an answer is usually wrong in more than one way.
  • The comment is optional, and an empty one is never sent as feedback.
  • The confirmation names the destination. "Thanks, that goes to the team that trains this assistant."
  • No double submits. The controls are replaced by the confirmation.

Variants

Ready

Was this answer useful?

Already sent

Thanks, that goes to the team that trains this assistant.

Props

PropTypeNotes
onSubmit(submission) => voidRequired. { verdict, reasonIds, comment? }.
reasons{ id, label }[]Yours. A default set ships.
askOnUpbooleanAsk for reasons after a thumbs up too. Defaults to false.
destinationstringWhere the feedback goes, named in the confirmation.
submittedbooleanStart in the confirmed state.
labelstringDefaults to "Was this answer useful?".

Accessibility

  • The thumbs are a labelled group of toggle buttons with aria-pressed.
  • Reasons are real checkboxes inside a fieldset with a legend; the chips are their labels, so the whole chip is a hit target.
  • The comment has a visible label.

When not to use

  • As the only way to report harm. Anything unsafe needs a route a person reads, with a way to follow up.
  • As a rating that changes the answer. If a thumbs-down should trigger a retry, say so and use Response Versions.
  • For support. A ticket has a conversation; this doesn't.

why it's built this way

Engineering Notes

The asymmetry between up and down is the design: a thumbs up submits immediately and a thumbs down opens the reason panel, because the useful signal is concentrated in what went wrong and a form after praise costs goodwill for data nobody reads. Reasons are multi-select rather than a single choice, since an answer is usually wrong in more than one way, and they arrive as ids so the caller can route and aggregate them without parsing labels. The comment stays optional and is trimmed to undefined when empty, so a submission never carries a whitespace string that looks like feedback in a dashboard. After sending, the component collapses to a single sentence naming the destination instead of leaving the controls in place, which prevents the double-submit that turns one opinion into three.

how it moves, and when it doesn't

Motion Notes

Nothing moves except the confirmation, which fades in once over `--pd-duration-base`. The reason panel appears without a slide or a height animation: it is the user's turn, and an animating panel under a cursor that is already moving toward a chip costs a mis-click. Under `prefers-reduced-motion` the fade is dropped.