npm package: @sensefolks/fastpoll
Description: Conduct single or multi-choice polls to understand user opinions in a snap
Author: SenseFolks
Latest version: 1.1.0

# sf-fastpoll

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

> Fast poll survey web component for collecting user feedback with single/multiple choice options.

## Features

- 🎯 Single and multiple choice polls
- 📝 Optional follow-up questions (triggered by specific choices)
- 👤 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

```bash
npm install @sensefolks/fastpoll
```

### CDN (Script Tag)

```html
<!-- Modern browsers (ES modules) -->
<script type="module" src="https://unpkg.com/@sensefolks/fastpoll/dist/sf-fastpoll/sf-fastpoll.esm.js"></script>

<!-- Legacy browsers -->
<script nomodule src="https://unpkg.com/@sensefolks/fastpoll/dist/sf-fastpoll/sf-fastpoll.js"></script>
```

Or via jsDelivr:

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

## Usage

### HTML

```html
<sf-fastpoll survey-key="your-survey-uuid" completion-message="Thank you for your feedback!"></sf-fastpoll>
```

### React

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

function App() {
  return <sf-fastpoll survey-key="your-survey-uuid" completion-message="Thank you!"></sf-fastpoll>;
}
```

### Vue

```vue
<template>
  <sf-fastpoll survey-key="your-survey-uuid" completion-message="Thank you!"></sf-fastpoll>
</template>

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

### Angular

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

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

```html
<!-- component.html -->
<sf-fastpoll survey-key="your-survey-uuid" completion-message="Thank you!"></sf-fastpoll>
```

## 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, choiceType, choiceCount }`                        | Survey loaded and ready to display                                  |
| `sfStepChange`   | `{ surveyKey, previousStep, currentStep, currentStepIndex }`              | User navigated between steps                                        |
| `sfChoiceSelect` | `{ surveyKey, selectedChoices, choiceType, lastAction, lastChoice }`      | User selected or deselected a choice                                |
| `sfSubmit`       | `{ surveyKey, selectedChoices, followUpResponse, 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:

1. **Poll** — User selects choices (always shown)
2. **Follow-up** — Free-text response (shown only when selected choices match configured trigger choices)
3. **Respondent details** — Collects user info like name, email, etc. (shown only when configured)
4. **Completion** — Displays the completion message

### CSS Parts

Style the component externally using `::part()`:

```css
/* Layout */
sf-fastpoll::part(survey-container) {
} /* Main wrapper */
sf-fastpoll::part(step) {
} /* Any step container */
sf-fastpoll::part(poll-step) {
} /* Poll step */
sf-fastpoll::part(follow-up-step) {
} /* Follow-up step */
sf-fastpoll::part(respondent-details-step) {
} /* Respondent details step */
sf-fastpoll::part(completion-step) {
} /* Completion step */
sf-fastpoll::part(button-container) {
} /* Button row wrapper */

/* Headings */
sf-fastpoll::part(heading) {
} /* All step headings */
sf-fastpoll::part(poll-heading) {
}
sf-fastpoll::part(follow-up-heading) {
}
sf-fastpoll::part(respondent-details-heading) {
}
sf-fastpoll::part(completion-heading) {
}

/* Poll choices */
sf-fastpoll::part(choices-container) {
} /* Choices wrapper */
sf-fastpoll::part(choice-option) {
} /* Individual choice label */
sf-fastpoll::part(choice-label) {
} /* Choice text span */

/* Buttons */
sf-fastpoll::part(button) {
} /* All buttons */
sf-fastpoll::part(next-button) {
} /* Next / Submit on poll & follow-up */
sf-fastpoll::part(back-button) {
} /* Back button */
sf-fastpoll::part(submit-button) {
} /* Submit on respondent details */
sf-fastpoll::part(retry-button) {
} /* Retry on error */

/* Follow-up */
sf-fastpoll::part(followup-input-container) {
}
sf-fastpoll::part(textarea) {
}
sf-fastpoll::part(followup-textarea) {
}

/* Respondent details form */
sf-fastpoll::part(form-container) {
}
sf-fastpoll::part(form-field) {
}
sf-fastpoll::part(form-label) {
}
sf-fastpoll::part(required-indicator) {
}
sf-fastpoll::part(input) {
}
sf-fastpoll::part(form-input) {
}
sf-fastpoll::part(select) {
}
sf-fastpoll::part(form-select) {
}
sf-fastpoll::part(radio-group) {
}
sf-fastpoll::part(radio-option) {
}
sf-fastpoll::part(radio-input) {
}
sf-fastpoll::part(radio-label) {
}
sf-fastpoll::part(checkbox-group) {
}
sf-fastpoll::part(checkbox-option) {
}
sf-fastpoll::part(checkbox-input) {
}
sf-fastpoll::part(checkbox-label) {
}

/* Messages */
sf-fastpoll::part(message) {
} /* All messages (loading, error) */
sf-fastpoll::part(loading-message) {
}
sf-fastpoll::part(error-message) {
} /* Error text (validation + load/submit) */
sf-fastpoll::part(error-container) {
} /* Error wrapper with retry button */
sf-fastpoll::part(announcements) {
} /* Screen reader live region */
```

## Accessibility

- Full keyboard navigation (Tab, Arrow keys, Enter/Space)
- ARIA `role="radiogroup"` / `role="group"` on choices depending on single/multi choice
- `aria-invalid` and `aria-describedby` on fields with validation errors
- `aria-live="polite"` region for screen reader announcements on step changes and selections
- 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](https://sensefolks.com)