Skip to main content
userTourKit
@tour-kit/surveysHeadless

Headless

Render-prop components that supply survey state and ARIA props without rendering any markup — full control over appearance and interaction

domidex01Published Updated

Headless components expose the same logic as the styled components through render props. You own every element; the component manages state, accessibility attributes, and controlled vs uncontrolled transitions.

When to use headless

Use headless components when:

  • Your design system has bespoke input styles that can't be layered over the defaults
  • You need to compose survey UI into an existing modal or drawer not managed by @tour-kit/surveys
  • You want to integrate with a third-party animation library

Use styled components when:

  • You want to ship quickly and don't have strong design constraints
  • Your app already uses Tailwind and the defaults are close enough

Import path

// Styled components (default entry point)
import { QuestionRating } from '@tour-kit/surveys';

// Headless components — separate entry point
import {
  HeadlessSurvey,
  HeadlessQuestionRating,
  HeadlessQuestionText,
  HeadlessQuestionSelect,
  HeadlessQuestionBoolean,
} from '@tour-kit/surveys/headless';

Available headless components

Pattern overview

Every headless component follows the same render-prop pattern:

<HeadlessQuestionRating
  id="score"
  label="Rate this feature"
  min={1}
  max={5}
  onChange={(value) => survey.answer('score', value)}
>
  {({ value, options, ratingGroupProps, getOptionProps }) => (
    <div {...ratingGroupProps}>
      {options.map((opt) => (
        <button key={opt} {...getOptionProps(opt)}>
          {opt}
        </button>
      ))}
    </div>
  )}
</HeadlessQuestionRating>

The *Props objects returned by each component contain correctly typed ARIA attributes, role, and tabIndex. Spread them onto your elements to get full accessibility without writing it yourself.