FeaturePriority
FeaturePriority is an embeddable feature prioritization survey. It starts with Kano, then uses MaxDiff and Bradley-Terry pairwise comparisons when enough features advance.
What FeaturePriority Measures
Configure 4–7 features in the dashboard. The respondent's Kano answers determine which stages follow:
- Kano asks about each feature's presence and absence. Must-be, performance, and attractive features advance. See the Kano guide.
- MaxDiff compares best and worst choices to narrow the qualifying features.
- Bradley-Terry estimates relative preference from the final pairwise choices.
After Kano, 0–2 qualifying features end the research flow; 3 go straight to pairwise comparison; 4 or more continue to MaxDiff, then pairwise. Refreshing clears progress.
When should I use FeaturePriority?
Use FeaturePriority to compare a shortlist of potential features.
- Feature comparison pages — Understand what matters most
- Onboarding research — Learn which capabilities matter to new users
- Product configuration research — Compare preference between capabilities
- Concept pages — Test feature expectations before committing to a roadmap
Installation
CDN
<script type="module" src="https://unpkg.com/@sensefolks/[email protected]/dist/sf-featurepriority/sf-featurepriority.esm.js"></script>NPM
npm install @sensefolks/featurepriorityEmbed FeaturePriority
HTML
<sf-featurepriority
survey-key="your-survey-uuid"
completion-message="Thank you for your feedback!">
</sf-featurepriority>React
import '@sensefolks/featurepriority';
function App() {
return (
<sf-featurepriority
survey-key="your-survey-uuid"
completion-message="Thank you!">
</sf-featurepriority>
);
}For Vue + Nuxt, Angular, 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
Set these variables on the component or a parent:
| Property | Default | Description |
|---|---|---|
--sf-primary | #005fcc | Primary brand color |
--sf-primary-hover | #0047a3 | Primary hover color |
--sf-text-primary | #111827 | Primary text color |
--sf-text-secondary | #6b7280 | Secondary/muted text color |
--sf-error-color | #dc2626 | Error state color |
--sf-card-bg | #ffffff | Card background color |
--sf-card-border | #d1d5db | Card border color |
--sf-card-radius | 8px | Card border radius |
--sf-button-radius | 6px | Button border radius |
--sf-transition | 150ms ease | Transition timing |
--sf-progress-bg | #e5e7eb | Progress track color |
--sf-progress-fill | Primary color | Progress fill color |
sf-featurepriority {
--sf-primary: #005fcc;
--sf-primary-hover: #0047a3;
--sf-text-primary: #111827;
--sf-text-secondary: #6b7280;
--sf-error-color: #dc2626;
--sf-error-text: #991b1b;
--sf-error-bg: #fef2f2;
--sf-error-border: #fecaca;
--sf-card-bg: #ffffff;
--sf-card-border: var(--color__grey--450);
--sf-card-radius: 8px;
--sf-button-radius: 6px;
--sf-progress-bg: #ede9fe;
--sf-progress-fill: #7c3aed;
--sf-feature-focus-bg: rgba(0, 95, 204, 0.1);
--sf-feature-drag-bg: rgba(0, 95, 204, 0.2);
--sf-transition: 150ms ease;
}CSS Parts
CSS Parts are grouped by Kano, MaxDiff, pairwise, and shared UI:
/* Layout */
sf-featurepriority::part(survey-container) { /* Outer survey wrapper */ }
sf-featurepriority::part(container) { /* Host element wrapper */ }
sf-featurepriority::part(step) { /* Step container (shared by all steps) */ }
sf-featurepriority::part(step-indicator) { /* Step progress indicator */ }
sf-featurepriority::part(heading) { /* Step headings (shared) */ }
sf-featurepriority::part(instructions) { /* Step instructions (shared) */ }
sf-featurepriority::part(button-container) { /* Button row container */ }
sf-featurepriority::part(button) { /* All buttons (shared) */ }
sf-featurepriority::part(next-button) { /* Next/Continue button */ }
sf-featurepriority::part(back-button) { /* Back button */ }
sf-featurepriority::part(submit-button) { /* Submit button */ }
/* Progress */
sf-featurepriority::part(progress) { /* Progress wrapper */ }
sf-featurepriority::part(progress-indicator) { /* Progress wrapper alias */ }
sf-featurepriority::part(progress-label) { /* Progress label */ }
sf-featurepriority::part(progress-text) { /* Progress text alias */ }
sf-featurepriority::part(progress-track) { /* Progress track */ }
sf-featurepriority::part(progress-bar) { /* Progress bar alias */ }
sf-featurepriority::part(progress-fill) { /* Filled progress bar */ }
/* Messages */
sf-featurepriority::part(message) { /* General messages */ }
sf-featurepriority::part(error-message) { /* Error messages */ }
sf-featurepriority::part(loading-message) { /* Loading state message */ }
sf-featurepriority::part(error-container) { /* Error state container */ }
sf-featurepriority::part(troubleshooting-link) { /* Link to integration troubleshooting */ }
sf-featurepriority::part(announcements) { /* Screen reader live region */ }
/* Kano step */
sf-featurepriority::part(kano-step) { /* Kano step container */ }
sf-featurepriority::part(kano-heading) { /* Kano step heading */ }
sf-featurepriority::part(kano-description) { /* Kano item description */ }
sf-featurepriority::part(kano-question) { /* Kano question block */ }
sf-featurepriority::part(kano-functional) { /* Functional question block */ }
sf-featurepriority::part(kano-dysfunctional) { /* Dysfunctional question block */ }
sf-featurepriority::part(kano-question-label) { /* Kano question label */ }
sf-featurepriority::part(kano-option) { /* Kano radio option wrapper */ }
sf-featurepriority::part(radio-group) { /* Radio button group */ }
sf-featurepriority::part(radio-input) { /* Radio input element */ }
sf-featurepriority::part(radio-label) { /* Radio option label */ }
/* Transition screen */
sf-featurepriority::part(step-transition) { /* Transition screen container */ }
sf-featurepriority::part(transition-heading) { /* Transition heading */ }
sf-featurepriority::part(transition-summary) { /* Transition summary text */ }
sf-featurepriority::part(transition-description) { /* Transition description text */ }
/* MaxDiff step */
sf-featurepriority::part(maxdiff-step) { /* MaxDiff step container */ }
sf-featurepriority::part(maxdiff-heading) { /* MaxDiff heading */ }
sf-featurepriority::part(maxdiff-instructions) { /* MaxDiff instructions */ }
sf-featurepriority::part(maxdiff-trial) { /* MaxDiff trial container */ }
sf-featurepriority::part(maxdiff-columns) { /* MaxDiff column headers row */ }
sf-featurepriority::part(maxdiff-column-header) { /* MaxDiff column header cell */ }
sf-featurepriority::part(maxdiff-option) { /* MaxDiff option row */ }
sf-featurepriority::part(maxdiff-item-label) { /* MaxDiff item label */ }
sf-featurepriority::part(maxdiff-item-description) { /* MaxDiff item description */ }
sf-featurepriority::part(best-selector) { /* Best selector cell */ }
sf-featurepriority::part(worst-selector) { /* Worst selector cell */ }
/* Pairwise step */
sf-featurepriority::part(pairwise-step) { /* Pairwise step container */ }
sf-featurepriority::part(pairwise-heading) { /* Pairwise heading */ }
sf-featurepriority::part(pairwise-instructions) { /* Pairwise instructions */ }
sf-featurepriority::part(pairwise-matchup) { /* Pairwise matchup container */ }
sf-featurepriority::part(pairwise-option) { /* Base pairwise option button */ }
sf-featurepriority::part(pairwise-option-left) { /* Left option button */ }
sf-featurepriority::part(pairwise-option-right) { /* Right option button */ }
sf-featurepriority::part(pairwise-option-title) { /* Option title text */ }
sf-featurepriority::part(pairwise-option-description) { /* Option description text */ }
sf-featurepriority::part(pairwise-vs) { /* "vs" divider */ }
/* Results / completion */
sf-featurepriority::part(funnel-complete-step) { /* Completion step container */ }
sf-featurepriority::part(funnel-complete-heading) { /* Completion heading */ }
sf-featurepriority::part(funnel-results) { /* Results container */ }
sf-featurepriority::part(ranking-summary) { /* Ranking summary block */ }
sf-featurepriority::part(summary-heading) { /* Summary heading */ }
sf-featurepriority::part(summary-list) { /* Summary list container */ }
sf-featurepriority::part(summary-item) { /* Individual summary item */ }
sf-featurepriority::part(summary-rank) { /* Rank number */ }
sf-featurepriority::part(summary-title) { /* Item title in summary */ }
sf-featurepriority::part(summary-kano-label) { /* Kano category label in summary */ }
/* Survey Fields step */
sf-featurepriority::part(survey-fields-step) { /* Survey Fields container */ }
sf-featurepriority::part(survey-fields-heading) { /* Survey Fields heading */ }
sf-featurepriority::part(form-container) { /* Form container */ }
sf-featurepriority::part(form-field) { /* Form field wrapper */ }
sf-featurepriority::part(form-label) { /* Form field label */ }
sf-featurepriority::part(form-input) { /* Text/email/number input */ }
sf-featurepriority::part(form-select) { /* Select dropdown */ }
sf-featurepriority::part(hcaptcha-container) { /* hCaptcha wrapper */ }
sf-featurepriority::part(form-radio-group) { /* Radio group in form */ }
sf-featurepriority::part(form-radio) { /* Radio input in form */ }
sf-featurepriority::part(form-radio-label) { /* Radio label in form */ }
sf-featurepriority::part(form-checkbox-group) { /* Checkbox group in form */ }
sf-featurepriority::part(form-checkbox) { /* Checkbox input in form */ }
sf-featurepriority::part(form-checkbox-label) { /* Checkbox label in form */ }
sf-featurepriority::part(field-error) { /* Field validation error */ }
sf-featurepriority::part(required-indicator) { /* Required field asterisk */ }
/* Branding */
sf-featurepriority::part(branding) { /* Branding container */ }
sf-featurepriority::part(branding-link) { /* Branding link */ }
sf-featurepriority::part(branding-logo) { /* Branding logo */ }Styling Example
sf-featurepriority {
--sf-primary: #7c3aed;
--sf-text-primary: #1f2937;
--sf-card-radius: 12px;
--sf-button-radius: 8px;
}
sf-featurepriority::part(kano-step) {
padding: 1.5rem;
background: var(--sf-card-bg);
border-radius: var(--sf-card-radius);
}
sf-featurepriority::part(pairwise-option-left),
sf-featurepriority::part(pairwise-option-right) {
border: 2px solid var(--sf-card-border);
border-radius: var(--sf-card-radius);
padding: 1rem;
transition: border-color var(--sf-transition);
}
sf-featurepriority::part(pairwise-option-selected) {
border-color: var(--sf-primary);
background-color: rgba(124, 58, 237, 0.05);
}Completion and validation styles
| CSS Part | Element |
|---|---|
success-message | Submission confirmation |
survey-field-error-message | Respondent-field validation feedback |
completion-heading | Completion message heading |
Use --sf-success-bg, --sf-success-border, and --sf-success-text for the confirmation background, border, and text.
Accessibility
- Full keyboard navigation with Enter/Space to select options
- ARIA labels and live regions for screen readers
- Step progress announcements for screen reader users
- 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 |