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

feedback-popup

v5.0.0

Published

A simple to use popup for collecting feedback from users about issues with the site that they are using. Currently it captures a screenshot of the users browser, the users OS and browser name + version and also a message from the user. This is all then se

Readme

feedback-popup

npm version npm downloads License: MIT GitHub issues

Feedback Popup is a simple to use popup for collecting feedback from users about issues with the site that they are using. It captures a screenshot of the user's browser, the user's OS and browser name + version, and also a message from the user. This is all then sent to an API, where you can do whatever you like with the information.

More features to come!

Table of Contents

Installation

npm install feedback-popup
# or
yarn add feedback-popup
# or
pnpm add feedback-popup

Breaking changes in v4

  • DOM setup runs in init(), not in the constructor. The constructor only stores configuration; the first init() call creates or finds the widget root, injects inner placeholder elements if needed, renders the floating button, and binds events.
  • Calling init() more than once on the same instance is ignored (with a console warning).
  • Recommended integration is an explicit mount (selector string or HTMLElement) or no HTML at all (the library appends a root to document.body). Relying on a pre-placed .js-feedback-popup node in your markup still works in v4 but is deprecated and will be removed in a future major version.

Breaking changes in v5 (CSS theming)

These changes apply when you adopt the v5 stylesheet (namespaced theming). Bump your major version when you ship this CSS to consumers.

  • Theming is done via --feedback-* CSS variables on .feedback-popup (or any ancestor of the widget). You do not need to override :root for the popup look.
  • .btn, .control, and .spinner are scoped under .feedback-popup. Styles from this package no longer apply to generic .btn / .control / .spinner classes elsewhere on the page. If you relied on those global rules, add your own styles for those classes outside the widget.
  • Checkbox styling uses color-mix() for semi-transparent states. Use a browser that supports color-mix or override the --feedback-checkbox-* variables with solid colors.

Usage

Recommended: explicit mount

Place a single empty container where you want the widget to live (layout, sidebar, footer, etc.). You can use a CSS selector or pass the element directly (e.g. from a framework ref). Missing widget classes and data-html2canvas-ignore on that node are added for you when init() runs.

<body>
  <div id="main-body"><!-- page content --></div>
  <div id="feedback-root"></div>
  <script type="module">
    import FeedbackPopup from 'feedback-popup';

    const feedbackPopup = new FeedbackPopup({
      mount: '#feedback-root',
      widgetTitle: 'Send Feedback',
      title: 'Help Us Improve',
      snapshotBodyId: '#main-body',
      placeholderText: 'Tell us what you think...',
      endpointUrl: 'https://your-api.com/feedback'
    });

    feedbackPopup.init();
  </script>
</body>

With a direct element reference:

import FeedbackPopup from 'feedback-popup';

const root = document.getElementById('feedback-root');
const feedbackPopup = new FeedbackPopup({
  mount: root,
  snapshotBodyId: '#main-body'
});
feedbackPopup.init();

Zero markup: auto-inject on document.body

If you omit mount and there is no .js-feedback-popup in the document, init() creates a root element, adds the feedback-popup and js-feedback-popup classes, sets data-html2canvas-ignore, and appends it to document.body. This is ideal for quick demos; the widget usually appears at the end of the body.

import FeedbackPopup from 'feedback-popup';

const feedbackPopup = new FeedbackPopup({
  snapshotBodyId: '#main-body',
  endpointUrl: 'https://your-api.com/feedback'
});
feedbackPopup.init();

Legacy: pre-built .js-feedback-popup in HTML (deprecated)

If you already ship the old wrapper and inner placeholder divs, you can still omit mount and init() will use the first matching .js-feedback-popup. Migrate to mount or auto-inject when you can; this pattern will be removed in a future major release.

<div class="feedback-popup js-feedback-popup" data-html2canvas-ignore="true">
  <div class="js-feedback-popup-btn-show"></div>
  <div class="js-feedback-popup-content"></div>
  <div class="js-feedback-popup-confirmation"></div>
</div>

Styling & Theming

The widget root is always an element with class feedback-popup (added automatically by init() if missing). All public theme tokens are CSS custom properties prefixed with --feedback-, with defaults set on .feedback-popup in src/styles/variables.css.

