@sensefolks/featurepriority
v1.0.0
Published
Identify high-impact features that drive user satisfaction and retention
Maintainers
Readme
sf-featurepriority
Identify high-impact features that drive user satisfaction and retention. Supports drag-and-drop ranking and a funneled Kano → MaxDiff → Pairwise methodology.
Features
- 🎯 Two survey modes: drag-and-drop ranking and guided funneled (Kano → MaxDiff → Pairwise)
- 🔬 Per-respondent real-time filtering — only features that matter advance to the next step
- 📊 Client-side scoring: Kano classification, MaxDiff utility scores, Bradley-Terry rankings
- 💾 Session persistence via localStorage — respondents can resume where they left off
- ⌨️ Keyboard-accessible throughout
- ♿ Screen reader optimized with ARIA live regions
- 🎨 Customizable via CSS Parts
- 📱 Responsive design
- 🌐 Works with any framework
How It Works (Funneled Mode)
All Features
│
▼
┌─────────────┐
│ Kano Step │ Respondent rates each feature as functional/dysfunctional
│ │ → Must-Be, Performance, Attractive features advance
└──────┬──────┘
│ survivors (≥3 features)
▼
┌─────────────┐
│ MaxDiff Step│ Best/Worst comparisons across balanced trials
│ │ → Top-N features by utility score advance
└──────┬──────┘
│ top-N features
▼
┌─────────────┐
│Pairwise Step│ Head-to-head matchups → Bradley-Terry ranking
└──────┬──────┘
│
▼
Final RankingIf fewer than 3 features survive Kano, the survey ends early with a Kano-only result. If fewer than 4 survive MaxDiff, the survey skips to Pairwise directly.
Survey Modes
Ranking Mode (default)
Respondents drag and drop features into priority order.
<sf-featurepriority survey-key="your-survey-uuid" completion-message="Thank you!"> </sf-featurepriority>Config:
{
"question": "Which features matter most to you?",
"surveyMode": "ranking",
"items": [
{ "title": "Dark mode", "value": "dark-mode" },
{ "title": "Offline support", "value": "offline" }
]
}Funneled Mode
Guided Kano → MaxDiff → Pairwise sequence.
Config:
{
"question": "Which features matter most to you?",
"surveyMode": "funneled",
"itemsPerTrial": 4,
"topNThreshold": 3,
"items": [
{ "title": "Dark mode", "description": "Switch to a dark color scheme", "value": "dark-mode" },
{ "title": "Offline support", "value": "offline" },
{ "title": "Collaboration", "value": "collab" },
{ "title": "API access", "value": "api" }
]
}itemsPerTrial: features shown per MaxDiff trial (3–5, default 4)topNThreshold: features advancing from MaxDiff to Pairwise (min 2, < item count)items: 4–7 features for funneled mode, 2–7 for ranking mode
Installation
NPM
npm install @sensefolks/featurepriorityCDN
<!-- ES modules -->
<script type="module" src="https://unpkg.com/@sensefolks/featurepriority/dist/sf-featurepriority/sf-featurepriority.esm.js"></script>
<!-- Legacy -->
<script nomodule src="https://unpkg.com/@sensefolks/featurepriority/dist/sf-featurepriority/sf-featurepriority.js"></script>jsDelivr:
<script type="module" src="https://cdn.jsdelivr.net/npm/@sensefolks/featurepriority/dist/sf-featurepriority/sf-featurepriority.esm.js"></script>Usage
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>;
}Vue
<template>
<sf-featurepriority survey-key="your-survey-uuid" completion-message="Thank you!"> </sf-featurepriority>
</template>
<script>
import '@sensefolks/featurepriority';
export default {};
</script>Angular
// app.module.ts
import { CUSTOM_ELEMENTS_SCHEMA } from '@angular/core';
import '@sensefolks/featurepriority';
@NgModule({ schemas: [CUSTOM_ELEMENTS_SCHEMA] })<!-- template -->
<sf-featurepriority survey-key="your-survey-uuid"></sf-featurepriority>API Properties
| Property | Attribute | Type | Default | Description |
| ------------------- | -------------------- | -------- | ------- | ------------------------------ |
| surveyKey | survey-key | string | — | Survey public UUID (required) |
| completionMessage | completion-message | string | "" | Message shown after submission |
Events
| Event | Detail | Description |
| -------------- | ----------------------------------------------------------- | -------------------------------------------------- |
| sfReady | { surveyKey, mode } | Fired when the component loads and config is ready |
| sfStepChange | { step: 'kano' \| 'maxdiff' \| 'pairwise' \| 'complete' } | Fired on funneled step transitions |
| sfSubmit | { surveyKey, responseData } | Fired after successful submission |
| sfError | { message, code } | Fired on load or submission errors |
CSS Parts
All interactive elements expose CSS parts for custom styling.
Shared parts
| Part | Description |
| -------------------- | -------------------------------------------- |
| survey-container | Outer wrapper |
| heading | Survey question heading |
| instructions | Helper text / instructions |
| step-indicator | Step progress indicator (e.g. "Step 1 of 3") |
| progress-indicator | Item/trial/matchup progress (e.g. "2 of 5") |
| nav-button | Previous / Next / Submit navigation buttons |
| error-message | Inline error messages |
| sr-region | Screen reader live region |
| step-transition | Interstitial transition screen between steps |
Kano parts
| Part | Description |
| -------------------- | ------------------------------------ |
| kano-question | Container for one Kano question pair |
| kano-functional | Functional question radio group |
| kano-dysfunctional | Dysfunctional question radio group |
| kano-option | Individual Kano radio option |
MaxDiff parts
| Part | Description |
| ---------------- | ------------------------------------ |
| maxdiff-trial | Container for one MaxDiff trial |
| maxdiff-option | Individual feature option in a trial |
| best-selector | "Most Important" radio selector |
| worst-selector | "Least Important" radio selector |
Pairwise parts
| Part | Description |
| ----------------------- | -------------------------------------- |
| pairwise-matchup | Container for one head-to-head matchup |
| pairwise-option-left | Left option in a matchup |
| pairwise-option-right | Right option in a matchup |
Ranking parts
| Part | Description |
| -------------- | -------------------------- |
| ranking-list | Drag-and-drop ranking list |
| ranking-item | Individual ranking item |
Accessibility
- All interactive elements are keyboard-navigable
- ARIA live regions announce step transitions, filtering results, and selection confirmations
- Radio groups use descriptive
aria-labelattributes - Pairwise matchups use
role="group"witharia-describedby - Step indicators include full context in
aria-label - Respects
prefers-reduced-motion— all animations are disabled when set
Browser Support
| Browser | Version | | ------- | ------- | | Chrome | 67+ | | Firefox | 63+ | | Safari | 10.1+ | | Edge | 79+ |
License
MIT © SenseFolks
