FeaturePriority
FeaturePriority runs structured feature research inside your product. Use Kano to classify expectations, MaxDiff to compare relative importance, or Bradley-Terry to model pairwise preference.
What FeaturePriority Measures
FeaturePriority runs a multi-step survey that can combine up to three methods in one response flow. You choose the methods in your dashboard.
- Kano analysis asks two questions per feature: "How would you feel if this feature existed?" and "How would you feel if it didn't?" The answers sort features into must-have, performance, attractive, indifferent, and reverse categories. For a deeper look, see the Kano model guide.
- MaxDiff shows a set of features and asks respondents to pick the best and worst. Repeated tasks produce relative importance evidence across the set.
- Bradley-Terry pairwise comparison presents two features side by side and asks which one they prefer. Repeated A-versus-B choices support a relative ranking.
The component handles step transitions and progress tracking in memory. Reloading the page starts a fresh Kano flow with no restored answers.
When FeaturePriority Is the Right Survey
Use it when your decision depends on comparing several potential features, not simply asking whether one idea sounds good.
- 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 (Recommended)
<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
Override these properties on the element or a parent to theme the component:
| 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
FeaturePriority has a large number of CSS Parts because of its multi-step design (Kano, MaxDiff, pairwise). Parts are organized by step:
/* 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);
}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 |