reference

every prop, every option.

<Remediate />

all props optional. omit endpoint and onSubmit and the widget renders but submissions go nowhere.

prop
what is it
endpoint
url to POST FormData to.
onSubmit
called on submit. receives blobs inline. if both endpoint and onSubmit are set, the POST runs first; onSubmit runs only on success.
onError
called when the POST fails.
metadata
merged verbatim into submission.metadata.
headers
extra headers on the POST. use a function for auth tokens that may refresh.
captureTypes
which capture modes to expose. defaults to all.
open
controlled open state. pair with onOpenChange.
onOpenChange
called when the user opens or closes the widget.
debug
log lifecycle events to the console.
messages
override any user-visible string.

<RemediateTrigger />

replace the default floating button with your own trigger.

import { Remediate, RemediateTrigger } from "remediate";

<Remediate endpoint="/api/feedback">
  <RemediateTrigger asChild>
    <button>report a bug</button>
  </RemediateTrigger>
</Remediate>

asChild (radix-style) merges props onto the child. omit it for the default button.

imperative api

import { remediate } from "remediate";

remediate.open();
remediate.close();
remediate.submit();   // submit the current draft

parseFeedback(req)

import { parseFeedback } from "remediate/server";

const { submission, files } = await parseFeedback(req);

req is a web Request. returns Promise<ParsedFeedback>. see payload.

throws on malformed multipart bodies. wrap in try/catch.

runtime support

runtimenotes
next.js app routerroute.ts exporting POST(req: Request)
next.js pages routeruse parseFeedbackPages(req, res)
remix / react routerfrom a loader/action
honoc.req.raw
expressuse parseFeedbackExpress(req)
fastifyuse the express adapter
cloudflare workersnative web Request
bun / denonative web Request
edge runtimestreamed multipart works on edge

cors

if your widget origin and endpoint origin differ, the browser will preflight. respond with:

return Response.json(
  { ok: true },
  {
    headers: {
      "Access-Control-Allow-Origin": "https://your-app.com",
      "Access-Control-Allow-Methods": "POST, OPTIONS",
      "Access-Control-Allow-Headers": "Content-Type, Authorization",
    },
  },
);

handle the OPTIONS preflight too.

csp

remediate needs:

media-src 'self' blob:
img-src 'self' data: blob:
connect-src 'self' <your-endpoint-origin>
worker-src 'self' blob:

worker-src only if you use video capture.

bundle

  • core: ~14kb gzipped
  • video capture: +8kb (lazy-loaded on first open)
  • voice capture: +2kb (lazy-loaded on first open)

"sideEffects": false. tree-shakes.

css

styles inject on mount under [data-remediate-widget]. the prefix is namespaced. no global resets, no tailwind reset interaction. override via:

[data-remediate-widget] { --rmd-accent: #ff5722; }

Made by Parth Patel