Survey
Google-Forms-style question cards: an eyebrow, a title with an optional required asterisk, and an answer. Survey owns the layout and semantics; the controls are the real DS components.
Installation#
Usage#
import {
SurveyQuestion,
SurveyHeader,
SurveyEyebrow,
SurveyTitle,
SurveyOptions,
SurveyOption,
} from "@/components/ui/survey"
export function Example() {
return (
<SurveyQuestion required>
<SurveyHeader>
<SurveyEyebrow>Question 1</SurveyEyebrow>
<SurveyTitle>How do you build UI today?</SurveyTitle>
</SurveyHeader>
<SurveyOptions defaultValue="shared">
<SurveyOption value="shared">A shared internal component library</SurveyOption>
<SurveyOption value="kit">An off-the-shelf UI kit</SurveyOption>
</SurveyOptions>
</SurveyQuestion>
)
}Single & multiple choice#
Without a prop, SurveyOptions is a single choice: the DS RadioGroup with its canonical dot and roving focus, reporting a string. Add multiple and each row becomes a DS Checkbox reporting a string[]. The controls aren't re-styled; they're the same radio and checkbox you'd use anywhere else.
Text, paragraph & dropdown#
A question doesn't have to be a choice. SurveyShortAnswer composes the DS Input, SurveyParagraph the auto-growing Textarea (with an optional counter), and SurveyDropdown the Select for long option lists. Each is labelled by the question title automatically.
Linear scale#
SurveyScale is a 1-to-N rating row built on RadioGroup. Set min/max and optional minLabel/maxLabel captions for the ends.
Rating#
SurveyRating composes the DS Rating for a star score, labelled by the question title. It forwards every Rating prop: max, size, icon, readOnly.
Description & disabled options#
Add a SurveyDescription under the title for context, and disable any single SurveyOption: keyboard navigation skips it and its row dims.
Density#
density="compact" tightens the card padding, gaps, and row height for embedded, information-dense forms; radius and color never change. Defaults to comfortable, or set it once on a DensityProvider.
Controlled#
Pass value and onValueChange to own the selection. For a multiple group the value is a string[].
Composing a form#
There is no Survey root or provider: every SurveyQuestion is a standalone card, so a survey is just the cards you need stacked inside your own form. Pass name to a single-choice SurveyOptions, SurveyScale, or a text part and the answer lands in FormData. A multiple group owns a string[] in React state, so serialize that one yourself.