All posts
11 min read

16 shadcn Questionnaire Blocks: Ask One Question at a Time and Answer With Something Useful

Sixteen free blocks built on the shadcn questionnaire primitive: support routers, product finders, intake forms, configurators, and shortlists that narrow as you answer. Each installs with one CLI command and turns a long form into a short conversation.

questionnaireformsshadcnreactux

Most interfaces ask badly. A support page offers a search box and hopes you know the vocabulary. A product page offers twelve filters and hopes you know your own requirements. A contact form asks fourteen questions at once, including the four that do not apply to you, and the answer arrives three days later from somebody who read none of them.

The alternative is older than the web: ask one question, listen to the answer, then ask the next one. That is what the shadcn questionnaire primitive makes practical in a React app, and it is what these sixteen blocks are built on. Every one of them asks a short sequence, and every one ends with something concrete: a written answer, a matched product, a booked appointment type, a specification with a price on it.

All sixteen are free.

Free block

This block is free. No license or account is required: install it with the CLI and use it in unlimited projects.

What installs

Each block is a single React component, and the CLI resolves its whole tree in one command:

bash
npx shadcn add "https://ui.beste.co/r/faq92"

That lands three layers:

  1. The section at components/beste/block/faq92.tsx. Plain TSX you own.
  2. The questionnaire primitive at components/ui/questionnaire.tsx, plus whatever else the block composes.
  3. Nothing else. No form engine, no flow builder, no runtime dependency on us.

If you are on Base UI rather than Radix, swap /r/ for /r-base/ and you get the Base UI build of the same component.

The primitive underneath

components/ui/questionnaire.tsx is a thin styled layer over @shadcn/react, the headless package shadcn publishes for it. It is worth understanding before you edit a block, because it does more than hide and show fields.

The parts compose like any other shadcn component:

tsx
<Questionnaire defaultItem="area" shortcuts="numbers" onSubmit={handleSubmit}>
  <QuestionnaireProgress />

  <QuestionnaireItem name="area" required>
    <QuestionnaireTitle>What is this about?</QuestionnaireTitle>
    <QuestionnaireChoices>
      <QuestionnaireChoice value="billing">Billing and invoices</QuestionnaireChoice>
      <QuestionnaireChoice value="access">Getting into the account</QuestionnaireChoice>
    </QuestionnaireChoices>
    <QuestionnaireError />
  </QuestionnaireItem>

  <QuestionnaireActions>
    <QuestionnairePrevious />
    <QuestionnaireNext />
    <QuestionnaireSubmit />
  </QuestionnaireActions>
</Questionnaire>

Four things it gives you for free are the reason these blocks are short:

Let the primitive own navigation

Every block here keeps the flow uncontrolled and only watches it, usually with onItemChange, to draw a progress bar or swap a photograph. Fighting the primitive for control of the current step is the fastest way to end up with a flow that disagrees with its own buttons.

Four things a questionnaire can end with

The sixteen blocks are not sixteen variations on a wizard. They are grouped by what happens when the answers land, because that is the decision you are actually making when you pick one.

One: route to a written answer

The cheapest support win is not a better search box. It is admitting that most tickets are a dozen questions wearing different words, and routing to the one that fits.

Answer Router
View block
Loading preview…
faq92: two questions instead of a search box. The answers pick one written answer from a list of routes, and the assistant card beside them answers the question you arrived by.

faq92 matches on a small object per answer, so a narrow route sits above a general one for the same subject and wins when both fit. The last entry is the catch-all, which means a submit never dead-ends. The same shape drives booking29, where the routes are appointment types with a length, a clinician, and a set of facts, and careers56, where they are open roles with a published pay band.

fitness40 is the honest version of the pattern. Its result answers in two columns of equal weight: who the programme is for beside who should not take it. A recommendation that never says no is a sales page, and readers can tell.

Two: score the answers and recommend

When the answer is a ranking rather than a lookup, the blocks score instead of match.

Product Finder Quiz
View block
Loading preview…
ecommerce46: a product finder that replaces the filter sidebar. Each answer asks for traits, each product scores one point per trait it carries, and the winner takes over the plate with the reasons it came out on top.

The scoring is deliberately blunt: one point per trait, highest total wins, ties go to the first item. What makes it feel considered is the reasons list, which is not written by hand. It collects the reason attached to every answer the winning product actually satisfies, so the same bag explains itself differently depending on how you reached it.

podcast54 scores the same way but returns an order rather than an item: three episodes to listen to in sequence, with the total runtime summed from the episodes themselves. workflow55 weights each answer with a number, turns the total into a percentage of the ceiling, and places you on a scale between shipping straight away and full change control. education102 grades against an answer key and shows its working, including the explanation for anything you got wrong.

