npm package: @sensefolks/reaction
Description: Lightweight reaction survey component for capturing sentiment through tappable icons
Author: SenseFolks
Latest version: 1.0.0

# sf-reaction

[![npm version](https://img.shields.io/npm/v/@sensefolks/reaction.svg)](https://www.npmjs.com/package/@sensefolks/reaction)
[![npm downloads](https://img.shields.io/npm/dm/@sensefolks/reaction.svg)](https://www.npmjs.com/package/@sensefolks/reaction)
[![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](https://opensource.org/licenses/MIT)

> 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

```bash
npm install @sensefolks/reaction
```

### CDN (Script Tag)

```html
<!-- 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:

```html
<script type="module" src="https://cdn.jsdelivr.net/npm/@sensefolks/reaction/dist/sf-reaction/sf-reaction.esm.js"></script>
```

## Usage

### HTML

```html
<sf-reaction survey-key="your-survey-uuid"></sf-reaction>
```

### React

```jsx
import '@sensefolks/reaction';

function App() {
  return <sf-reaction survey-key="your-survey-uuid"></sf-reaction>;
}
```

### Vue

```vue
<template>
  <sf-reaction survey-key="your-survey-uuid"></sf-reaction>
</template>

<script>
import '@sensefolks/reaction';
export default { name: 'App' };
</script>
```

### Angular

```typescript
// app.module.ts
import { CUSTOM_ELEMENTS_SCHEMA } from '@angular/core';
import '@sensefolks/reaction';

@NgModule({
  schemas: [CUSTOM_ELEMENTS_SCHEMA],
})
export class AppModule {}
```

```html
<!-- component.html -->
<sf-reaction survey-key="your-survey-uuid"></sf-reaction>
```

## How It Works

1. On load, the component fetches survey config from the embed API using the `surveyKey`.
2. It renders a row of reaction buttons based on the config's `reactionMode` (`emotion`, `binary`, or `single`) or custom reactions.
3. Tapping a reaction sends a POST (new), PATCH (change), or soft-delete PATCH (deselect) to the response API.
4. The selected reaction and response ID are saved to `localStorage` under `sf-reaction:{surveyKey}` for session persistence.
5. 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()`:

```css
/* 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"` with `aria-pressed` to 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](https://sensefolks.com)