Feedback Control Layer
The feedback control layer provides a comprehensive, user-friendly feedback collection system for DCC-BS Nuxt applications. It enables users to submit feedback directly from your application, with support for ratings, file attachments, and seamless integration with GitHub issues.
Overview
The feedback control layer includes:
FeedbackControlComponent - A ready-to-use Vue component for feedback collection- API Integration - Automatically creates GitHub issues from user feedback
- File Upload Support - Allows users to attach files (screenshots, logs, etc.)
- Rating System - Emoji-based rating for quick sentiment analysis
- Form Validation - Built-in validation using Zod schemas
- Internationalization - Full i18n support for multi-language applications
- Responsive Design - Mobile-friendly interface with smooth animations
How It Works
The feedback control layer provides a floating feedback button that opens a comprehensive feedback form. When users submit feedback:
- User opens feedback → Clicks the floating button
- Fills in the form → Selects rating, writes message, provides email, adds attachments
- Form validation → Client-side validation ensures data integrity
- Submission to API → Form data sent to
/api/feedbackendpoint - GitHub integration → Feedback is automatically converted to a GitHub issue
- Success feedback → User sees confirmation with animation
- Form reset → Form resets after 3 seconds, ready for next feedback
Architecture
Your Nuxt App
↓
FeedbackControl Component
↓
/api/feedback endpoint
↓
GitHub API
↓
GitHub Issue createdQuick Start
1. Add Feedback Control Layer to Your Project
In your nuxt.config.ts:
export default defineNuxtConfig({
extends: [
['github:DCC-BS/nuxt-layers/feedback-control', { install: true }]
]
})2. Configure GitHub Integration
** Local ** Set the required environment variables in your .env file:
| Variable | Required | Description | Example |
|---|---|---|---|
FEEDBACK_REPO | Yes | Name of the GitHub repository for feedback issues | Feedback |
FEEDBACK_REPO_OWNER | Yes | GitHub organization or username that owns the repository | DCC-BS |
FEEDBACK_PROJECT | Yes | GitHub project name for organization | Test |
FEEDBACK_GITHUB_TOKEN | Yes | Personal access token with content and issues read & write permissions | ghp_xxxxxxxxxxxx |
TIP
To set the env variables at runtime prefix the variables with NUXT_ for example NUXT_FEEDBACK_REPO
GitHub Token Setup
To create a GitHub token for the feedback control:
- Go to Settings → Developer settings → Personal access tokens → Fine-grained tokens
- Click Generate new token
- Give it a descriptive name (e.g., "Feedback Control")
- Select only repositories and add you repository
- Select the following permissions:
- ✅
contents(read and write content) - ✅
issues(read and write issues)
- ✅
- Click Generate token
- Copy the token immediately (you won't see it again)
** Production ** To set the variables at runtime and not build time you need to prefix the variables with NUXT_:
NUXT_FEEDBACK_REPO=Feedback # Repository name where the issue will be created
NUXT_FEEDBACK_REPO_OWNER=DCC-BS # Repository owner name where the issue will be created
NUXT_FEEDBACK_PROJECT=Test # Project name used in the title of the issue
NUXT_GITHUB_TOKEN=your_github_token # GitHub token with read & wirte access to issues and contentthe variables are set in the runtime config of nuxt:
runtimeConfig: {
feedback: {
repo: process.env.FEEDBACK_REPO,
repoOwner: process.env.FEEDBACK_REPO_OWNER,
project: process.env.FEEDBACK_PROJECT,
githubToken: process.env.GITHUB_TOKEN,
},
},3. Use Feedback Control in Your App
Add the FeedbackControl component to your layout or a specific page:
<script setup lang="ts">
// No setup needed - just use the component
</script>
<template>
<div>
<!-- Your application content -->
<!-- Feedback button appears automatically -->
<FeedbackControl />
</div>
</template>Component Props
The FeedbackControl component accepts the following optional props:
| Prop | Type | Default | Description |
|---|---|---|---|
defaultMail | string | "" | Pre-fill the email address field |
inline | boolean | false | Removes fixed positioning to allow placement inline with other elements (e.g., in a footer) |
Example:
<template>
<FeedbackControl defaultMail="user@example.com" />
</template>Component Features
Rating System
The feedback control includes a 5-level emoji-based rating system:
| Emoji | Value | Description |
|---|---|---|
| 😕 | poor | Very unsatisfied |
| 😐 | okay | Somewhat satisfied |
| 🙂 | good | Satisfied |
| 😀 | great | Very satisfied |
| 🤩 | excellent | Extremely satisfied |
Users click on the emoji to select their rating, providing quick sentiment analysis for your team.
Form Fields
The feedback form includes:
Rating Selection (Required)
- Five emoji buttons for quick rating selection
- Visual feedback when selected (highlighted border and background)
Message (Required)
- Multi-line text area for detailed feedback
- Placeholder text guides users
- Minimum validation to ensure meaningful feedback
Email (Optional)
- Email input for follow-up contact
- Email format validation
- Optional: users can leave blank for anonymous feedback
File Attachments (Optional)
- Upload up to 2 files
- Maximum file size: 75MB per file
- Drag-and-drop support
- File type validation
Validation
The feedback control uses Zod for comprehensive form validation:
- Rating: Must be selected (one of the 5 values)
- Message: Required, trimmed to ensure non-empty content
- Email: Valid email format if provided
- Attachments:
- Maximum 2 files
- Maximum 75MB per file
- File size validation before upload
API Endpoint
The feedback control layer creates a server API endpoint at /api/feedback that processes form submissions.
Request Format
POST /api/feedback
interface FeedbackBody {
rating: 'poor' | 'okay' | 'good' | 'great' | 'excellent';
message: string;
email?: string;
attachments: FeedbackAttachment[];
}
interface FeedbackAttachment {
base64: string;
fileName: string;
}GitHub Issue Format
The API creates a GitHub issue with the following structure:
Title:
[Rating] Feedback from user@example.comBody:
## Feedback Details
- **Rating**: 😊 good
- **Email**: user@example.com
## Message
This is the feedback message provided by the user.
## Attachments
- [screenshot.png](https://github.com/DCC-BS/Feedback/assets/...)Styling and Customization
The feedback control uses Nuxt UI components for consistent styling:
Built-in Styles
The component uses these Nuxt UI components:
UButton- Submit button and close buttonUPopover- Dropdown containerUTextarea- Message inputUInput- Email inputUAlert- Error messagesUFileUpload- File upload component
Custom Styling
You can customize the appearance using CSS overrides:
<template>
<div>
<FeedbackControl />
</div>
</template>
<style>
/* Customize feedback button */
#feedback-control button {
/* Your custom styles */
}
/* Customize form container */
#feedback-control .p-2 {
/* Your custom styles */
}
</style>Position Customization
By default, the feedback button is fixed at bottom-4 right-4 (16px from bottom and right). You can customize the position in two ways:
1. Using the inline Prop
To place the component inline with other elements (e.g., in a footer or a grid), set the inline prop to true. This removes the fixed positioning entirely, allowing standard layout flow to dictate placement.
<template>
<footer class="flex justify-between p-4">
<p>© 2024 My App</p>
<!-- Button sits inline in the footer -->
<FeedbackControl :inline="true" />
</footer>
</template>2. Using CSS Overrides
If you need to keep the fixed positioning but change the coordinates, use CSS overrides:
#feedback-control {
bottom: 32px !important;
right: 32px !important;
}Internationalization
The feedback control layer includes full i18n support with translations for all user-facing text.
Available Translations
The component includes translations for:
- Button labels
- Form field labels
- Placeholder text
- Help text
- Error messages
- Success messages
- Accessibility labels (aria-labels)
Adding Custom Translations
To add or customize translations, create an i18n configuration file:
// nuxt.config.ts
export default defineNuxtConfig({
i18n: {
locales: [
{ code: 'en', iso: 'en-US', file: 'en.json', name: 'English' },
{ code: 'de', iso: 'de-DE', file: 'de.json', name: 'Deutsch' }
],
defaultLocale: 'en'
}
})Add translations for the feedback namespace:
// locales/en.json
{
"feedback": {
"button": "Feedback",
"title": "Submit Feedback",
"rating_label": "How was your experience?",
"ratings": {
"poor": "Poor",
"okay": "Okay",
"good": "Good",
"great": "Great",
"excellent": "Excellent"
},
"message_label": "Your feedback",
"message_placeholder": "Tell us what you think...",
"email_label": "Email (optional)",
"email_placeholder": "your@email.com",
"email_help": "Leave blank for anonymous feedback",
"attachments_label": "Attachments",
"attachments_help": "Add up to {maxFiles} files, max {maxSize} each",
"submit": "Submit Feedback",
"submitting": "Submitting...",
"success_title": "Thank you!",
"success_message": "Your feedback has been submitted successfully.",
"close": "Close",
"aria_label": "Open feedback form"
}
}Examples
Basic Usage
<template>
<div>
<h1>My Application</h1>
<p>Welcome to the app!</p>
<!-- Feedback control appears automatically -->
<FeedbackControl />
</div>
</template>Pre-fill Email
<script setup lang="ts">
import { useAppAuth } from '#layers/auth/app/composables/useAuth';
const { data } = useAppAuth();
const userEmail = computed(() => data?.user?.email || '');
</script>
<template>
<div>
<!-- Pre-fill with authenticated user's email -->
<FeedbackControl :defaultMail="userEmail" />
</div>
</template>Inline Usage
<template>
<div class="flex items-center gap-4">
<span>Need help? Give us feedback.</span>
<!-- Component is placed inline, not fixed -->
<FeedbackControl :inline="true" />
</div>
</template>Related Documentation
- Authentication Layer - For integrating with user authentication
- Logger Layer - For logging feedback submissions
- Backend Communication - For API integration patterns
- Nuxt Layers Overview - Main documentation
