@sensefolks/openfeedback
v1.0.0
Published
Ask open-ended questions to understand user pain points
Maintainers
Readme
sf-openfeedback
Open-ended feedback survey web component for collecting qualitative user insights through free-text responses.
Features
- 📝 Open-ended text feedback collection
- ✅ Built-in form validation with accessible error messages
- 👤 Optional respondent details collection (text, email, number, dropdown, radio, checkbox)
- ♿ Keyboard navigable with ARIA labels and live regions
- 🎨 Customizable via CSS Parts
- 📱 Responsive design
- 🌐 Works with any framework
Installation
NPM
npm install @sensefolks/openfeedbackCDN (Script Tag)
<!-- Modern browsers (ES modules) -->
<script type="module" src="https://unpkg.com/@sensefolks/openfeedback/dist/sf-openfeedback/sf-openfeedback.esm.js"></script>
<!-- Legacy browsers -->
<script nomodule src="https://unpkg.com/@sensefolks/openfeedback/dist/sf-openfeedback/sf-openfeedback.js"></script>Or via jsDelivr:
<script type="module" src="https://cdn.jsdelivr.net/npm/@sensefolks/openfeedback/dist/sf-openfeedback/sf-openfeedback.esm.js"></script>Usage
HTML
<sf-openfeedback survey-key="your-survey-uuid" completion-message="Thank you for your feedback!"></sf-openfeedback>React
import '@sensefolks/openfeedback';
function App() {
return <sf-openfeedback survey-key="your-survey-uuid" completion-message="Thank you!"></sf-openfeedback>;
}Vue
<template>
<sf-openfeedback survey-key="your-survey-uuid" completion-message="Thank you!"></sf-openfeedback>
</template>
<script>
import '@sensefolks/openfeedback';
export default { name: 'App' };
</script>Angular
// app.module.ts
import { CUSTOM_ELEMENTS_SCHEMA } from '@angular/core';
import '@sensefolks/openfeedback';
@NgModule({
schemas: [CUSTOM_ELEMENTS_SCHEMA],
})
export class AppModule {}<!-- component.html -->
<sf-openfeedback survey-key="your-survey-uuid" completion-message="Thank you!"></sf-openfeedback>API
Properties
| Property | Attribute | Type | Default | Description |
| ------------------- | -------------------- | --------- | -------------------------------- | --------------------------------------------------------------- |
| surveyKey | survey-key | string | — | UUID of the survey to load (required) |
| completionMessage | completion-message | string | 'Thank you for your response!' | Message shown after successful submission |
| enableEvents | enable-events | boolean | true | Whether to emit custom events (sfReady, sfStepChange, etc.) |
Events
All events are emitted when enableEvents is true (the default).
| Event | Detail | Description |
| -------------- | ------------------------------------------------------------ | ------------------------------------------------------------------- |
| sfReady | { surveyKey, question } | Survey loaded and ready to display |
| sfStepChange | { surveyKey, previousStep, currentStep, currentStepIndex } | User navigated between steps |
| sfInput | { surveyKey, value, characterCount } | User typed in the feedback textarea |
| sfSubmit | { surveyKey, feedback, completionTimeSeconds } | Survey successfully submitted |
| sfError | { surveyKey, errorType, errorMessage } | Error occurred (errorType: 'load', 'submit', or 'validation') |
Survey Steps
The component progresses through steps based on the survey configuration:
- Question — Open-ended textarea for feedback (always shown)
- Respondent details — Collects user info like name, email, etc. (shown only when configured)
- Completion — Displays the completion message
CSS Parts
Style the component externally using ::part():
/* Layout */
sf-openfeedback::part(container) {
} /* Main wrapper (Host) */
sf-openfeedback::part(step) {
} /* Any step container */
sf-openfeedback::part(question-step) {
} /* Question step */
sf-openfeedback::part(respondent-details-step) {
} /* Respondent details step */
sf-openfeedback::part(completion-step) {
} /* Completion step */
sf-openfeedback::part(button-container) {
} /* Button row wrapper */
/* Headings */
sf-openfeedback::part(heading) {
} /* All step headings */
sf-openfeedback::part(question-heading) {
}
sf-openfeedback::part(respondent-heading) {
}
sf-openfeedback::part(completion-heading) {
}
/* Textarea */
sf-openfeedback::part(input) {
} /* All input elements */
sf-openfeedback::part(textarea) {
} /* Feedback textarea */
/* Respondent details form */
sf-openfeedback::part(respondent-fields-container) {
}
sf-openfeedback::part(field) {
} /* Form field container */
sf-openfeedback::part(field-label) {
} /* Form field labels */
sf-openfeedback::part(required-indicator) {
} /* Required asterisk */
sf-openfeedback::part(form-input) {
} /* Text/email/number inputs */
sf-openfeedback::part(select) {
}
sf-openfeedback::part(form-select) {
} /* Dropdown selects */
sf-openfeedback::part(radio-group) {
}
sf-openfeedback::part(radio-option) {
}
sf-openfeedback::part(radio-input) {
}
sf-openfeedback::part(radio-label) {
}
sf-openfeedback::part(checkbox-group) {
}
sf-openfeedback::part(checkbox-option) {
}
sf-openfeedback::part(checkbox-input) {
}
sf-openfeedback::part(checkbox-label) {
}
/* Buttons */
sf-openfeedback::part(button) {
} /* All buttons */
sf-openfeedback::part(next-button) {
} /* Next / Submit on question step */
sf-openfeedback::part(back-button) {
} /* Back button */
sf-openfeedback::part(submit-button) {
} /* Submit on respondent details */
sf-openfeedback::part(retry-button) {
} /* Retry on error */
/* Messages & States */
sf-openfeedback::part(message) {
} /* All messages (loading, error) */
sf-openfeedback::part(loading-message) {
}
sf-openfeedback::part(error-message) {
} /* Error text (validation + load/submit) */
sf-openfeedback::part(error-container) {
} /* Error wrapper with retry button */
sf-openfeedback::part(empty-message) {
} /* No respondent details message */
sf-openfeedback::part(announcements) {
} /* Screen reader live region */
/* Branding */
sf-openfeedback::part(branding) {
} /* Branding container */
sf-openfeedback::part(branding-link) {
} /* Branding link */
sf-openfeedback::part(branding-logo) {
} /* Branding logo SVG */Accessibility
- Full keyboard navigation (Tab between fields, Enter to submit)
- ARIA
aria-invalidandaria-describedbyon fields with validation errors aria-live="polite"region for screen reader announcements on step changes and submissions- Focus indicators (
outline) on all interactive elements - High contrast mode support via
@media (prefers-contrast: high) - Respects
prefers-reduced-motion
Browser Support
- Chrome 88+
- Firefox 85+
- Safari 14+
- Edge 88+
- IE11 (with ES5 build)
License
MIT © SenseFolks
