@sensefolks/reaction
v1.0.0
Published
Lightweight reaction survey component for capturing sentiment through tappable icons
Maintainers
Readme
sf-reaction
Lightweight reaction survey web component for capturing sentiment through tappable emoji, icons, or thumbs up/down.
Features
- 😍 Emotion, binary (thumbs), and single (heart) reaction modes
- 🎨 Custom reactions with emoji or SVG icons
- 💾 Session persistence via localStorage
- ♿ Keyboard navigable with ARIA labels and live regions
- 🎨 Customizable via CSS Parts
- 📱 Responsive design
- 🌐 Works with any framework
Installation
NPM
npm install @sensefolks/reactionCDN (Script Tag)
<!-- Modern browsers (ES modules) -->
<script type="module" src="https://unpkg.com/@sensefolks/reaction/dist/sf-reaction/sf-reaction.esm.js"></script>
<!-- Legacy browsers -->
<script nomodule src="https://unpkg.com/@sensefolks/reaction/dist/sf-reaction/sf-reaction.js"></script>Or via jsDelivr:
<script type="module" src="https://cdn.jsdelivr.net/npm/@sensefolks/reaction/dist/sf-reaction/sf-reaction.esm.js"></script>Usage
HTML
<sf-reaction survey-key="your-survey-uuid"></sf-reaction>React
import '@sensefolks/reaction';
function App() {
return <sf-reaction survey-key="your-survey-uuid"></sf-reaction>;
}Vue
<template>
<sf-reaction survey-key="your-survey-uuid"></sf-reaction>
</template>
<script>
import '@sensefolks/reaction';
export default { name: 'App' };
</script>Angular
// app.module.ts
import { CUSTOM_ELEMENTS_SCHEMA } from '@angular/core';
import '@sensefolks/reaction';
@NgModule({
schemas: [CUSTOM_ELEMENTS_SCHEMA],
})
export class AppModule {}<!-- component.html -->
<sf-reaction survey-key="your-survey-uuid"></sf-reaction>How It Works
- On load, the component fetches survey config from the embed API using the
surveyKey. - It renders a row of reaction buttons based on the config's
reactionMode(emotion,binary, orsingle) or custom reactions. - Tapping a reaction sends a POST (new), PATCH (change), or soft-delete PATCH (deselect) to the response API.
- The selected reaction and response ID are saved to
localStorageundersf-reaction:{surveyKey}for session persistence. - If the stored response is no longer found (404), the session is cleared automatically.
Reaction Modes
| Mode | Default Reactions |
| --------- | -------------------------------------------------- |
| emotion | Love, Haha, Wow, Sad, Angry, Like (Phosphor icons) |
| binary | Thumbs Up, Thumbs Down |
| single | Heart |
Custom reactions override defaults and support emoji or svg icon types.
API
Properties
| Property | Attribute | Type | Default | Description |
| ----------- | ------------ | -------- | ----------- | ------------------------------------- |
| surveyKey | survey-key | string | undefined | UUID of the survey to load (required) |
Events
| Event | Detail | Description |
| ---------- | -------------------------------------------- | ---------------------------------------------------------------------------------- |
| sfReady | { surveyKey, reactionMode, reactionCount } | Survey config loaded and reactions rendered |
| sfSubmit | { surveyKey, selectedReaction, action } | Reaction created, updated, or deleted (action: create | update | delete) |
| sfError | { surveyKey, errorType, errorMessage } | Error occurred (errorType: 'load' or 'submit') |
CSS Parts
Style the component externally using ::part():
/* Layout */
sf-reaction::part(reaction-container) {
} /* Top-level wrapper */
sf-reaction::part(reactions-row) {
} /* Flex container holding all reaction buttons */
/* Reaction items */
sf-reaction::part(reaction-item) {
} /* Each reaction button */
sf-reaction::part(reaction-item-active) {
} /* Currently selected reaction button */
sf-reaction::part(reaction-icon) {
} /* Icon wrapper (default and SVG types) */
sf-reaction::part(reaction-emoji) {
} /* Emoji text span */
sf-reaction::part(reaction-emoji-highlight) {
} /* Circular highlight behind selected emoji */
sf-reaction::part(reaction-label) {
} /* Text label below each reaction */
/* Buttons */
sf-reaction::part(button) {
} /* Generic button base (retry) */
sf-reaction::part(retry-button) {
} /* "Try again" button on error */
/* Messages */
sf-reaction::part(message) {
} /* Shared part on all status text */
sf-reaction::part(loading-message) {
} /* Loading text */
sf-reaction::part(error-message) {
} /* Error text */
sf-reaction::part(error-container) {
} /* Error wrapper with retry button */
sf-reaction::part(announcements) {
} /* Screen reader live region */Accessibility
- Reaction buttons use
role="button"witharia-pressedto indicate selection state - A live region (
aria-live="polite") announces selection changes to screen readers - Focus indicators are visible and enhanced in high-contrast mode
- Animations respect
prefers-reduced-motion
Browser Support
- Chrome 88+
- Firefox 85+
- Safari 14+
- Edge 88+
- IE11 (with ES5 build)
License
MIT © SenseFolks
