Feedback Widget Programmatic API
In addition to the visual interface with the floating button, you can control the widget entirely from code. This allows you to open the form from your own buttons, submit feedback without a visual interface, or react to widget events.
useFeedbackWidget Hook (React)
The @almirant/feedback-react package includes a hook that provides full access to the widget API.
import { useFeedbackWidget } from '@almirant/feedback-react';
function MyComponent() {
const {
open, // Opens the form
close, // Closes the form
submit, // Submits feedback programmatically
isReady, // true when the widget is initialized
isOpen, // true when the form is visible
error, // Last error or null
} = useFeedbackWidget();
return (
<button onClick={open}>
Send feedback
</button>
);
}
The useFeedbackWidget hook requires the <FeedbackWidget> component to be mounted somewhere in the component tree. If no widget is mounted, the hook returns no-op functions and isReady will be false.
Hook properties
| Property | Type | Description |
|---|---|---|
open() | () => void | Opens the feedback form |
close() | () => void | Closes the form |
submit(data) | (data: FeedbackData) => Promise<void> | Submits feedback programmatically |
isReady | boolean | true when the widget is fully initialized |
isOpen | boolean | true when the form is visible |
error | string | null | Last error message, or null if there are no errors |
Example: custom button
Hide the default floating button and use your own:
import { FeedbackWidget, useFeedbackWidget } from '@almirant/feedback-react';
function FeedbackButton() {
const { open, isReady } = useFeedbackWidget();
return (
<button
onClick={open}
disabled={!isReady}
className="my-feedback-button"
>
Leave feedback
</button>
);
}
function App() {
return (
<>
<nav>
<FeedbackButton />
</nav>
<FeedbackWidget
publicKey="pk_your_public_key"
showTriggerLabel={false}
/>
</>
);
}
Example: submit feedback programmatically
Submit feedback without showing the visual form. Useful for collecting contextual feedback (after completing an action, when closing a modal, etc.).
import { useFeedbackWidget } from '@almirant/feedback-react';
function PostPurchaseFeedback() {
const { submit, error } = useFeedbackWidget();
const handleRating = async (rating: number) => {
await submit({
message: `Post-purchase rating: ${rating}/5`,
metadata: {
type: 'rating',
rating,
orderId: 'order_123',
},
});
};
return (
<div>
<p>How was your purchase experience?</p>
{[1, 2, 3, 4, 5].map((n) => (
<button key={n} onClick={() => handleRating(n)}>
{n}
</button>
))}
{error && <p className="error">{error}</p>}
</div>
);
}
FeedbackData type
interface FeedbackData {
message: string; // Feedback text (required)
category?: string; // Category: 'bug', 'feature', 'improvement', 'other'
metadata?: Record<string, unknown>; // Additional data
}
Global API (JavaScript)
When using the script tag, the API is available on the global FeedbackWidget object.
Methods
// Open the form
FeedbackWidget.open();
// Close the form
FeedbackWidget.close();
// Submit feedback without visual interface
FeedbackWidget.submit({
message: 'The payment button is not responding in Safari',
category: 'bug',
metadata: {
browser: navigator.userAgent,
page: window.location.href,
},
});
// Check if the widget is ready
if (FeedbackWidget.isReady()) {
FeedbackWidget.open();
}
Method reference
| Method | Parameters | Return | Description |
|---|---|---|---|
init(options) | WidgetOptions | void | Initializes the widget with the given configuration |
open() | -- | void | Opens the form |
close() | -- | void | Closes the form |
submit(data) | FeedbackData | Promise<void> | Submits feedback programmatically |
isReady() | -- | boolean | Returns true if the widget is initialized |
isOpen() | -- | boolean | Returns true if the form is visible |
destroy() | -- | void | Removes the widget from the DOM and releases resources |
Events and callbacks
You can subscribe to widget events to react to user actions.
Script tag
FeedbackWidget.init({
publicKey: 'pk_your_public_key',
onOpen: () => {
console.log('The form was opened');
},
onClose: () => {
console.log('The form was closed');
},
onSubmit: (data) => {
console.log('Feedback submitted:', data.message);
// You can send to your own analytics
analytics.track('feedback_submitted', {
category: data.category,
});
},
onError: (error) => {
console.error('Error submitting feedback:', error);
},
});
React
<FeedbackWidget
publicKey="pk_your_public_key"
onOpen={() => console.log('Opened')}
onClose={() => console.log('Closed')}
onSubmit={(data) => {
analytics.track('feedback_submitted', {
category: data.category,
});
}}
onError={(error) => {
console.error('Error:', error);
}}
/>
Callback list
| Callback | Parameters | Triggered when... |
|---|---|---|
onOpen | -- | The form is opened |
onClose | -- | The form is closed |
onSubmit | { message, category, metadata } | Feedback is submitted successfully |
onError | { message: string } | An error occurs while submitting |
Submitting feedback without visual interface
If you don't need the visual form and want to build your own UI, you can use only the submit function:
JavaScript
// Initialize without a visible button
FeedbackWidget.init({
publicKey: 'pk_your_public_key',
// No floating button is shown when using submit directly
});
// Your custom form
document.getElementById('my-form').addEventListener('submit', async (e) => {
e.preventDefault();
const message = document.getElementById('message').value;
try {
await FeedbackWidget.submit({
message: message,
category: 'feature',
metadata: {
source: 'custom-form',
page: window.location.pathname,
},
});
alert('Feedback submitted');
} catch (error) {
alert('Error submitting: ' + error.message);
}
});
React
import { FeedbackWidget, useFeedbackWidget } from '@almirant/feedback-react';
function CustomFeedbackForm() {
const { submit, error } = useFeedbackWidget();
const [message, setMessage] = useState('');
const [sending, setSending] = useState(false);
const handleSubmit = async (e: React.FormEvent) => {
e.preventDefault();
setSending(true);
try {
await submit({
message,
category: 'feature',
metadata: { source: 'custom-form' },
});
setMessage('');
} finally {
setSending(false);
}
};
return (
<form onSubmit={handleSubmit}>
<textarea
value={message}
onChange={(e) => setMessage(e.target.value)}
placeholder="Your feedback..."
required
/>
<button type="submit" disabled={sending}>
{sending ? 'Sending...' : 'Submit'}
</button>
{error && <p className="error">{error}</p>}
</form>
);
}
// Don't forget to mount the widget (it can be hidden)
function App() {
return (
<>
<CustomFeedbackForm />
<FeedbackWidget publicKey="pk_your_public_key" />
</>
);
}
Even if you build your own interface, you need to initialize the widget with FeedbackWidget.init() or mount <FeedbackWidget> for the submit function to have access to the Almirant API. The widget handles authentication and submission.
Destroying the widget
If you need to completely remove the widget (for example, when navigating to a different section in a SPA):
// JavaScript
FeedbackWidget.destroy();
In React, the widget is automatically destroyed when the <FeedbackWidget> component unmounts.