Loading the CSS

The published npm package ships the JS library from dist/; stylesheet files live in the repo under src/styles/. Include them in your app (copy, submodule, or bundle main.css and its imports) the same way you do today. The entry file is src/styles/main.css.

How to override

Add rules that target the widget root (or a wrapper you pass as mount) and set variables:

.feedback-popup {
  --feedback-color-primary: #5c6bc0;
  --feedback-color-brand: #283593;
  --feedback-header-bg: var(--feedback-color-brand);
  --feedback-widget-button-bg: var(--feedback-color-primary);
  --feedback-widget-button-hover-bg: #3949ab;
}

Because variables inherit, you can also set them on a parent container if the widget is nested:

#feedback-root.feedback-popup,
#feedback-root .feedback-popup {
  --feedback-dialog-width: 36rem;
}

Variables reference (defaults in variables.css)

| Variable | Role | |----------|------| | Typography | | | --feedback-font-family | Font stack for widget UI | | --feedback-font-size-header | Modal title | | --feedback-font-size-body | Body / textarea / confirmation text | | --feedback-font-size-widget | Floating button label | | --feedback-font-size-screenshot-label | “Include a screenshot?” row | | --feedback-font-weight-header | Title weight | | --feedback-font-weight-body | Body weight | | --feedback-font-weight-label | Checkbox label weight | | --feedback-line-height-header | Title line height | | Core colors | | | --feedback-color-surface | White / surfaces | | --feedback-color-text | Main text | | --feedback-color-text-muted | Placeholder | | --feedback-color-brand | Brand / header | | --feedback-color-primary | Primary actions, widget button | | --feedback-color-secondary | Screenshot row background | | --feedback-color-on-primary | Text on primary-colored bars | | --feedback-color-on-brand | Text on header | | --feedback-color-disabled | Disabled / muted UI | | --feedback-color-link | Links in confirmation text | | --feedback-color-link-hover | Link hover | | Overlay | | | --feedback-overlay-bg | Backdrop behind modal | | --feedback-overlay-z-index | Stacking order | | --feedback-overlay-transition | Backdrop transition | | Floating button | | | --feedback-widget-offset-right | Horizontal inset from right | | --feedback-widget-offset-bottom | Offset from bottom | | --feedback-widget-width | Button strip width | | --feedback-widget-min-height | Min height | | --feedback-widget-padding-x / --feedback-widget-padding-y | Padding | | --feedback-widget-button-bg | Button background | | --feedback-widget-button-text | Button label color | | --feedback-widget-button-hover-bg | Hover background | | --feedback-widget-button-disabled-bg | Disabled background | | Dialog | | | --feedback-dialog-bg | Panel background | | --feedback-dialog-width | Panel width | | --feedback-dialog-max-height-offset | calc(100% - offset) on tall viewports | | --feedback-dialog-max-height-offset-mobile | Same under 575px width | | --feedback-dialog-border-radius | Panel and confirmation card corner radius | | Header | | | --feedback-header-bg | Header bar | | --feedback-header-text | Title color | | --feedback-header-height | Bar height | | --feedback-header-padding-x | Horizontal padding | | Textarea | | | --feedback-textarea-bg | Textarea area background | | --feedback-textarea-height | Textarea block height | | --feedback-textarea-padding-x / --feedback-textarea-padding-y | Inner padding | | Screenshot UI | | | --feedback-add-screenshot-bg | Blue bar behind checkbox | | --feedback-add-screenshot-text | Label color on that bar | | --feedback-add-screenshot-height | Row height | | --feedback-add-screenshot-padding | Row padding | | --feedback-screenshot-area-bg | Canvas preview area | | --feedback-screenshot-area-height | Preview height | | Footer | | | --feedback-footer-bg | Row behind Send/Cancel | | --feedback-footer-padding | Footer padding | | Confirmation card | | | --feedback-confirmation-bg | Thank-you card background | | --feedback-confirmation-width / --feedback-confirmation-height | Card size | | --feedback-confirmation-padding-x / --feedback-confirmation-padding-y | Card padding | | --feedback-confirmation-thank-you-margin-bottom | Space below thank-you line | | Dialog buttons | | | --feedback-button-radius | Border radius | | --feedback-button-confirm-bg / --feedback-button-confirm-border / --feedback-button-confirm-text | Send button | | --feedback-button-confirm-hover-bg / --feedback-button-confirm-hover-text | Send hover | | --feedback-button-cancel-bg / --feedback-button-cancel-border / --feedback-button-cancel-text | Cancel | | --feedback-button-cancel-hover-bg | Cancel hover | | --feedback-button-dialog-text / --feedback-button-dialog-font-size | Alternate dialog-style button (e.g. .btn-diolog) | | --feedback-button-padding-x / --feedback-button-padding-y | Action button padding | | --feedback-button-gap | Space between Send and Cancel | | --feedback-button-font-size | Button font size | | --feedback-button-transition | Button transitions | | --feedback-button-text-transform | e.g. uppercase | | Checkbox | | | --feedback-checkbox-label-font-size | Label size | | --feedback-checkbox-indicator-size | Box size | | --feedback-checkbox-indicator-border | Border color | | --feedback-checkbox-indicator-radius | Radius | | --feedback-checkbox-indicator-default / hover / checked / checked-hover / disabled | Indicator backgrounds (color-mix by default) | | --feedback-checkbox-check-color | Checkmark color | | --feedback-checkbox-check-disabled-border | Checkmark border when disabled | | Spinner | | | --feedback-spinner-size | Diameter | | --feedback-spinner-border-width | Ring thickness | | --feedback-spinner-track-color / --feedback-spinner-accent-color | Two-tone ring | | --feedback-spinner-animation-duration | Rotation speed |

