FeaturePriority
FeaturePriority helps you rank backlog items using structured methods. It combines Kano, MaxDiff, and Bradley-Terry to separate must-haves from lower-priority features.
How It Works
FeaturePriority runs a multi-step survey that can combine up to three methods in one session. 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. Over multiple rounds, this produces a clean ranking that's more reliable than simple rating scales.
- Bradley-Terry pairwise comparison presents two features side by side and asks "which do you prefer?" Simple A-vs-B choices turn into a statistically sound ranking.
The component handles step transitions, progress tracking, and session state.
When to Use FeaturePriority
Embed FeaturePriority where users evaluate and prioritize options:
- Feature comparison pages — Understand what matters most
- Onboarding preference steps — Personalize the experience
- Product configuration flows — Capture priority order
- Landing pages — Validate feature importance before building
Installation
CDN (Recommended)
<!-- Modern browsers (ES modules) -->
<script type="module" src="https://unpkg.com/@sensefolks/featurepriority/dist/sf-featurepriority/sf-featurepriority.esm.js"></script>
<!-- Legacy browsers -->
<script nomodule src="https://unpkg.com/@sensefolks/featurepriority/dist/sf-featurepriority/sf-featurepriority.js"></script> NPM
npm install @sensefolks/featurepriority Framework Integration
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, Angular, Next.js, and Svelte examples, see the Embedding 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 |
Events
This component does not emit custom DOM events.
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-featurepriority {
--sf-primary: #005fcc;
--sf-primary-hover: #0047a3;
--sf-text-primary: #111827;
--sf-text-secondary: #6b7280;
--sf-error-color: #dc2626;
--sf-card-bg: #ffffff;
--sf-card-border: #d1d5db;
--sf-card-radius: 8px;
--sf-button-radius: 6px;
--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 */ }
sf-featurepriority::part(retry-button) { /* Retry button on error */ }
/* 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(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 */ }
/* Respondent details step */
sf-featurepriority::part(respondent-details-step) { /* Respondent details container */ }
sf-featurepriority::part(respondent-details-heading) { /* Respondent details 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 | Supported (ES5 build) |