Headless
Render-prop components that supply survey state and ARIA props without rendering any markup — full control over appearance and interaction
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
HeadlessSurvey
Provides full useSurvey state via render prop — no markup rendered
HeadlessQuestionRating
Rating scale state: value, options, ratingGroupProps, getOptionProps
HeadlessQuestionText
Text input state: value, characterCount, inputProps, characterCountProps
HeadlessQuestionSelect
Select state: value, groupProps, getOptionProps — works in single or multi mode
HeadlessQuestionBoolean
Boolean state: value, groupProps, getOptionProps for yes/no
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.
Ship onboarding, not config.
npm i @tour-kit/core is MIT and free. The Pro packages work unlicensed too — a one-time $99 license removes the production watermark when you ship.
MIT-licensed — no signup, no credit card. Pay once, only when you ship.