@tehsin06/feedback
v1.1.12
Published
A lightweight, customizable React feedback widget for collecting user feedback with built-in image upload support.
Readme
@tehsin06/feedback
A lightweight, customizable React feedback widget for collecting user feedback with built-in image upload support.
✨ Features
- 🎯 Customizable feedback types: Provide your own dropdown options
- 📸 Image upload with drag-and-drop and clipboard paste (Ctrl+V)
- ✅ Form validation with inline error messages
- 🛡️ Honeypot spam protection built-in
- 🎨 Fully customizable via CSS variables
- 📱 Responsive design - works on mobile and desktop
- ⚡ Lightweight - minimal dependencies
- 🔧 Flexible positioning - fixed side button or inline top bar
- 🎭 Custom button variants - 8 pre-built styles
- 🚫 No notification system dependency - handle success/error your way
- 🔌 Custom submit handler - full control over form submission with
onSubmitcallback
📦 Installation
npm install @tehsin06/feedback antdPeer Dependencies
react >= 17react-dom >= 17
🚀 Quick Start
import { FeedbackWidget } from "@tehsin06/feedback";
function App() {
return (
<div>
<YourAppContent />
{/* Fixed feedback button on right side */}
<FeedbackWidget triggerPosition="right-side" simulationMode="random" />
</div>
);
}✨ Styles are automatically included — no need for separate CSS imports!
📖 API Reference
FeedbackWidget Props
| Prop | Type | Default | Description |
| ----------------- | --------------------------------------------------------- | ----------------------- | ------------------------------------------------ |
| triggerPosition | "right-side" \| "top-bar" | "right-side" | Position of the trigger button |
| simulationMode | "success" \| "error" \| "random" | "random" | Mock submission behavior for testing |
| triggerVariant | ButtonVariant | "primary" | Style variant for trigger button |
| submitVariant | ButtonVariant | "primary" | Style variant for submit button |
| feedbackOptions | Array<{value: string, label: string}> | [{Bug}, {Suggestion}] | Custom options for feedback type dropdown |
| onSubmit | (data: FeedbackSubmissionData) => void \| Promise<void> | undefined | Callback fired on form submission with form data |
Button Variants
Available variants: primary, secondary, danger, success, warning, info, ghost, outline
Example with Custom Variants
<FeedbackWidget
triggerPosition="right-side"
triggerVariant="info"
submitVariant="success"
simulationMode="success"
/>Custom Feedback Options
Customize the feedback type dropdown with your own options:
const customOptions = [
{ value: "Bug", label: "🐛 Bug Report" },
{ value: "Feature", label: "✨ Feature Request" },
{ value: "Question", label: "❓ Question" },
{ value: "Praise", label: "👏 Praise" },
];
<FeedbackWidget feedbackOptions={customOptions} triggerPosition="right-side" />;Handle Form Submission
Use the onSubmit callback to receive form data and integrate with your backend:
import { FeedbackWidget } from "@tehsin06/feedback";
import type { FeedbackSubmissionData } from "@tehsin06/feedback";
function App() {
const handleFeedbackSubmit = async (data: FeedbackSubmissionData) => {
// Access all form data
console.log(data.feedbackType); // e.g., "Bug"
console.log(data.message); // User's message
console.log(data.imageFile); // File object or undefined
console.log(data.sourcePath); // Current page path
// Send to your API
const formData = new FormData();
formData.append("type", data.feedbackType);
formData.append("message", data.message);
if (data.imageFile) {
formData.append("image", data.imageFile);
}
const response = await fetch("/api/feedback", {
method: "POST",
body: formData,
});
if (response.ok) {
// Show success notification
alert("Thank you for your feedback!");
} else {
throw new Error("Submission failed");
}
};
return (
<div>
<YourContent />
<FeedbackWidget
onSubmit={handleFeedbackSubmit}
triggerPosition="right-side"
/>
</div>
);
}🎨 Customization
CSS Variables
Override these CSS variables to match your brand:
:root {
/* Background & borders */
--feedback-bg: rgba(8, 28, 53, 0.96);
--feedback-border: rgba(148, 163, 184, 0.6);
/* Text colors */
--feedback-text: #e7f1ff;
--feedback-muted: #94a3b8;
/* Accent color */
--feedback-accent: #bc88ff;
--feedback-accent-text: #020b18;
/* Button styles */
--feedback-button-bg: #bc88ff;
--feedback-button-text: #020b18;
--feedback-button-hover-bg: #a66ff7;
}Dark/Light Theme Example
/* Light theme */
.light-theme {
--feedback-bg: rgba(255, 255, 255, 0.98);
--feedback-text: #1a202c;
--feedback-border: rgba(0, 0, 0, 0.1);
--feedback-accent: #4f46e5;
}
/* Dark theme */
.dark-theme {
--feedback-bg: rgba(17, 24, 39, 0.98);
--feedback-text: #f9fafb;
--feedback-border: rgba(255, 255, 255, 0.1);
--feedback-accent: #818cf8;
}💡 Usage Examples
Fixed Side Button
<FeedbackWidget triggerPosition="right-side" triggerVariant="primary" />Creates a fixed button on the right edge of the screen.
Top Bar Inline Button
<nav>
<Logo />
<NavLinks />
<FeedbackWidget triggerPosition="top-bar" triggerVariant="ghost" />
</nav>Renders an inline button suitable for navigation bars.
Testing Different Scenarios
// Always succeed
<FeedbackWidget simulationMode="success" />
// Always fail (for error handling testing)
<FeedbackWidget simulationMode="error" />
// Random (75% success, 25% error)
<FeedbackWidget simulationMode="random" />🔧 Advanced Usage
Backend Integration
Use the onSubmit callback to send feedback to your backend API:
import { FeedbackWidget } from "@tehsin06/feedback";
import type { FeedbackSubmissionData } from "@tehsin06/feedback";
function App() {
const handleSubmit = async (data: FeedbackSubmissionData) => {
const formData = new FormData();
formData.append("type", data.feedbackType);
formData.append("message", data.message);
formData.append("path", data.sourcePath || "");
if (data.imageFile) {
formData.append("screenshot", data.imageFile);
}
const response = await fetch("/api/feedback", {
method: "POST",
body: formData,
});
if (!response.ok) {
throw new Error("Failed to submit feedback");
}
// Optionally return data from your API
const result = await response.json();
console.log("Feedback ID:", result.id);
};
return <FeedbackWidget onSubmit={handleSubmit} />;
}With Notification System Integration
import { FeedbackWidget } from "@tehsin06/feedback";
import type { FeedbackSubmissionData } from "@tehsin06/feedback";
import { toast } from "your-toast-library";
function App() {
const handleSubmit = async (data: FeedbackSubmissionData) => {
try {
await fetch("/api/feedback", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify(data),
});
toast.success("Thank you for your feedback!");
} catch (error) {
toast.error("Failed to submit feedback. Please try again.");
throw error; // Re-throw to prevent form reset
}
};
return <FeedbackWidget onSubmit={handleSubmit} />;
}Handling Success/Error
The widget automatically handles form submission and resets on success. When you provide the onSubmit callback, you have full control over the submission process:
const handleSubmit = async (data: FeedbackSubmissionData) => {
try {
await sendToBackend(data);
// Show success message with your notification system
showNotification("Feedback submitted!", "success");
} catch (error) {
// Handle errors your way
showNotification("Failed to submit feedback", "error");
throw error; // Re-throw to prevent form reset
}
};
<FeedbackWidget onSubmit={handleSubmit} />;Note: If onSubmit is not provided, the widget uses its default mock submission service with simulationMode for testing purposes.
📝 TypeScript Support
Full TypeScript support with exported types:
import type {
FeedbackType,
FeedbackSubmission,
FeedbackSubmissionData, // New! Data passed to onSubmit callback
ButtonVariant,
} from "@tehsin06/feedback";FeedbackSubmissionData Interface
interface FeedbackSubmissionData {
feedbackType: string; // Selected feedback type
message: string; // User's message
imageFile?: File; // Uploaded image (if any)
sourcePath?: string; // Current page path
}🎯 Features Detail
Image Upload
- Drag & drop files onto the dropzone
- Click to browse file selection
- Clipboard paste (Ctrl+V / Cmd+V)
- Image preview with remove option
- Accepts: PNG, JPG, JPEG, GIF, WebP (max 5MB)
Form Validation
- Required field validation
- Character limits (10-500 chars for message)
- Image size validation
- Real-time error messages
Spam Protection
Includes invisible honeypot field that bots typically fill out, helping filter spam submissions.
📦 Package Structure
dist/
├── index.js # Main component exports (includes bundled CSS)
└── index.d.ts # TypeScript definitionsNo Additional Imports Needed
All styles are automatically bundled into the main package. Simply import the component and styles are applied automatically:
import { FeedbackWidget } from "@tehsin06/feedback";🤝 Contributing
Contributions are welcome! Please feel free to submit a Pull Request.
📄 License
MIT © [Tredit]
🐛 Issues
Found a bug? Please open an issue with:
- Steps to reproduce
- Expected behavior
- Actual behavior
- Screenshots (if applicable)
🚀 Roadmap
- [ ] Email field option
- [ ] Custom field support
- [ ] Analytics integration
- [ ] File attachment support (non-image files)
- [ ] Multi-language support
- [ ] Accessibility improvements (WCAG 2.1 AA)
Made with ❤️ by Tredit
