Scale Question
betaA question answered on a short worded scale, for check-ins, like "Poor, Broken, OK, Good, Great". One answer, as cards in a row with the dot above each word. All ink, so no end of the scale looks better.
Preview
check-in
states
size
Install
1. Add the registry to
components.json, once per app. Without it, the shadcn CLI looks up@txbrendanin a public list that txbrendan/ui does not control.npx shadcn@latest registry add "@txbrendan=https://txbrendan.dev/r/{name}.json"2. Add the theme, once per app. It replaces your color tokens with ones checked for contrast.
npx shadcn@latest add @txbrendan/theme3. Add the component.
npx shadcn@latest add @txbrendan/scale-question
Use it for
- Check-ins: sleep, workload, mood, how hard a task felt.
- Name the question in label, and say over what time in hint, like "Last three nights".
- Give up to five steps, lowest first. Words, not numbers: "None, Light, Some, Busy, Too much".
- The answer is the step's number, 1 to the number of steps.
- Keep each word short. Five cards share a phone's width, and a long word wraps.
Avoid it for
- A scale with an end that is good or bad by color. This one stays ink on purpose.
- More than five steps, or a number scale like 1 to 10. Use a slider or a number stepper.
- Options that need a hint or a price each. Use selection cards.
Props
- steps
The words, lowest first. Up to five.
string[]
- value
The step's number, 1 to steps.length, or null for no answer. Use with onValueChange to control it.
number | null
- defaultValue
The step's number at first render, when you do not control it.
number | null
- onValueChange
Called with the step's number when someone picks one.
(value: number) => void
- label
Names the question. TypeScript requires this, aria-label, or aria-labelledby.
ReactNode
- hint
Over what time, like "Last three nights". It describes the group.
ReactNode
- error
Replaces the hint, in red, and turns every card's edge red.
ReactNode
- size
Text and dot size.
"sm" | "md" | "lg" · default "md"
- disabled
Blocks choosing.
boolean · default false
- ref
Reaches the group. Focusing it focuses the answer, or the first step.
Ref<HTMLDivElement>
- id
Lands on the group, with aria-* and data-*. Its aria-describedby joins the note's.
string
- className
Classes for the frame around the label, the cards, and the note.
string
| Prop | Type | Default | What it does |
|---|---|---|---|
| steps | string[] | - | The words, lowest first. Up to five. |
| value | number | null | - | The step's number, 1 to steps.length, or null for no answer. Use with onValueChange to control it. |
| defaultValue | number | null | - | The step's number at first render, when you do not control it. |
| onValueChange | (value: number) => void | - | Called with the step's number when someone picks one. |
| label | ReactNode | - | Names the question. TypeScript requires this, aria-label, or aria-labelledby. |
| hint | ReactNode | - | Over what time, like "Last three nights". It describes the group. |
| error | ReactNode | - | Replaces the hint, in red, and turns every card's edge red. |
| size | "sm" | "md" | "lg" | "md" | Text and dot size. |
| disabled | boolean | false | Blocks choosing. |
| ref | Ref<HTMLDivElement> | - | Reaches the group. Focusing it focuses the answer, or the first step. |
| id | string | - | Lands on the group, with aria-* and data-*. Its aria-describedby joins the note's. |
| className | string | - | Classes for the frame around the label, the cards, and the note. |
Accessibility
- A radio group named by the label, with a radio in each card named by its word.
- Tab lands on the answer, or the first step. The arrow keys move and choose.
- Screen readers hear the word and where it sits, like "Some, 3 of 5".
- The hint or the error describes the group. An error is announced once when it appears.
- A chosen card shows a dot and a doubled edge, so the answer does not rest on color.
Examples
Answered, with a hint
<ScaleQuestion label="Sleep" hint="Last three nights" steps={["Poor", "Broken", "OK", "Good", "Great"]} defaultValue={4} />Unanswered, with a hint
<ScaleQuestion label="Workload" hint="This week" steps={["None", "Light", "Some", "Busy", "Too much"]} />