Skip to main content
userTourKit
@tour-kit/surveysHeadless

HeadlessQuestionSelect

Headless select — manages single or multi-select state and returns groupProps and getOptionProps with correct ARIA roles for each mode

domidex01Published Updated

HeadlessQuestionSelect manages value state and returns ARIA props that adapt to mode. In single mode, options receive role="radio"; in multi mode they receive role="checkbox".

Import

import { HeadlessQuestionSelect } from '@tour-kit/surveys/headless';

Usage

Single-select

import { HeadlessQuestionSelect } from '@tour-kit/surveys/headless';

const options = [
  { value: 'price', label: 'Price' },
  { value: 'features', label: 'Missing features' },
  { value: 'support', label: 'Poor support' },
];

<HeadlessQuestionSelect
  id="cancel-reason"
  label="Why are you leaving?"
  options={options}
  mode="single"
  onChange={(value) => survey.answer('cancel-reason', value)}
>
  {({ value, groupProps, getOptionProps }) => (
    <div {...groupProps} className="flex flex-col gap-2">
      {options.map((opt) => {
        const optProps = getOptionProps(opt.value);
        return (
          <div
            key={opt.value}
            {...optProps}
            onClick={() => setValue(opt.value)}
            className={`p-3 border rounded cursor-pointer ${optProps['aria-checked'] ? 'border-blue-600 bg-blue-50' : ''}`}
          >
            {opt.label}
          </div>
        );
      })}
    </div>
  )}
</HeadlessQuestionSelect>

Multi-select

<HeadlessQuestionSelect
  id="reasons"
  label="Select all that apply"
  options={options}
  mode="multi"
  onChange={(value) => survey.answer('reasons', value)}
>
  {({ options: opts, groupProps, getOptionProps, setValue, value }) => (
    <div {...groupProps} className="flex flex-col gap-2">
      {opts.map((opt) => {
        const optProps = getOptionProps(opt.value);
        const current = Array.isArray(value) ? value : [];
        return (
          <div
            key={opt.value}
            {...optProps}
            onClick={() => {
              const next = current.includes(opt.value)
                ? current.filter((v) => v !== opt.value)
                : [...current, opt.value];
              setValue(next);
            }}
            className={`p-3 border rounded cursor-pointer ${optProps['aria-checked'] ? 'border-blue-600' : ''}`}
          >
            {opt.label}
          </div>
        );
      })}
    </div>
  )}
</HeadlessQuestionSelect>

Props

Prop

Type

Render prop shape

Prop

Type