Skip to content
WorkShippedPublished on npm, MIT, pre-1.0 (0.2.1)

react-bug-report

An accessible, provider-neutral React bug-report form, dialog and widget, published on npm.

Overview

Drop-in bug reporting that initialises nothing on its own: the host app chooses where reports go (HTTP, Sentry, or any callback), whether screenshots are captured, and what context is included. Privacy is the default.

Role
Sole author and maintainer
Timeframe
Aug 13 to 15, 2026 (0.1.0 to 0.2.1)
Status
Published, MIT, pre-1.0 (0.2.1)
In use
Adopted in Diwalco's web app

Stack

  • React 18.2 / 19
  • TypeScript (strict)
  • tsup (ESM + CJS)
  • Vitest
  • Testing Library
  • axe-core
  • Playwright
  • Redocly (OpenAPI 3.1)

Context

Apps need an in-app “report a bug” flow that doesn't lock them into one vendor or silently collect data. I first hand-built a Sentry-only feedback dialog for Diwalco, then wrote this general, provider-neutral package and adopted it back into Diwalco's web app, replacing ~580 lines of hand-rolled feedback UI.

Try it

This is the published package, loaded only when you open it. Reports go to a local callback, so nothing leaves your browser; after sending, you can inspect exactly what a transport would have received.

Try anonymous mode, the details toggle, or a screenshot.

What it does

  • Three components: a standalone form, a native <dialog> modal, and a floating widget.
  • A report model with message, severity, steps, expected and actual behaviour, optional contact, opt-in technical context and one screenshot, in a versioned envelope with a client-generated ID.
  • Anonymous mode guarantees contact details are omitted.
  • Transports: HTTP multipart (timeouts, AbortSignal, RFC 7807 problem details, Retry-After, typed retryable errors); a Sentry adapter that wraps the host's own sendFeedback with no Sentry dependency bundled; or any callback.
  • Pluggable screenshot capture (DOM or getDisplayMedia) with bounded canvas sizes.
  • A published server contract: an OpenAPI 3.1 spec for POST /v1/bug-reports.

Deep dives

A privacy leak hidden in a vendor default

In 0.2.1: with technical context off, Sentry still received the reporter's live URL, because its sendFeedback back-fills url when the key is absent. The fix always states the key (an explicit undefined overrides the default), with an internal type so the public type stays assignable to Sentry's. Regression-tested.

Keeping the report out of its own screenshot

In 0.2.0: screen capture photographed the open dialog, and closing it first would lose the draft. Providers can now declare requiresHiddenUi: the UI hides by visibility (nothing unmounts), waits for a bounded next paint (a 100 ms deadline for background tabs), captures, and returns. Shipped as a minor version because it changes default behaviour.

Accessibility beyond the basics

A native modal with Escape; a backdrop that only closes when both pointer-down and pointer-up land on it, so a text-selection drag never discards a draft; a fully keyboard-operable severity listbox; linked validation errors; a polite live region with focus moved to the success heading; prefers-reduced-motion and forced-colours support; and an axe-core scan in tests.

Cross-bundle error identity

Error classes are registered on a global symbol, so instanceof works across separately bundled ESM and CJS entry points.

Numbers

Runtime dependencies
0
Entry points: a React-free core, two transports, two capture providers, and the root
6
Unit tests (static count), plus 9 Playwright end-to-end tests run across 3 browsers
70+
Lines of hand-rolled feedback UI it replaced in Diwalco's web app
~580

Limits and roadmap

  • No CI yet; the quality gate is the publish script.
  • No manual screen-reader pass recorded; keyboard and axe-core tested.
  • Bundle size not yet tracked in the repo.
Next case studyDiwalcoFounding engineer on a private family-tree and family-feed platform, from the API and data model to deploy-and-rollback.