KQ-1757 · PROMOTER/SCALE
Promoter Scale
A score survey: zero to ten, then the one question written for the band the answer falls in. Picking a score fills the segments from zero up to it in a quick wave — each fill sweeping in on springs.snap a few milliseconds after the last, every one in the picked band's colour, draining from the top when the score drops — and a beat later the scale shrinks into a summary chip, its segments travelling on springs.glide into the chip's mini ticks while the follow-up slides in from 16px. The scale is a real radio group: arrows and Home or End move the score with the wave following, number keys pick one (1 then 0 is ten) and Enter, Space or a click confirms; the chip brings the scale back, Escape in the follow-up does too, and sending, thanked, failed and dismissed states are covered with the card's measured height gliding between them.
Order FW-2041 · three ferns, arrived Tuesday
Arrow keys or a number choose a score; 1 then 0 is ten. Enter confirms it.
How likely are you to recommend Fernworks to a friend or colleague?
pick a score · fernworks survey
Install
One command — the source lands in your repo. Or copy it from the Code tab.
$ pnpm dlx shadcn@latest add @kinetiq/promoter-scale
Props
- segmentStyle
- "tiles" | "bars" | "dots"
- default "tiles"
- How the scale is drawn: equal tiles that fill from the left, bars rising left to right that fill from the base, or discs that fill from the centre.
- bandPalette
- "status" | "tonal" | "quiet"
- default "status"
- Band colours as pigment: danger, warn and success; the accent at three depths; or quiet greys with promoters in the accent.
- cornerRadius
- number
- default 8
- Corner radius in px of the segments, ticks, chip, field and buttons; the card rounds with it.
- question
- string
- default "How likely are you to recommend Fernworks to a friend or colleague?"
- The question over the scale; it also names the radio group.
- bands
- PromoterBand[]
- default defaultPromoterBands
- Score bands low to high as { id, label, from, to, colour? }: Detractor 0–6, Passive 7–8, Promoter 9–10 by default.
- followUps
- Record<string, PromoterFollowUp>
- default defaultPromoterFollowUps
- The follow-up for each band id as { question, placeholder?, chips? }; chips become quick reason toggles.
- value / defaultValue
- number | null
- default — / null
- The score.
- onValueChange
- (score) => void
- default —
- Fires as a click, an arrow or a number key changes the score.
- onScore
- (score, band) => void
- default —
- A score was confirmed and its follow-up opened.
- onSubmit
- (answer) => void | Promise
- default —
- Send or Skip was pressed with { score, band, comment, reasons }. Return a promise to show sending; a rejection shows the failed state with the answer kept.
- onDismiss
- () => void
- default —
- The survey was dismissed; it folds to one line with Undo.
- lowLabel
- string
- default "Not likely"
- Words under the low end of the scale.
- highLabel
- string
- default "Very likely"
- Words under the high end of the scale.
- max
- number
- default 10
- The top of the scale.
- sendState
- "idle" | "sending" | "sent" | "failed"
- default —
- Controlled send state, for a host that tracks delivery itself; by default it follows the promise onSubmit returns.
- disabled
- boolean
- default false
- The survey can be read but not answered.
- className
- string
- default —
- Classes for the survey's outer box.
| Prop | Type | Default | Description |
|---|---|---|---|
| segmentStyle | "tiles" | "bars" | "dots" | "tiles" | How the scale is drawn: equal tiles that fill from the left, bars rising left to right that fill from the base, or discs that fill from the centre. |
| bandPalette | "status" | "tonal" | "quiet" | "status" | Band colours as pigment: danger, warn and success; the accent at three depths; or quiet greys with promoters in the accent. |
| cornerRadius | number | 8 | Corner radius in px of the segments, ticks, chip, field and buttons; the card rounds with it. |
| question | string | "How likely are you to recommend Fernworks to a friend or colleague?" | The question over the scale; it also names the radio group. |
| bands | PromoterBand[] | defaultPromoterBands | Score bands low to high as { id, label, from, to, colour? }: Detractor 0–6, Passive 7–8, Promoter 9–10 by default. |
| followUps | Record<string, PromoterFollowUp> | defaultPromoterFollowUps | The follow-up for each band id as { question, placeholder?, chips? }; chips become quick reason toggles. |
| value / defaultValue | number | null | — / null | The score. |
| onValueChange | (score) => void | — | Fires as a click, an arrow or a number key changes the score. |
| onScore | (score, band) => void | — | A score was confirmed and its follow-up opened. |
| onSubmit | (answer) => void | Promise | — | Send or Skip was pressed with { score, band, comment, reasons }. Return a promise to show sending; a rejection shows the failed state with the answer kept. |
| onDismiss | () => void | — | The survey was dismissed; it folds to one line with Undo. |
| lowLabel | string | "Not likely" | Words under the low end of the scale. |
| highLabel | string | "Very likely" | Words under the high end of the scale. |
| max | number | 10 | The top of the scale. |
| sendState | "idle" | "sending" | "sent" | "failed" | — | Controlled send state, for a host that tracks delivery itself; by default it follows the promise onSubmit returns. |
| disabled | boolean | false | The survey can be read but not answered. |
| className | string | — | Classes for the survey's outer box. |