@samletnorge/feedback-widget
v0.1.1
Published
Universal feedback widget that creates GitHub issues
Maintainers
Readme
💬 Universal Feedback Widget
A lightweight, framework-agnostic feedback widget that automatically creates GitHub discussions or GitHub issues. Works with any website - React, Vue, Svelte, plain HTML, or any other framework.
✨ Features
- 🎯 Zero Dependencies - Works without any external libraries
- 🌐 Universal Compatibility - Works with any framework or vanilla HTML
- 💬 GitHub Discussions - Creates threaded discussions (recommended)
- 🐛 GitHub Issues - Creates trackable issues for bugs/features
- 🎨 Flexible Theming - Inherit page styles, Tailwind CSS, or custom colors
- 📱 Responsive Design - Mobile-friendly with elegant vertical tab
- ⚡ Lightweight - Under 20KB minified and gzipped
- 🔧 Custom Triggers - Use your own buttons or the default tab
- 📝 Custom Forms - Bring your own form design
- 🚀 Programmatic API - Trigger modals via JavaScript
- ⌨️ Accessibility Ready - Full keyboard navigation and ARIA support
🚀 Quick Start
Option 1: CDN (Recommended)
Add these two lines to your HTML and you're done:
<!-- Include the widget -->
<script src="https://cdn.jsdelivr.net/npm/@samletnorge/feedback-widget@latest/dist/feedback-widget.min.js"></script>
<!-- GitHub Discussions (Recommended) -->
<feedback-widget
data-repo="your-username/your-repo"
data-token="your-github-token"
data-type="discussion"
data-category="feedback"
>
</feedback-widget>Option 2: NPM Install
npm install @samletnorge/feedback-widget<script src="node_modules/@samletnorge/feedback-widget/dist/feedback-widget.min.js"></script>
<feedback-widget data-repo="user/repo" data-token="token"></feedback-widget>💭 Discussions vs Issues
Choose the right GitHub feature for your feedback collection:
| Feature | GitHub Discussions | GitHub Issues |
|---------|-------------------|---------------|
| Best for | General feedback, questions, community input | Bug reports, feature requests, actionable items |
| Structure | Threaded conversations, organized by category | Linear comments, organized by labels |
| Workflow | Community-driven discussions | Project management, assignees, milestones |
| Configuration | data-type="discussion"data-category="feedback" | data-type="issue"data-labels="feedback,bug" |
⚙️ Configuration Reference
Core Options
| Attribute | Type | Default | Description |
|-----------|------|---------|-------------|
| data-repo | String | Required | GitHub repository (owner/repo) |
| data-token | String | Required | GitHub Personal Access Token |
| data-type | String | "discussion" | "discussion" or "issue" |
| data-category | String | "feedback" | Discussion category name |
| data-labels | String | "feedback" | Comma-separated issue labels |
| data-title | String | "Feedback" | Modal title |
Appearance & Behavior
| Attribute | Type | Default | Description |
|-----------|------|---------|-------------|
| data-position | String | "right" | "right", "left", "bottom-right", "bottom-left" |
| data-inherit-styling | Boolean | false | Use page CSS instead of inline styles |
| data-custom-trigger | String | null | CSS selector for custom trigger button |
| data-custom-form | String | null | CSS selector for custom form |
| data-theme | String | "light" | "light" or "dark" |
Theming Options
| Attribute | Type | Default | Description |
|-----------|------|---------|-------------|
| data-primary-color | String | "#007bff" | Primary color (hex/rgb) |
| data-background-color | String | "#ffffff" | Modal background color |
| data-text-color | String | "#333333" | Text color |
| data-border-color | String | "#dddddd" | Border color |
| data-border-radius | String | "8px" | Border radius |
| data-font-family | String | "system-ui, -apple-system, sans-serif" | Font family |
CSS Class Support
| Attribute | Type | Description |
|-----------|------|-------------|
| data-primary-color-class | String | CSS class for primary color (e.g., "bg-blue-600") |
| data-background-color-class | String | CSS class for background color |
| data-text-color-class | String | CSS class for text color |
| data-border-color-class | String | CSS class for border color |
🎨 Theming & Customization
1. Inherit Page Styles (Recommended)
Perfect integration with your existing design:
<!-- Enable inherit styling -->
<feedback-widget
data-repo="myuser/myrepo"
data-token="token"
data-inherit-styling="true"
>
</feedback-widget>Then add CSS to style the widget components:
/* Regular CSS */
.feedback-widget-modal {
background: white;
border: 1px solid #e5e7eb;
border-radius: 0.5rem;
box-shadow: 0 10px 25px rgba(0, 0, 0, 0.1);
padding: 1.5rem;
}
.feedback-widget-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 1.5rem;
}
.feedback-widget-title {
font-size: 1.25rem;
font-weight: 600;
color: #111827;
margin: 0;
}
.feedback-widget-input,
.feedback-widget-textarea {
width: 100%;
padding: 0.75rem;
border: 1px solid #d1d5db;
border-radius: 0.375rem;
background: white;
}
.feedback-widget-btn-primary {
background: #3b82f6;
color: white;
border: none;
padding: 0.5rem 1rem;
border-radius: 0.375rem;
cursor: pointer;
}2. Tailwind CSS Classes
<feedback-widget
data-primary-color-class="bg-blue-600"
data-background-color-class="bg-white dark:bg-gray-900"
data-text-color-class="text-gray-900 dark:text-white"
data-border-color-class="border-gray-200 dark:border-gray-700"
>
</feedback-widget>For Svelte/Vue with Tailwind:
<style>
/* Tailwind CSS classes */
:global(.feedback-widget-modal) {
@apply bg-white border border-gray-200 rounded-lg shadow-lg p-6;
}
:global(.feedback-widget-header) {
@apply flex justify-between items-center mb-6;
}
:global(.feedback-widget-title) {
@apply text-xl font-semibold text-gray-900 m-0;
}
:global(.feedback-widget-input),
:global(.feedback-widget-textarea) {
@apply w-full p-3 border border-gray-300 rounded-md bg-white text-gray-900 placeholder:text-gray-400 focus:outline-none focus:ring-2 focus:ring-blue-500;
}
:global(.feedback-widget-btn-primary) {
@apply bg-blue-600 text-white hover:bg-blue-700;
}
:global(.feedback-widget-btn-secondary) {
@apply bg-gray-100 text-gray-700 hover:bg-gray-200;
}
</style>3. Custom Colors & Positioning
<feedback-widget
data-primary-color="#8B5CF6"
data-background-color="#F8FAFC"
data-text-color="#1E293B"
data-border-radius="12px"
data-position="left"
data-theme="dark"
>
</feedback-widget>Available CSS Classes for Inherit Styling
| CSS Class | Element | Description |
|-----------|---------|-------------|
| .feedback-widget-modal | Modal container | Main modal wrapper |
| .feedback-widget-header | Header section | Contains title and close button |
| .feedback-widget-title | Modal title | H2 heading element |
| .feedback-widget-close-btn | Close button | X button in header |
| .feedback-widget-form | Form element | Main form container |
| .feedback-widget-field | Field wrapper | Contains label + input |
| .feedback-widget-label | Form labels | Label elements |
| .feedback-widget-input | Text inputs | Subject and email inputs |
| .feedback-widget-textarea | Textarea | Feedback message field |
| .feedback-widget-actions | Button container | Cancel and submit buttons |
| .feedback-widget-btn | Base button | Base class for all buttons |
| .feedback-widget-btn-primary | Submit button | Primary action button |
| .feedback-widget-btn-secondary | Cancel button | Secondary action button |
🎯 Custom Triggers & Forms
Custom Trigger Button
Use your own styled button instead of the default vertical tab:
<button id="my-feedback-btn">Give Feedback</button>
<feedback-widget
data-repo="myuser/myrepo"
data-token="token"
data-custom-trigger="#my-feedback-btn"
>
</feedback-widget>Programmatic API
// Simple helper function
window.openFeedbackWidget();
// Or dispatch custom event
document.dispatchEvent(new Event('feedback-widget-open'));
// Access widget directly
const widget = document.querySelector('feedback-widget')._feedbackWidgetInstance;
widget.openModal();Custom Form
Provide your own completely custom form:
<div id="custom-form" style="display: none;">
<form>
<input name="subject" placeholder="What's this about?" required>
<textarea name="feedback" placeholder="Tell us more..." required></textarea>
<input name="email" placeholder="Email (optional)">
<button type="submit">Send</button>
</form>
</div>
<feedback-widget
data-custom-form="#custom-form"
data-repo="myuser/myrepo"
data-token="token"
>
</feedback-widget>🔑 GitHub Token Setup
For GitHub Discussions
- Go to GitHub Settings > Developer settings > Personal access tokens
- Click "Generate new token (classic)"
- Give it a name like "Feedback Widget"
- Select scopes:
write:discussion(required for discussions) !! NB: This is why this is recommended. It only allows writing discussions, not whole repo
- Click "Generate token"
- Copy the token (starts with
github_pat_orghp_)
For GitHub Issues
Same steps as above, but you only need:
public_repo(for public repositories) orrepo(for private repos) for these i would recomend using a github finetuned token with only theissuesscope. but you need to be admin for that.
⚠️ Security Note: Never expose your token in client-side code for production. Consider using a serverless function or GitHub App for production deployments. THIS IS ALSO WHY I RECOMMEND USING TOKEN WITH ONLY write:discussion SCOPE or issues SCOPE.
🌟 Framework Examples
React/Next.js
import { useEffect } from 'react';
function App() {
useEffect(() => {
const script = document.createElement('script');
script.src = 'https://cdn.jsdelivr.net/npm/@samletnorge/feedback-widget@latest/dist/feedback-widget.min.js';
document.head.appendChild(script);
}, []);
return (
<div>
<h1>My React App</h1>
<feedback-widget
data-repo="myuser/myrepo"
data-token={process.env.REACT_APP_GITHUB_TOKEN}
data-type="discussion"
data-inherit-styling="true"
/>
</div>
);
}Vue.js
<template>
<div>
<h1>My Vue App</h1>
<feedback-widget
:data-repo="repo"
:data-token="token"
data-type="discussion"
data-category="general"
data-position="left"
/>
</div>
</template>
<script>
export default {
data() {
return {
repo: "myuser/myrepo",
token: process.env.VUE_APP_GITHUB_TOKEN
}
},
mounted() {
const script = document.createElement('script');
script.src = 'https://cdn.jsdelivr.net/npm/@samletnorge/feedback-widget@latest/dist/feedback-widget.min.js';
document.head.appendChild(script);
}
}
</script>Svelte/SvelteKit
<script>
import { onMount } from 'svelte';
onMount(() => {
const script = document.createElement('script');
script.src = 'https://cdn.jsdelivr.net/npm/@samletnorge/feedback-widget@latest/dist/feedback-widget.min.js';
document.head.appendChild(script);
});
</script>
<!-- CSS for custom styling -->
<style>
:global(.feedback-widget-modal) {
@apply bg-background border border-border rounded-lg;
}
</style>
<h1>My Svelte App</h1>
<feedback-widget
data-repo="myuser/myrepo"
data-token="token"
data-primary-color-class="bg-primary"
data-background-color-class="bg-background"
data-inherit-styling="true"
/>Angular
// app.component.ts
import { Component, OnInit } from '@angular/core';
@Component({
selector: 'app-root',
template: `
<feedback-widget
[attr.data-repo]="repo"
[attr.data-token]="token"
data-type="discussion"
data-inherit-styling="true">
</feedback-widget>
`
})
export class AppComponent implements OnInit {
repo = 'myuser/myrepo';
token = environment.githubToken;
ngOnInit() {
const script = document.createElement('script');
script.src = 'https://cdn.jsdelivr.net/npm/@samletnorge/feedback-widget@latest/dist/feedback-widget.min.js';
document.head.appendChild(script);
}
}Plain HTML
<!DOCTYPE html>
<html>
<head>
<title>My Website</title>
</head>
<body>
<h1>Welcome to my website!</h1>
<script src="https://cdn.jsdelivr.net/npm/@samletnorge/feedback-widget@latest/dist/feedback-widget.min.js"></script>
<feedback-widget
data-repo="myuser/myrepo"
data-token="github_pat_xxxxx"
data-type="discussion"
data-category="feedback"
></feedback-widget>
</body>
</html>📊 Generated Content
GitHub Discussions
Discussions are created with this format:
**Subject:** Great new feature idea
Hi! I love the new design, but I think it could use more contrast on the buttons for better accessibility.
---
Contact: [email protected]
---
Submitted via feedback widget
Page: https://mywebsite.com/dashboard
User Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7)...GitHub Issues
Issues are created with this format:
**Subject:** Bug report - Login not working
The login form doesn't submit when I click the button. I've tried multiple browsers.
---
Contact: [email protected]
---
Submitted via feedback widget
Page: https://mywebsite.com/login
User Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64)...🎯 Event Handling
Listen for feedback submissions:
document.addEventListener('feedback-submitted', (event) => {
console.log('Feedback received:', event.detail);
// { subject: "Bug report", feedback: "Login broken", email: "[email protected]" }
// Send to your analytics
gtag('event', 'feedback_submitted', {
'feedback_type': event.detail.subject ? 'detailed' : 'simple',
'has_email': !!event.detail.email
});
});
document.addEventListener('feedback-error', (event) => {
console.error('Feedback submission failed:', event.detail.error);
});
document.addEventListener('feedback-success', (event) => {
console.log('Feedback submitted successfully:', event.detail);
});🛠️ Development
Local Development
git clone https://github.com/samletnorge/feedback-widget.git
cd feedback-widget
pnpm install
pnpm run devVisit http://localhost:8080 to see the demo.
Build
pnpm run build # Creates dist/feedback-widget.min.js🤝 Contributing
- Fork the repository
- Create a feature branch:
git checkout -b feature/amazing-feature - Add a changelog when you do something significant (using changesets):
npx changeset- Follow the prompts to describe your changes
- This will create a new file in the
.changesetdirectory - You can add multiple changesets before committing
- Include the
.changeset/files in your commit
- Commit changes:
git commit -m 'Add amazing feature' - Push to branch:
git push origin feature/amazing-feature - Open a Pull Request
- Wait for review and address any feedback
- Once approved, your changes will be merged and included in the next release!
📝 License
MIT License - see LICENSE file for details.
🆘 Support
- Demo: Live Demo
- Documentation: GitHub Wiki
- Issues: GitHub Issues
- Discussions: GitHub Discussions
🌟 Show Your Support
If this widget helped your project, please give it a ⭐ on GitHub!
Made with ❤️ for the web community
