KQ-911 · REPORT/SHEET
Report Sheet
A report sheet that rises inside the component's own box. Pressing Report glides a ResizeObserver-measured height open on glide, the reasons arrive as radio chips from 8px on snap in a cascade stagger, and picking one unfolds a note field in that same measured height and hands it focus. Send stamps a mark that lands from 1.12x on recoil and lowers the sheet after a hold; arrows step the chips, Home and End jump, Escape closes and returns focus to the trigger.
KQ-911 · REPORT/SHEET
Reporting a message from Rui Baptista, sent at 08:12.
Whoever packed pallet 4471 cannot count. Useless.
sheet closed · no reason
Install
One command — the source lands in your repo. Or copy it from the Code tab.
$ pnpm dlx shadcn@latest add @kinetiq/report-sheet
Props
- message
- { author: string; time: string; text: string }
- default —
- The message under report, quoted at the top of the component.
- reasons
- ReportReason[]
- default —
- The chips, in the order given; each carries a label and an optional hint sentence.
- open / defaultOpen
- boolean
- default false
- Controlled or initial sheet state.
- onOpenChange
- (open: boolean) => void
- default —
- Fires from the trigger, Cancel, Escape, and the lower after a send.
- reason / defaultReason
- string
- default ""
- Controlled or initial reason id.
- onReasonChange
- (id: string) => void
- default —
- Fires from a chip press or an arrow key, and with an empty string when the sheet lowers after a send.
- note / defaultNote
- string
- default ""
- Controlled or initial note.
- onNoteChange
- (note: string) => void
- default —
- Fires from every keystroke in the note field.
- onSubmit
- (report: { reason: string; label: string; note: string }) => void
- default —
- Fires once from Send with the frozen report.
- onCancel
- () => void
- default —
- Fires from Cancel and from Escape.
- noteMaxLength
- number
- default 140
- Characters the note field accepts.
- holdMs
- number
- default 1100
- How long the stamp holds before the sheet lowers; the timer pauses while the tab is hidden.
- triggerLabel
- string
- default "Report"
- The trigger's word.
- title
- string
- default "Why are you reporting this?"
- The sheet's heading, which also names the radio group.
- sentLabel
- string
- default "Report sent"
- The stamp's word.
- label
- string
- default —
- Names the sheet for assistive technology.
| Prop | Type | Default | Description |
|---|---|---|---|
| message | { author: string; time: string; text: string } | — | The message under report, quoted at the top of the component. |
| reasons | ReportReason[] | — | The chips, in the order given; each carries a label and an optional hint sentence. |
| open / defaultOpen | boolean | false | Controlled or initial sheet state. |
| onOpenChange | (open: boolean) => void | — | Fires from the trigger, Cancel, Escape, and the lower after a send. |
| reason / defaultReason | string | "" | Controlled or initial reason id. |
| onReasonChange | (id: string) => void | — | Fires from a chip press or an arrow key, and with an empty string when the sheet lowers after a send. |
| note / defaultNote | string | "" | Controlled or initial note. |
| onNoteChange | (note: string) => void | — | Fires from every keystroke in the note field. |
| onSubmit | (report: { reason: string; label: string; note: string }) => void | — | Fires once from Send with the frozen report. |
| onCancel | () => void | — | Fires from Cancel and from Escape. |
| noteMaxLength | number | 140 | Characters the note field accepts. |
| holdMs | number | 1100 | How long the stamp holds before the sheet lowers; the timer pauses while the tab is hidden. |
| triggerLabel | string | "Report" | The trigger's word. |
| title | string | "Why are you reporting this?" | The sheet's heading, which also names the radio group. |
| sentLabel | string | "Report sent" | The stamp's word. |
| label | string | — | Names the sheet for assistive technology. |