KQ-1328 · FEEDBACK/WIDGET

Feedback Widget

A feedback widget docked to the edge of a page: its tab opens a panel on glide with a row of drawn faces that wake as the pointer or focus reaches them, the mouth curving into its mood on snap and the pigment rising from grey, the chosen one landing on recoil; a press slid along the row scrubs through them. A choice glides open a text box whose question answers the mood and an optional screenshot that flashes the page and flies its frame into the panel on glide; Send folds the note in half about its crease on glide, tucks it into the tab on the exit ease, and the tab lands on recoil to say thanks. The faces are a radio group (arrows move and choose), Tab stays inside the panel, and Escape closes it and returns focus to the tab.

KQ-1328 · FEEDBACK/WIDGET
Fieldline/ Route plannerNew
3 stops · 42 km
  1. Coldbrook depot08:10
  2. Basinworks yard09:25
  3. Waylight market10:40

Drag stops to reorder. Times update as the route changes.

panel open · pick a face

Install

One command — the source lands in your repo. Or copy it from the Code tab.

$ pnpm dlx shadcn@latest add @kinetiq/feedback-widget

Props

open / defaultOpen
boolean
default — / false
The panel is open.
onOpenChange
(open: boolean) => void
default —
Fires from the tab, the close button, Escape or a finished send.
value / defaultValue
FeedbackDraft
default — / emptyFeedback
The draft: rating (1 to the number of faces, or null), message and screenshot.
onValueChange
(draft: FeedbackDraft) => void
default —
Fires from the face, keystroke or attachment that changed the draft, and with an empty draft after a send.
onSubmit
(feedback: FeedbackDraft & { scale: number }) => void | Promise<void>
default —
Sends the feedback. A promise holds Send pending; a rejection's message is shown and Send retries.
onCapture
() => FeedbackShot | Promise<FeedbackShot>
default —
Takes the screenshot (name and an image src). Without it a drawn sketch of the page is attached.
faces
"five" | "three" | "two"
default "five"
How many faces the rating offers.
dock
"right" | "left" | "bottom"
default "right"
The edge the tab sits on; the panel opens beside it (above it for bottom).
steps
"guided" | "single" | "quick"
default "guided"
Faces first and the rest after a choice, everything at once, or faces only where a choice sends.
title
string
default "How is it going?"
The panel's question and accessible name.
prompts
Partial<FeedbackPrompts>
default defaultFeedbackPrompts
What the text box asks after a low, middling or high rating.
placeholder
string
default "A sentence or two is plenty."
The text box's hint.
maxLength
number
default 280
The longest message; the counter turns warn in the last 10%.
screenshot
boolean
default true
Offer to attach a screenshot.
tabLabel
string
default "Feedback"
The tab's word.
sentLabel
string
default "Thanks"
What the tab and the folded note say once it is sent.
thanksHold
number
default 1600
How long the tab says thanks, in ms; it waits while the page is hidden.
fixed
boolean
default false
Dock to the viewport instead of the page passed as children.
children
React.ReactNode
default —
The page the widget docks to.
label
string
default —
The panel's accessible name when it should differ from the title.
sound
boolean
default false
A pop for each face chosen (pitched by rating) and for the note landing in the tab; a swish as the panel opens, closes and folds.
disabled
boolean
default false
Shows the tab but takes no input.
className
string
default —
Classes for the root, which wraps the page.