{"id":31710547,"url":"https://github.com/oneminch/nuxt-feedback","last_synced_at":"2025-10-09T00:28:29.937Z","repository":{"id":305727036,"uuid":"1009883089","full_name":"oneminch/Nuxt-Feedback","owner":"oneminch","description":"A customizable feedback widget for Nuxt apps","archived":false,"fork":false,"pushed_at":"2025-09-09T21:17:18.000Z","size":1568,"stargazers_count":15,"open_issues_count":10,"forks_count":1,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-09-11T13:21:01.999Z","etag":null,"topics":["feedback","feedback-widget","nuxt","nuxt-module"],"latest_commit_sha":null,"homepage":"https://nuxt-feedback.minch.dev/","language":"Vue","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/oneminch.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2025-06-27T22:15:09.000Z","updated_at":"2025-09-06T14:36:58.000Z","dependencies_parsed_at":"2025-07-21T18:54:08.353Z","dependency_job_id":"9f327bc8-c385-45ce-b2e4-a8b9c1633ccc","html_url":"https://github.com/oneminch/Nuxt-Feedback","commit_stats":null,"previous_names":["oneminch/nuxt-feedback-widget","oneminch/nuxt-feedback"],"tags_count":5,"template":false,"template_full_name":null,"purl":"pkg:github/oneminch/Nuxt-Feedback","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/oneminch%2FNuxt-Feedback","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/oneminch%2FNuxt-Feedback/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/oneminch%2FNuxt-Feedback/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/oneminch%2FNuxt-Feedback/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/oneminch","download_url":"https://codeload.github.com/oneminch/Nuxt-Feedback/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/oneminch%2FNuxt-Feedback/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":279000708,"owners_count":26082879,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-10-08T02:00:06.501Z","response_time":56,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["feedback","feedback-widget","nuxt","nuxt-module"],"created_at":"2025-10-09T00:28:28.043Z","updated_at":"2025-10-09T00:28:29.930Z","avatar_url":"https://github.com/oneminch.png","language":"Vue","funding_links":[],"categories":[],"sub_categories":[],"readme":"![Cover Image](/playground/public/cover.png)\n\n\u003cdiv align=\"center\"\u003e\n\n# Nuxt Feedback Widget\n\n[![npm version][npm-version-src]][npm-version-href]\n[![License][license-src]][license-href]\n[![Nuxt][nuxt-src]][nuxt-href]\n\n\u003c!--\n[![npm downloads][npm-downloads-src]][npm-downloads-href]\n[![code quality][code-quality-src]][code-quality-href]\n[![bundle size][bundle-size-src]][bundle-size-href]\n--\u003e\n\nA simple \u0026 customizable feedback widget for your Nuxt apps.\n\n[📖 Documentation](#table-of-contents) |\n[💻 Demo](https://nuxt-feedback.minch.dev)\n\n\u003c/div\u003e\n\n## Table of Contents\n\n- [Features](#features)\n- [Quick Setup](#quick-setup)\n- [Configuration](#configuration)\n  - [Module Options](#module-options)\n  - [Environment Variables](#environment-variables)\n- [Usage](#usage)\n  - [Basic Usage](#basic-usage)\n  - [Customizing the Widget](#customizing-the-widget)\n  - [Using the Composable](#using-the-composable)\n- [Submission Methods](#submission-methods)\n  - [Email (Resend)](#email-resend)\n  - [GitHub Issues](#github-issues)\n  - [Custom Endpoint](#custom-endpoint)\n- [Examples](#examples)\n  - [Different Styling Approaches](#different-styling-approaches)\n  - [Topic-specific Feedback](#topic-specific-feedback)\n  - [Programmatic Control](#programmatic-control)\n- [Known Issues](#known-issues)\n- [Troubleshooting](#troubleshooting)\n  - [Common Issues](#common-issues)\n  - [Error Handling](#error-handling)\n- [Contribution](#contribution)\n- [License](#license)\n\n## Features\n\n- 💚 Beautiful \u0026 accessible UI based on Shadcn-Vue \u0026 Tailwind CSS 4\n  - Built-in dark mode support with class (.dark)\n- 🔩 Customizable `\u003cFeedbackWidget /\u003e` component\n- 📲 Scope feedback to specific features/topics\n- 📧 Multiple submission methods supported:\n  - Email (via Resend)\n  - GitHub Issues\n  - Custom Handler\n- 🌟 Handy composable for controlling widget\n\nI recommend reading the [Known Issues](#known-issues) section before setting up the module.\n\n## Quick Setup\n\nAdd the module to your Nuxt application in one command:\n\n```bash\nnpx nuxt module add @minch/nuxt-feedback\n```\n\nTo add manually, install the `@minch/nuxt-feedback` package using your package manager of choice and add it to your `nuxt.config.ts`:\n\n```ts\nexport default defineNuxtConfig({\n  modules: [\"@minch/nuxt-feedback\"],\n\n  feedbackWidget: {\n    method: \"email\", // Required: Choose your submission method\n    siteName: \"My App\", // Optional: Default is \"Your Nuxt App\"\n  },\n});\n```\n\nDefine environment variables for your selected method. [Read more below](#environment-variables).\n\nThat's it! You can now start using `\u003cFeedbackWidget /\u003e` in your components.\n\n## Configuration\n\n### Module Options\n\nConfigure the module in your `nuxt.config.ts` under the `feedbackWidget` property:\n\n```ts\nexport default defineNuxtConfig({\n  modules: [\"@minch/nuxt-feedback\"],\n\n  feedbackWidget: {\n    method: \"email\", // Required: 'email' | 'github' | 'custom-endpoint'\n    siteName: \"My App\", // Optional: Used in emails and GitHub issues\n    customEndpoint: \"/api/custom-handler\", // Required only for 'custom-endpoint' method\n  },\n});\n```\n\n#### Module Options Reference\n\n| Option           | Type                                       | Required | Default           | Description                                                        |\n| ---------------- | ------------------------------------------ | -------- | ----------------- | ------------------------------------------------------------------ |\n| `method`         | `'email' \\| 'github' \\| 'custom-endpoint'` | ✅       | -                 | Feedback submission method                                         |\n| `siteName`       | `string`                                   | ❌       | `\"Your Nuxt App\"` | Site name used in feedback submissions                             |\n| `customEndpoint` | `string`                                   | ❌       | -                 | Custom endpoint path (required when method is `'custom-endpoint'`) |\n\n### Environment Variables\n\nDepending on your chosen method, add the required environment variables to your `runtimeConfig`:\n\n```ts\nexport default defineNuxtConfig({\n  // ... module config above\n\n  runtimeConfig: {\n    // For Email method (via Resend)\n    resendApiKey: process.env.RESEND_API_KEY,\n    resendFrom: process.env.RESEND_FROM_EMAIL,\n    resendTo: process.env.RESEND_TO_EMAIL,\n\n    // For GitHub method\n    githubToken: process.env.GITHUB_TOKEN,\n    githubRepo: process.env.GITHUB_REPO,\n    githubOwner: process.env.GITHUB_OWNER,\n  },\n});\n```\n\n#### Environment Variables Reference\n\n**Email Method (Resend)**\n\n- `RESEND_API_KEY`: Your Resend API key\n- `RESEND_FROM_EMAIL`: Email address to send from (must be verified in Resend)\n- `RESEND_TO_EMAIL`: Email address to receive feedback\n\n**GitHub Method**\n\n- `GITHUB_TOKEN`: GitHub personal access token with repo permissions\n- `GITHUB_REPO`: Repository name (e.g., \"my-project\")\n- `GITHUB_OWNER`: Repository owner username or organization\n\n## Usage\n\n### Basic Usage\n\nAdd the widget to your layout or page:\n\n```vue\n\u003ctemplate\u003e\n  \u003cdiv\u003e\n    \u003c!-- Your content --\u003e\n    \u003cFeedbackWidget /\u003e\n  \u003c/div\u003e\n\u003c/template\u003e\n```\n\n### Customizing the Widget\n\nThe `\u003cFeedbackWidget /\u003e` component accepts several props for customization:\n\n```vue\n\u003ctemplate\u003e\n  \u003cFeedbackWidget\n    title=\"Send us feedback!\"\n    description=\"We value your thoughts and suggestions.\"\n    trigger-label=\"💬 Feedback\"\n    trigger-class=\"bg-blue-500 hover:bg-blue-600 text-white px-4 py-2 rounded\"\n    submit-label=\"Send Feedback\"\n    with-topics\n    :topics=\"['General', 'Bug Report', 'Feature Request', 'UI/UX']\"\n  /\u003e\n\u003c/template\u003e\n```\n\n#### Component Props Reference\n\n```ts\ninterface FeedbackUIProps {\n  title?: string;\n  description?: string;\n  triggerLabel?: string;\n  triggerClass?: string;\n  submitLabel?: string;\n  withTopics?: boolean;\n  topics?: string[];\n}\n```\n\n| Prop           | Type       | Default                                                 | Description                                   |\n| -------------- | ---------- | ------------------------------------------------------- | --------------------------------------------- |\n| `title`        | `string`   | `\"Feedback\"`                                            | Title displayed in the feedback modal         |\n| `description`  | `string`   | `\"Tell us what you think.\"`                             | Description text in the modal                 |\n| `triggerLabel` | `string`   | `\"Feedback\"`                                            | Text for the trigger button                   |\n| `triggerClass` | `string`   | `\"\"`                                                    | Additional CSS classes for the trigger button |\n| `submitLabel`  | `string`   | `\"Submit\"`                                              | Text for the submit button                    |\n| `withTopics`   | `boolean`  | `true`                                                  | Whether to show the topics selector           |\n| `topics`       | `string[]` | `[\"General Feedback\", \"Bug Report\", \"Feature Request\"]` | Array of available feedback topics            |\n\n### Using the Composable\n\nControl the widget programmatically using the `useFeedbackWidget` composable:\n\n```vue\n\u003cscript setup lang=\"ts\"\u003e\nconst { isOpen, openWidget, closeWidget } = useFeedbackWidget();\n\n// Open widget programmatically\nfunction handleButtonClick() {\n  openWidget();\n}\n\u003c/script\u003e\n\n\u003ctemplate\u003e\n  \u003cdiv\u003e\n    \u003cbutton @click=\"handleButtonClick\"\u003eGive Feedback 💝\u003c/button\u003e\n\n    \u003c!-- Widget state --\u003e\n    \u003cp v-if=\"isOpen\"\u003eWidget is currently open\u003c/p\u003e\n  \u003c/div\u003e\n\u003c/template\u003e\n```\n\n\u003e **Note**\n\u003e\n\u003e You still need to add the `\u003cFeedbackWidget /\u003e` component to your app somewhere. If you would like to hide the default trigger and programmatically toggle the widget using your means, you can hide it by passing styles to the `triggerClass` prop.\n\n#### Composable API\n\n```ts\ninterface UseFeedbackWidget {\n  isOpen: Ref\u003cboolean, boolean\u003e; // Current widget state\n  openWidget: () =\u003e void; // Open the widget\n  closeWidget: () =\u003e void; // Close the widget\n\n  // For Internal Use\n  isWidgetMounted: Readonly\u003cRef\u003cboolean, boolean\u003e\u003e;\n  registerWidget: () =\u003e void;\n  unregisterWidget: () =\u003e void;\n}\n```\n\n## Submission Methods\n\n### Email (Resend)\n\nSends feedback via email using the Resend service.\n\n**Setup:**\n\n1. Sign up for [Resend](https://resend.com)\n2. Get your API key and verify your domain\n3. Set environment variables:\n\n```env\nRESEND_API_KEY=your_api_key\nRESEND_FROM_EMAIL=feedback@yourdomain.com\nRESEND_TO_EMAIL=admin@yourdomain.com\n```\n\nYou can learn more about Resend from [their docs](https://resend.com/docs)\n\n**Configuration:**\n\n```ts\n// nuxt.config.ts\nexport default defineNuxtConfig({\n  modules: [\"@minch/nuxt-feedback\"],\n\n  feedbackWidget: {\n    method: \"email\",\n    siteName: \"My Awesome App\"\n  }\n\n  runtimeConfig: {\n    resendApiKey: process.env.RESEND_API_KEY,\n    resendFrom: process.env.RESEND_FROM_EMAIL,\n    resendTo: process.env.RESEND_TO_EMAIL\n  }\n});\n```\n\n### GitHub Issues\n\nCreates GitHub issues for each feedback submission.\n\n**Setup:**\n\n1. Create a GitHub personal access token (PAT) with read and write permissions to a repo of your choice.\n2. Set environment variables:\n\n```env\nGITHUB_TOKEN=your_github_token\nGITHUB_REPO=your-repo-name # Can be a private repo\nGITHUB_OWNER=your-username-or-org\n```\n\n**Configuration:**\n\n```ts\n// nuxt.config.ts\nexport default defineNuxtConfig({\n  modules: [\"@minch/nuxt-feedback\"],\n\n  feedbackWidget: {\n    method: \"github\",\n    siteName: \"My Awesome App\"\n  }\n\n  runtimeConfig: {\n    githubToken: process.env.GITHUB_TOKEN,\n    githubRepo: process.env.GITHUB_REPO,\n    githubOwner: process.env.GITHUB_OWNER\n  }\n});\n```\n\n### Custom Endpoint\n\nForwards feedback to your own API endpoint for custom processing.\n\n**Configuration:**\n\n```ts\n// nuxt.config.ts\nexport default defineNuxtConfig({\n  modules: [\"@minch/nuxt-feedback\"],\n\n  feedbackWidget: {\n    method: \"custom-endpoint\",\n    customEndpoint: \"/api/my-custom-handler\",\n    siteName: \"My Awesome App\",\n  },\n});\n```\n\n**Feedback Data Structure:**\n\n```ts\ninterface FeedbackDataType {\n  topic: string; // Selected topic\n  reaction: string; // Feedback reaction\n  message: string; // User's optional message\n  siteName: string; // Your configured site name\n  metadata: {\n    route: {\n      fullPath: string;\n      hash: string;\n      query: LocationQuery;\n      name: RouteRecordNameGeneric;\n      path: string;\n      redirectedFrom: RouteLocationGeneric | undefined;\n    };\n    time: {\n      timestamp: string; // ISO string\n      timezone: string; // User's timezone\n    };\n  };\n}\n```\n\n\u003e **Imporant:** The feedback data is forwarded as is to your custom endpoint. Since user input can't be trusted, you'll need to implement some form of sanitization in your endpoint.\n\n**Example Custom Handler:**\n\n```ts\n// ~/server/api/my-custom-handler.ts\nexport default defineEventHandler(async (event) =\u003e {\n  try {\n    const rawFeedback = await readBody(event);\n\n    // Sanitize input\n    const feedback = sanitizer(rawFeedback);\n\n    // Save to database\n    await db.insert(feedback);\n\n    // Send to analytics\n    await $fetch(\"/api/analytics\", {\n      method: \"POST\",\n      body: {\n        event: \"feedback_submitted\",\n        properties: {\n          topic: feedback.topic,\n          route: feedback.metadata.route.path,\n        },\n      },\n    });\n\n    return { success: true };\n  } catch (error) {\n    throw createError({\n      statusCode: 500,\n      statusMessage: \"Failed to process feedback\",\n    });\n  }\n});\n```\n\n\u003e **Note**\n\u003e\n\u003e Your server route doesn't need to return anything.\n\u003e\n\u003e All error is handled at the default endpoint that sends the request to your custom endpoint. When an error occurs in your endpoint, it's a good idea to either return or throw the error. That way the appropriate success/failure messages will be displayed to the user.\n\n## Examples\n\n### Different Styling Approaches\n\n**Minimal trigger:**\n\n```vue\n\u003ctemplate\u003e\n  \u003cFeedbackWidget\n    trigger-label=\"?\"\n    trigger-class=\"fixed bottom-4 right-4 w-12 h-12 rounded-full bg-blue-500 text-white shadow-lg hover:bg-blue-600 transition-colors\"\n  /\u003e\n\u003c/template\u003e\n```\n\n**Integrated in navigation:**\n\n```vue\n\u003ctemplate\u003e\n  \u003cFeedbackWidget\n    trigger-label=\"Feedback\"\n    trigger-class=\"nav-link\"\n    title=\"Help us improve\"\n    description=\"Your feedback helps us build a better product\"\n  /\u003e\n\u003c/template\u003e\n```\n\n### Topic-specific Feedback\n\n```vue\n\u003ctemplate\u003e\n  \u003cFeedbackWidget\n    :topics=\"['Account', 'AI', 'Billing', 'Documentation', 'Observability']\"\n    with-topics\n    title=\"Report an Issue\"\n    description=\"Let us know what's not working\"\n  /\u003e\n\u003c/template\u003e\n```\n\n### Programmatic Control\n\n\u003e This approach currently has some issues.\n\n```vue\n\u003cscript setup lang=\"ts\"\u003e\nconst { openWidget } = useFeedbackWidget();\n\n// Show feedback after user completes action\nasync function handleTaskComplete() {\n  await saveUserProgress();\n\n  // Prompt for feedback\n  setTimeout(() =\u003e {\n    openWidget();\n  }, 1000);\n}\n\u003c/script\u003e\n```\n\n## Known Issues\n\nA list of issues I have noticed and I'm working on a fix for:\n\n- The widget doesn't currently work on fully static sites such as ones deployed to GitHub Pages as it requires a server for submitting feedback.\n- The `useFeedbackWidget` composable doesn't detect the `\u003cFeedbackWidget /\u003e` component properly.\n\n## Troubleshooting\n\nFeel free to open an issue if you are not able to resolve an issue.\n\n### Common Issues\n\n**Widget not appearing:**\n\n- Ensure the module is properly added to your `nuxt.config.ts`\n- Check that you've set a valid `method` in your configuration\n- Verify the component is imported (it should be auto-imported) and added to your app\n\n**Styling conflicts:**\n\n- If you have custom Tailwind config, ensure compatibility\n- Use `triggerClass` prop to override default styling\n\n**Submission failures:**\n\n- Check your environment variables are set correctly\n- Verify API keys and tokens have proper permissions\n- Check the browser console and server logs for errors\n\n**Multiple widgets appearing:**\n\n- Make sure you only have one `\u003cFeedbackWidget /\u003e` component per page. This issue will likely be resolved in a future release.\n\n**Method not found:**\n\n- Ensure your `method` is one of: `'email'`, `'github'`, or `'custom-endpoint'`\n- Check spelling in your configuration\n\n### Error Handling\n\nThe module includes built-in error handling:\n\n- Invalid configurations show warnings in development\n- Failed submissions display user-friendly error messages\n- Server errors are logged for debugging\n\nIf you encounter issues, check:\n\n1. Browser developer console\n2. Server logs\n3. Network tab for API request failures\n\n## Contribution\n\n\u003cdetails\u003e\n  \u003csummary\u003eLocal development\u003c/summary\u003e\n  \n  ```bash\n  # Install dependencies\n  pnpm install\n  \n  # Generate type stubs\n  pnpm run dev:prepare\n  \n  # Develop with the playground\n  pnpm run dev\n  \n  # Build the playground\n  pnpm run dev:build\n  \n  # Run ESLint\n  pnpm run lint\n  \n  # Run Vitest\n  pnpm run test\n  pnpm run test:watch\n  \n  # Release new version\n  pnpm run release\n  ```\n\u003c/details\u003e\n\n## License\n\n[MIT](/LICENSE)\n\n© 2025-present [Dawit Urgessa](https://minch.dev)\n\n\u003c!-- Badges --\u003e\n\n[npm-version-src]: https://img.shields.io/npm/v/@minch/nuxt-feedback/latest.svg?style=flat\u0026colorA=020420\u0026colorB=00DC82\n[npm-version-href]: https://npmjs.com/package/@minch/nuxt-feedback\n[license-src]: https://img.shields.io/npm/l/@minch/nuxt-feedback.svg?style=flat\u0026colorA=020420\u0026colorB=00DC82\n[license-href]: https://npmjs.com/package/@minch/nuxt-feedback\n[nuxt-src]: https://img.shields.io/badge/Nuxt-020420?logo=nuxt\n[nuxt-href]: https://nuxt.com\n\n\u003c!--\n[npm-downloads-href]: https://npm.chart.dev/nuxt-feedback-widget\n[npm-downloads-src]: https://img.shields.io/npm/dm/nuxt-feedback-widget.svg?style=flat\u0026colorA=020420\u0026colorB=00DC82\n--\u003e\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Foneminch%2Fnuxt-feedback","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Foneminch%2Fnuxt-feedback","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Foneminch%2Fnuxt-feedback/lists"}