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

@saas-maker/feedback

v0.4.0

Published

Backend-free React feedback widget with screenshots and page-element context.

Readme

@saas-maker/feedback

A backend-free React feedback widget with optional screenshots and Pinpoint page-element context. The package renders the interface; your application owns the destination, storage, and retention.

Install

pnpm add @saas-maker/feedback

Quick start: callback

import { FeedbackWidget } from '@saas-maker/feedback'
import '@saas-maker/feedback/dist/index.css'

export function AppFeedback() {
  return (
    <FeedbackWidget
      onSubmit={async (feedback) => {
        await fetch('/api/feedback', {
          method: 'POST',
          headers: { 'content-type': 'application/json' },
          body: JSON.stringify({
            ...feedback,
            screenshot: undefined,
          }),
        })

        // feedback.screenshot is the original File. Upload it separately if needed.
      }}
    />
  )
}

onSubmit may send an email, create an issue, call an authenticated API, or write to any system your product already uses.

Quick start: ingestion URL

Use ingestionUrl when your caller-owned endpoint accepts the package's stable multipart contract:

import { FeedbackWidget } from '@saas-maker/feedback'
import '@saas-maker/feedback/dist/index.css'

export function AppFeedback() {
  return <FeedbackWidget ingestionUrl="/api/feedback" />
}

The destination may be a relative path or an absolute HTTP(S) URL. Cross-origin destinations must allow the request through CORS. The package sends no cookies, authorization, project key, or other credentials. Use onSubmit instead when the destination requires authentication or a different payload.

Configure exactly one of onSubmit and ingestionUrl.

Endpoint contract

URL mode sends one POST with a FormData body:

| Field | Value | |---|---| | feedback | JSON string containing the submission without screenshot | | screenshot | Original image file when supplied; otherwise omitted |

The widget displays success only after a 2xx response. A network failure or non-2xx response keeps the form data available and shows an error. Requests are never retried automatically.

Payload

interface FeedbackSubmission {
  type: 'bug' | 'feature' | 'feedback'
  title: string
  description: string
  email?: string
  name?: string
  anchor?: {
    selector: string
    tag: string | null
    text: string
    source: string | null
    url: string
  }
  screenshot?: File
  page: {
    url: string
    title: string
  }
}

The success state appears only after the selected destination succeeds. Callback errors and URL ingestion failures are shown in the form.

Props

| Prop | Type | Default | Description | |---|---|---|---| | onSubmit | (feedback) => void \| Promise<void> | XOR | Product-owned submission callback | | ingestionUrl | string | XOR | Caller-owned HTTP(S) multipart endpoint | | userEmail | string | — | Pre-filled email | | userName | string | — | Pre-filled name | | requireEmail | boolean | false | Require an email before submission | | types | FeedbackType[] | bug, feature, feedback | Allowed types | | position | bottom-right or bottom-left | bottom-right | Trigger position | | theme | light, dark, or auto | auto | Color theme | | accentColor | string | #1464ff | Accent color | | triggerText | string | Feedback | Trigger label | | enablePointing | boolean | true | Enable Pinpoint |

Pinpoint

Pinpoint lets the user click a page element. The submission receives a selector, visible text, page path, and source hint when React development metadata or a data-source attribute is available. Nothing is submitted until the user explicitly sends the form.

Screenshots

JPEG, PNG, GIF, and WebP files up to 5 MB can be attached. Callback mode receives the original File; URL mode uploads it in the screenshot multipart field. The package does not retain it.

Privacy

Your product controls the endpoint, authentication, destination, and retention policy. Disclose collected feedback, identity fields, screenshots, and page-element context in your own privacy policy where appropriate. Never place a secret in client-side widget configuration.

Compatibility

  • React 18 and React 19
  • Modern browsers with File, URL.createObjectURL, and DOM APIs
  • Client-rendered components

License

MIT