Examples

Dark header and primary accent

.feedback-popup {
  --feedback-color-brand: #1a237e;
  --feedback-color-primary: #ff6f00;
  --feedback-header-bg: var(--feedback-color-brand);
  --feedback-widget-button-bg: var(--feedback-color-primary);
  --feedback-widget-button-hover-bg: #ff8f00;
  --feedback-button-confirm-bg: var(--feedback-color-primary);
  --feedback-button-confirm-border: var(--feedback-color-primary);
}

Wider dialog, more padding

.feedback-popup {
  --feedback-dialog-width: 40rem;
  --feedback-textarea-height: 24rem;
  --feedback-header-padding-x: 2rem;
  --feedback-footer-padding: 1.2rem;
}

Configuration Options

| Option | Type | Default | Description | |--------|------|---------|-------------| | mount | string | HTMLElement | (none) | Root element for the widget (selector or element). If omitted, the first .js-feedback-popup is used, or a new root is appended to document.body. | | widgetTitle | string | 'Feedback' | The title shown on the feedback button | | title | string | 'Send Feedback' | The title of the feedback popup | | snapshotBodyId | string | '#main-body' | CSS selector for the element to capture in the screenshot | | placeholderText | string | 'Enter your feedback here...' | Placeholder text for the feedback textarea | | endpointUrl | string | 'http://localhost:3005/api/feedback' | API endpoint to send feedback to |

API

Methods

  • init(): Initialize the feedback popup (DOM scaffold, button, event listeners). Safe to call once per instance.
  • showFeedbackModal(): Show the feedback popup
  • hideContentDiv(): Hide the feedback popup
  • createScreenshot(): Create a screenshot of the current page
  • sendData(): Send feedback data to the configured endpoint

Development

# Install dependencies
pnpm install

# Start development server
pnpm start

# Run tests
pnpm test

# Build for production
pnpm build

License

MIT

New Features

There is a TODO.md with the current plan of new features, updates etc... that are being checked off as I get to them. Submit a PR if you want to add any suggestions.

Contributing

Clone this project to get involved

[email protected]:TommyScribble/feedback-popup.git

Prerequisites

Node.js =22.14.0 must be installed. If you are using Volta this is already pinned.

Installation

  • Running pnpm i in the app's root directory will install everything you need for development.

Development Server

Dev API

This api sends the body of the request to the feedback folder. This is excluded by the gitignore and will be generated if it doesnt exist. To clean the folder run

    pnpm run clean-fedback

Testing

Vitest is used to test all functionality. To run all the tests run

    pnpm run test

Building

To test builds locally run

    pnpm run build

This will first delete and then build the output to the dist directory

pnpn run clean

will delete built resources.