<gh-feedback>Add a feedback button to any website. Files GitHub Issues.
| Style | |
| Icon | |
| Size | |
| Color | |
| Border | |
| Position (FAB only) |
| Theme | |
| Color | |
| Categories |
Copy gh-feedback.js into your project and add to your HTML:
<script type="module" src="gh-feedback.js"></script>
<gh-feedback
repo="https://github.com/you/repo"
endpoint="https://your-worker.workers.dev/feedback"
></gh-feedback>
A hosted copy is also available as a convenience:
<script type="module" src="https://gh-feedback.synapticnoise.com/gh-feedback.js"></script>
The component needs a backend to securely file GitHub Issues (so your token stays server-side). See Proxy Setup below, or use any backend that accepts the JSON payload.
| Attribute | Type | Default | Description |
|---|---|---|---|
repo |
string | -- | GitHub repository URL or owner/repo format. Required. |
endpoint |
string | -- | URL of the proxy endpoint (recommended). Component POSTs JSON here. |
token |
string | -- | GitHub PAT for direct mode. Exposed in page source -- use proxy mode for public sites. |
trigger |
string | fab |
Trigger style: fab (floating action button), button (inline button), link (text link), or none (no trigger; open programmatically). |
icon |
string | memo |
Icon: chat, bug, megaphone, lightbulb, pencil, flag, memo, none. |
size |
string | md |
Size: sm, md, lg, or a number for pixel size (e.g. 40). |
color |
string | #238636 |
Primary color (hex). Sets the FAB, button, and accent color. |
position |
string | bottom-right |
FAB corner position: bottom-right, bottom-left, top-right, top-left. Only applies when trigger="fab". |
theme |
string | light |
Popup color theme: light or dark. |
labels |
string | -- | Comma-separated labels added to every issue (e.g. "feedback,ui"). |
button-text |
string | -- | Text shown on the trigger. For FAB, makes it pill-shaped. |
show-severity |
boolean | -- | When present, shows a severity selector (Low / Medium / High / Critical) for bug reports. |
types |
string | bug,feature,question |
Comma-separated list of feedback types to show. Available: bug, feature, question, ui, docs, performance. |
border-color |
string | -- | Border color on the trigger element. |
border-width |
string | -- | Border width in pixels on the trigger element. |
border-radius |
string | -- | Border radius in pixels on the trigger element (overrides default). |
popup-color |
string | #238636 |
Accent color used inside the popup (e.g. submit button). Defaults to the primary color. |
no-type-icons |
boolean | -- | When present, hides the emoji icons next to feedback type names in the popup. |
The proxy keeps your GitHub token on the server. Users never see it.
Copy the worker/ directory from this repo into your project, or start fresh:
mkdir gh-feedback-worker && cd gh-feedback-worker
cp -r /path/to/gh-feedback/worker/* .
npm init -y
Create a fine-grained Personal Access Token:
gh-feedback-proxyThen store it as a Wrangler secret:
npx wrangler secret put GITHUB_TOKEN
# Paste the token when prompted
Open worker/wrangler.toml and set these two values:
GITHUB_REPO — change "owner/repo" to your GitHub repository (e.g., "acme/webapp")ALLOWED_ORIGINS — change "*" to your website's URL (e.g., "https://your-site.com"). During development, include localhost too: "https://your-site.com,http://localhost:3000". The default * allows any site — restrict before going livecd worker
npx wrangler deploy
Wrangler prints the worker URL, e.g., https://gh-feedback-proxy.your-account.workers.dev.
<gh-feedback repo="https://github.com/you/repo" endpoint="https://gh-feedback-proxy.your-account.workers.dev/feedback"></gh-feedback>
curl -X POST https://gh-feedback-proxy.your-account.workers.dev/feedback \
-H "Content-Type: application/json" \
-d '{"title": "Test issue from curl", "type": "bug"}'
You should get back {"issueNumber": ..., "issueUrl": "..."} and see the issue in your GitHub repo.
Multi-repo note: The worker always files issues to the repo configured in GITHUB_REPO. To file to multiple repos, deploy one worker per repo.
The component POSTs JSON to any URL. The worker/ template is for Cloudflare Workers, but any backend works. The contract:
POST { title, type, severity?, description, labels?, repo?, context? }
--> 201 { issueNumber, issueUrl }
--> 4xx/5xx { error: "message" }
Your backend receives this JSON, creates a GitHub Issue using a server-side token, and returns the result. The key requirement is that the endpoint holds the GitHub token server-side -- it never reaches the browser.
Any of these work:
api/feedback.js with GITHUB_TOKEN env varnetlify/functions/feedback.jsmain.ts fileThe Cloudflare Worker in worker/ is a good reference implementation (~80 lines). Adapt it to your platform.
If you don't want to set up a proxy, you can pass a GitHub token directly:
<gh-feedback repo="https://github.com/you/repo" token="ghp_yourTokenHere"></gh-feedback>
| Event | Detail | Cancelable | Description |
|---|---|---|---|
gh-feedback:submit |
{ title, type, description, labels, repo, severity? } |
Yes | Fires before submission. Call preventDefault() to cancel. |
gh-feedback:filed |
{ issueNumber, issueUrl } |
No | Fires after issue is successfully created. |
document.querySelector('gh-feedback')
.addEventListener('gh-feedback:filed', (e) => {
console.log(`Issue #${e.detail.issueNumber}: ${e.detail.issueUrl}`);
});
Set the getContext property to a function that returns an object. The data is attached to the issue body in a collapsible details section.
const fb = document.querySelector('gh-feedback');
fb.getContext = () => ({
url: location.href,
viewport: `${innerWidth}x${innerHeight}`,
userAgent: navigator.userAgent,
timestamp: new Date().toISOString()
});
For fine-grained control beyond the color attribute, override CSS custom properties on the gh-feedback element:
| Property | Light Default | Dark Default |
|---|---|---|
--gh-feedback-primary | #238636 | #238636 |
--gh-feedback-primary-hover | #2ea043 | #2ea043 |
--gh-feedback-bg | #ffffff | #1c2128 |
--gh-feedback-text | #1f2328 | #e6edf3 |
--gh-feedback-border | #d1d9e0 | #444c56 |
--gh-feedback-input-bg | #f6f8fa | #22272e |
--gh-feedback-error | #d1242f | #d1242f |
--gh-feedback-success | #238636 | #238636 |
--gh-feedback-fab-bg | (primary) | (primary) |
--gh-feedback-fab-text | #ffffff | #ffffff |
<style>
gh-feedback {
--gh-feedback-primary: #6f42c1;
--gh-feedback-primary-hover: #8250df;
}
</style>
<gh-feedback repo="https://github.com/you/repo" endpoint="..." theme="dark"></gh-feedback>
Proxy mode (recommended): Your GitHub token stays on the server. The browser only communicates with your worker endpoint.
Direct mode: The token is in the HTML source. Only for internal tools or pages behind auth.
If your site uses a strict Content Security Policy, add the proxy endpoint to connect-src:
Content-Security-Policy: connect-src 'self' https://your-worker.workers.dev;
Shadow DOM <style> elements are CSP-exempt in modern browsers, so no style-src changes are needed.
Run the unit tests (worker):
npm install
npm test
Run the Playwright E2E tests:
npx playwright install --with-deps chromium
npx playwright test
Run all tests:
npm run test:all
MIT -- use it anywhere.