UserChoice
UserChoice presents product concepts and records the choices people make between them. Use those repeated choices to study which attributes and combinations influence preference.
What UserChoice Measures
UserChoice presents a series of product configurations ("concepts") and asks respondents to choose among them. Across tasks, this reveals which attributes and combinations drive preference.
For a deeper methodology overview, see theconjoint analysis guide.
Choices and task progress stay only in the mounted component. Reloading the page starts again at the first task with blank answers.
When UserChoice Is the Right Survey
Use it when people must choose between realistic combinations and you need to understand the trade-offs behind those choices.
- Product concepts — Compare realistic combinations of features, price, or service levels
- Plan design — Learn which bundles people prefer when benefits compete
- Concept validation — Compare candidate configurations before building
- Beta and early-access research — Study preference with an engaged audience
Installation
CDN (Recommended)
<script type="module" src="https://unpkg.com/@sensefolks/[email protected]/dist/sf-userchoice/sf-userchoice.esm.js"></script>NPM
npm install @sensefolks/userchoiceEmbed UserChoice
HTML
<sf-userchoice
survey-key="your-survey-uuid"
completion-message="Thank you for your feedback!">
</sf-userchoice>React
import '@sensefolks/userchoice';
function App() {
return (
<sf-userchoice
survey-key="your-survey-uuid"
completion-message="Thank you!">
</sf-userchoice>
);
}Vue
<template>
<sf-userchoice
survey-key="your-survey-uuid"
completion-message="Thank you!">
</sf-userchoice>
</template>
<script>
import '@sensefolks/userchoice';
export default {name: 'App'};
</script>Angular
// app.module.ts
import {CUSTOM_ELEMENTS_SCHEMA} from '@angular/core';
import '@sensefolks/userchoice';
@NgModule({
schemas: [CUSTOM_ELEMENTS_SCHEMA],
})For React + Next.js, Vue + Nuxt, Svelte, and Astro examples, see theEmbedding Tutorial.
API Reference
Properties
| Property | Attribute | Type | Default | Description |
|---|---|---|---|---|
surveyKey | survey-key | string | — | Required. UUID of the survey from your dashboard |
completionMessage | completion-message | string | 'Thank you for your response!' | Message shown after submission |
thankYouMessage | thank-you-message | string | — | Overrides the saved survey thank-you message |
sessionData | — | Record<string, string | number | boolean> | {} | Complete typed Session Data matching every field in the schema defined during survey creation |
Events
| Event | Description | Detail Properties |
|---|---|---|
sfError | Fired on load, submit, or validation errors | surveyKey, errorType, errorMessage |
CSS Custom Properties
Override these custom properties to theme the component:
| Property | Default | Description |
|---|---|---|
--sf-primary | #005fcc | Primary accent color |
--sf-primary-hover | #0047a3 | Primary color hover state |
--sf-text-primary | #111827 | Primary text color |
--sf-text-secondary | #6b7280 | Secondary/muted text color |
--sf-error-color | #dc2626 | Error state color |
--sf-error-text | #991b1b | Error message text color |
--sf-card-bg | #ffffff | Card/container background |
--sf-card-border | #d1d5db | Card/container border color |
--sf-card-radius | 8px | Card/container border radius |
--sf-button-radius | 6px | Button border radius |
--sf-transition | 150ms ease | Default transition timing |
--sf-selected-bg | #e8f0fe | Selected card background |
--sf-selected-border | #005fcc | Selected card border color |
--sf-card-shadow | 0 1px 3px rgba(0,0,0,0.1) | Card shadow |
--sf-card-shadow-hover | 0 4px 12px rgba(0,0,0,0.15) | Card hover shadow |
--sf-none-bg | #f9fafb | "None" option background |
--sf-none-border | #9ca3af | "None" option border |
--sf-error-bg | #fef2f2 | Error state background |
--sf-error-border | #fecaca | Error state border |
--sf-progress-bg | #e5e7eb | Progress bar track background |
--sf-progress-fill | #005fcc | Progress bar fill color |
/* Override theme tokens on the component */
sf-userchoice {
--sf-primary: #7c3aed;
--sf-primary-hover: #6d28d9;
--sf-card-radius: 12px;
--sf-button-radius: 8px;
--sf-selected-bg: #ede9fe;
--sf-selected-border: #7c3aed;
--sf-selected-ring: rgba(0, 95, 204, 0.2);
--sf-button-text: #ffffff;
--sf-none-hover-bg: #f3f4f6;
}CSS Parts
Style individual elements inside the shadow DOM using ::part(). UserChoice has a large number of parts because of its multi-step, card-based UI:
/* Survey container */
sf-userchoice::part(survey-container) { }
/* Steps */
sf-userchoice::part(step) { }
sf-userchoice::part(choice-task-step) { }
sf-userchoice::part(survey-fields-step) { }
sf-userchoice::part(completion-step) { }
/* Headings */
sf-userchoice::part(heading) { }
sf-userchoice::part(task-heading) { }
sf-userchoice::part(survey-fields-heading) { }
sf-userchoice::part(completion-heading) { }
/* Task header & progress */
sf-userchoice::part(task-header) { }
sf-userchoice::part(task-instructions) { }
sf-userchoice::part(progress-indicator) { }
sf-userchoice::part(progress-label) { }
sf-userchoice::part(progress-track) { }
sf-userchoice::part(progress-bar) { }
sf-userchoice::part(progress-fill) { }
sf-userchoice::part(progress-text) { }
/* Concepts */
sf-userchoice::part(concepts-container) { }
sf-userchoice::part(concept) { }
sf-userchoice::part(concept-selected) { }
sf-userchoice::part(concept-unselected) { }
sf-userchoice::part(none-option) { }
sf-userchoice::part(concept-header) { }
sf-userchoice::part(concept-radio) { }
sf-userchoice::part(concept-title) { }
sf-userchoice::part(concept-attributes) { }
sf-userchoice::part(concept-attribute) { }
sf-userchoice::part(attribute-label) { }
sf-userchoice::part(attribute-value) { }
/* Buttons */
sf-userchoice::part(button-container) { }
sf-userchoice::part(button) { }
sf-userchoice::part(back-button) { }
sf-userchoice::part(next-button) { }
sf-userchoice::part(submit-button) { }
/* Survey Fields form */
sf-userchoice::part(form-container) { }
sf-userchoice::part(form-field) { }
sf-userchoice::part(form-label) { }
sf-userchoice::part(form-input) { }
sf-userchoice::part(form-select) { }
sf-userchoice::part(hcaptcha-container) { }
sf-userchoice::part(input) { }
sf-userchoice::part(select) { }
sf-userchoice::part(required-indicator) { }
sf-userchoice::part(radio-group) { }
sf-userchoice::part(radio-option) { }
sf-userchoice::part(radio-input) { }
sf-userchoice::part(radio-label) { }
sf-userchoice::part(checkbox-group) { }
sf-userchoice::part(checkbox-option) { }
sf-userchoice::part(checkbox-input) { }
sf-userchoice::part(checkbox-label) { }
/* Completion */
sf-userchoice::part(completion-summary) { }
sf-userchoice::part(summary-text) { }
/* Messages & errors */
sf-userchoice::part(message) { }
sf-userchoice::part(error-message) { }
sf-userchoice::part(loading-message) { }
sf-userchoice::part(error-container) { }
sf-userchoice::part(troubleshooting-link) { }
/* Branding */
sf-userchoice::part(branding) { }
sf-userchoice::part(branding-link) { }
sf-userchoice::part(branding-logo) { }
/* Accessibility */
sf-userchoice::part(announcements) { }Accessibility
- Full keyboard navigation (Tab, Arrow keys, Enter/Space)
- ARIA labels and live regions for screen readers
- Progress announcements ("Choice Task 2 of 5")
- Focus indicators and high contrast mode support
- Respects
prefers-reduced-motion
Browser Support
| Browser | Version |
|---|---|
| Chrome | 88+ |
| Firefox | 85+ |
| Safari | 14+ |
| Edge | 88+ |
| IE11 | Not supported |