npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

storybook-addon-feedback

v0.2.0

Published

Storybook feedback survey addon to collect user ratings and reviews

Readme

storybook-addon-feedback

A Storybook addon that displays a configurable feedback survey in the toolbar. Collect star ratings, multiple-choice answers, and free-text responses from your Storybook users — then forward them to any webhook endpoint.

Live Demo →

Features

  • 5 question types — star rating, radio group, checkbox group, text input, textarea
  • Smart auto-popup — trigger the survey after a time delay, after a number of story navigations, or both
  • Persistent state — remembers completed/skipped/dismissed status across sessions via localStorage
  • Draft auto-save — in-progress answers are saved to sessionStorage and restored on reopen
  • Webhook submission — POST responses as JSON to any URL with configurable headers and timeout
  • Channel event — emits a feedback-survey/submitted event so other addons or tools can react
  • Customizable copy — override every UI string (buttons, error messages, thank-you screen)
  • Keyboard shortcut — toggle the survey dialog with Alt+Shift+S
  • Cross-tab sync — survey state updates propagate across browser tabs
  • Lifecycle controls — max impressions, cooldown period after dismissal, expiration date, global enable/disable

Installation

npm install storybook-addon-feedback

Peer dependencies

| Package | Version | | ------------------ | ------------------------------------ | | storybook | ^10.0.0 | | react | ^16.8.0 \|\| ^17 \|\| ^18 \|\| ^19 | | react-dom | ^16.8.0 \|\| ^17 \|\| ^18 \|\| ^19 | | @storybook/icons | ^2.0.0 |

Setup

Register the addon in your .storybook/main.ts:

import type { StorybookConfig } from '@storybook/react-vite';

const config: StorybookConfig = {
  stories: ['../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],
  addons: ['storybook-addon-feedback'],
  framework: {
    name: '@storybook/react-vite',
    options: {}
  }
};
export default config;

The addon works with both Vite and Webpack Storybook setups.

Configuration

Configure the survey via the feedbackSurvey parameter in .storybook/preview.ts:

import type { Preview } from '@storybook/react';

const preview: Preview = {
  parameters: {
    feedbackSurvey: {
      surveyId: 'my-survey-v1',
      title: 'Help Us Improve!',
      description: 'Share your thoughts on our component docs.',
      webhookUrl: 'https://your-endpoint.example.com/feedback',
      trigger: {
        delayMs: 5000,
        storyCount: 3
      },
      questions: [
        {
          id: 'rating',
          type: 'rating',
          label: 'How would you rate the docs?',
          required: true
        },
        {
          id: 'ease',
          type: 'radio',
          label: 'Was it easy to find what you needed?',
          options: ['Very Easy', 'Somewhat Easy', 'Difficult'],
          required: true,
          direction: 'row'
        },
        {
          id: 'topics',
          type: 'checkbox',
          label: 'What would you like more of?',
          options: ['Code Examples', 'Accessibility Guides', 'Best Practices']
        },
        {
          id: 'comments',
          type: 'textarea',
          label: 'Any other feedback?'
        }
      ]
    }
  }
};
export default preview;

Configuration reference

SurveyConfig

| Property | Type | Default | Description | | ------------------ | ------------------------- | ---------------------- | ------------------------------------------------------------ | | surveyId | string | 'default-survey-v1' | Unique identifier. Changing this resets all stored state. | | title | string | 'Feedback Survey' | Dialog title. | | description | string? | 'Help us improve...' | Short intro shown below the title. | | questions | SurveyField[] | [] | Questions to display. Survey is hidden when empty. | | webhookUrl | string? | — | URL to POST responses to. Omit to only emit a channel event. | | webhookHeaders | Record<string, string>? | — | Extra headers sent with the webhook request. | | requestTimeoutMs | number? | 10000 | Webhook timeout in ms (min 1000, max 120000). | | trigger | SurveyTrigger? | — | Auto-popup behavior. | | enabled | boolean? | true | Set to false to disable the survey globally. | | messages | SurveyMessages? | — | Override UI strings. |

SurveyField

| Property | Type | Description | | ------------- | ----------------------------------------------------------- | ---------------------------------------------------- | | id | string | Unique question identifier (used as response key). | | type | 'rating' \| 'radio' \| 'checkbox' \| 'text' \| 'textarea' | Question type. | | label | string | Question text shown to the user. | | required | boolean? | Whether the field must be filled before submission. | | options | string[]? | Choices for radio and checkbox types. | | placeholder | string? | Placeholder text for text and textarea types. | | direction | 'row' \| 'column'? | Layout direction for radio and checkbox options. |

SurveyTrigger

| Property | Type | Default | Description | | ---------------- | --------- | ------- | --------------------------------------------------------------------------------- | | delayMs | number? | 5000 | Auto-open after this many milliseconds. Set to 0 to disable time-based trigger. | | storyCount | number? | 3 | Auto-open after navigating to this many stories. | | maxImpressions | number? | — | Stop showing after this many auto-popups. | | coolDownDays | number? | — | Days to wait before showing again after a dismissal. | | expiresAt | string? | — | ISO date string after which the survey stops appearing. |

SurveyMessages

Override any UI string:

| Key | Default | | ------------------- | -------------------------------------------------- | | selectOption | "Please select at least one option." | | selectRating | "Please select a rating." | | requiredField | "This field is required." | | submissionFailure | "Failed to submit feedback. Please try again." | | skipPermanent | "Don't show again" | | cancel | "Cancel" | | submitFeedback | "Submit Feedback" | | submitting | "Submitting..." | | thankYouTitle | "Thank you!" | | thankYouBody | "Your feedback has been successfully submitted." | | thankYouClose | "Close" |

Webhook payload

When webhookUrl is configured, the addon sends a POST request with this JSON body:

{
  "surveyId": "my-survey-v1",
  "timestamp": "2025-06-01T12:34:56.789Z",
  "responses": {
    "rating": 4,
    "ease": "Very Easy",
    "topics": ["Code Examples", "Best Practices"],
    "comments": "Great docs!"
  }
}

If no webhookUrl is set, the addon still emits the payload on the Storybook channel under the feedback-survey/submitted event. You can listen for it in another addon or decorator:

import { addons } from 'storybook/manager-api';

addons.register('my-listener', (api) => {
  const channel = api.getChannel();
  channel.on('feedback-survey/submitted', (payload) => {
    console.log('Feedback received:', payload);
  });
});

How it works

The survey button appears in the Storybook toolbar (visible in story view mode). A notification dot indicates the survey hasn't been completed or permanently skipped.

Auto-popup logic:

  1. After the configured delayMs timeout fires, or
  2. After the user navigates to storyCount different stories

The survey won't auto-pop if any of these conditions are true:

  • Already completed
  • Permanently skipped ("Don't show again")
  • Dismissed this session
  • Within the cooldown period after a previous dismissal
  • Max impressions reached
  • Past the expiresAt date
  • enabled is false

Users can always open the survey manually via the toolbar button or the Alt+Shift+S shortcut, regardless of auto-popup state.

Per-story configuration

You can override the survey config for specific stories using story-level parameters:

export const MyStory = {
  parameters: {
    feedbackSurvey: {
      title: 'Rate this component',
      questions: [
        {
          id: 'component-rating',
          type: 'rating',
          label: 'How useful is this component?',
          required: true
        }
      ]
    }
  }
};

License

MIT