Skip to content

TommyScribble/feedback-popup

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

199 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

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

git@github.com: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.

About

A simple to use popup for collecting feedback from users about the sites that they are using. It captures a screenshot of the current users browser, the users OS and browser name + versions and also a personal message from the user. This is all then emailed to an endpoint.

Topics

Resources

License

Stars

Watchers

Forks

Packages

 
 
 

Contributors