Three: build something while you answer

The most useful thing a questionnaire can do is show its work as it goes, so nothing arrives as a surprise at the end.

Live Made To Order Configurator
View block
Loading preview…
product12: a made-to-order configurator. Every option takes over the photograph, writes its own line into a running specification, and moves a total that is visible from the first question.

product12 never hides the price. The specification sits under the questions the whole time, filling one row per answered step, with the total recomputed from a base plus each option. event101 does the same for a day at a conference: a fixed rail of time slots that fill in as you choose, with the hours you left open still on the page, because an empty afternoon is a decision worth seeing.

Narrowing Destination Shortlist
View block
Loading preview…
travel42: a shortlist that eliminates in the open. Six photographs sit beside the questions and dim as each answer rules them out, with a live count underneath.

travel42 inverts the filter sidebar. Instead of a result count quietly changing somewhere, you watch the grid narrow one answer at a time, which tells you what each question is costing you while you can still change it. It is possible to answer your way down to nothing, so the empty state is written copy rather than a blank panel.

gallery25 takes the idea somewhere else again: its questions are photographs rather than sentences. You pick the frames you would hang, and the result is a distribution rather than a winner, because a split eye should read as split.

Four: collect, then confirm

The last group is the one closest to a traditional form, and the one where a questionnaire earns the most.

Studio Brief With Changing Plate
View block
Loading preview…
agency24: a four-step studio brief where the photograph changes with the question on screen, and sending it swaps the form for a ledger of every answer.

A brief asked one question at a time is answered more honestly than the same brief as a wall of fields, and the closing ledger matters as much as the questions: it shows the sender exactly what is about to be sent. onboarding43 applies that to workspace setup, cta92 to a newsletter that asks which subjects you want before it asks for your address, and saas108 to a sales enquiry that branches, so nobody is asked about compliance for a blog.

Every value on the screen is a prop

The rule behind the whole catalog holds here: if you can read it, you can pass it.

Each block renders its full demo with zero props, so <Faq92 /> looks exactly like the embed above. Every prop is optional and falls back to the demo value, so you replace demo copy with real content one field at a time:

tsx
import { Faq92 } from "@/components/beste/block/faq92";

export default function HelpPage() {
  return (
    <Faq92
      heading="Two questions instead of a search box"
      questions={[
        {
          name: "area",
          title: "What is this about?",
          choices: [
            { value: "billing", label: "Billing and invoices" },
            { value: "access", label: "Getting into the account" },
          ],
        },
        {
          name: "state",
          title: "Where did it stop working?",
          choices: [
            { value: "before", label: "Before I could start" },
            { value: "after", label: "It finished, but the result is wrong" },
          ],
        },
      ]}
      answers={[
        {
          match: { area: "billing", state: "after" },
          title: "The invoice does not match what you expected",
          description: "Mid-cycle plan changes are prorated to the day.",
          link: { label: "Read how proration is calculated", href: "/docs/billing" },
        },
        {
          title: "Something else",
          description: "Start from the index and narrow down from there.",
          link: { label: "Open the help index", href: "/docs" },
        },
      ]}
    />
  );
}

Every block exports its demo object too (faq92Demo here), which doubles as documentation: the exact shape your data needs, in a file you can open.

Wiring the result to your backend is the part we deliberately left to you. Each block resolves its outcome in one handler, so you add a fetch there and nothing else changes.

The details we had to get right

The full set

Every block links to a live, full-screen preview. They are gathered under one hub at /blocks/tag/questionnaire.

BlockWhat it doesEnds with
faq92Support router, two questionsOne written answer
booking29Appointment intakeA matched appointment type
careers56Role fit finderOne open role and its pay band
fitness40Programme matchWho it is for, beside who it is not
ecommerce46Product finderOne product and why it won
podcast54Listening path builderThree episodes in order
workflow55Process sizerA position on a weighted scale
education102Graded lesson checkA score and a per-question review
product12Made-to-order configuratorA live specification and total
event101Conference day builderA filled schedule, gaps included
travel42Narrowing shortlistWhatever survived the answers
gallery25Taste profile from photographsA distribution across styles
agency24Studio briefA ledger of the answers
onboarding43Workspace setup wizardA review of what will be created
cta92Tailored subscriptionA confirmation that reads back
saas108Branching sales enquiryA scoped enquiry, sent

Start with the question you already ask badly

The quickest way in is not to build a new flow. It is to find the place where your product already asks too much at once: the contact form nobody finishes, the filter sidebar nobody touches, the help page that sends everyone to the same inbox. Install the block that fits, replace the demo copy with the questions you already ask on a call, and wire the outcome to whatever handles it today.

The questions are the product decision. The blocks are so that writing them down takes an afternoon rather than a sprint.

Markdown version