Skip to main content

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>
);
}
Important

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

PropertyTypeDescription
open()() => voidOpens the feedback form
close()() => voidCloses the form
submit(data)(data: FeedbackData) => Promise<void>Submits feedback programmatically
isReadybooleantrue when the widget is fully initialized
isOpenbooleantrue when the form is visible
errorstring | nullLast 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

MethodParametersReturnDescription
init(options)WidgetOptionsvoidInitializes the widget with the given configuration
open()--voidOpens the form
close()--voidCloses the form
submit(data)FeedbackDataPromise<void>Submits feedback programmatically
isReady()--booleanReturns true if the widget is initialized
isOpen()--booleanReturns true if the form is visible
destroy()--voidRemoves 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

CallbackParametersTriggered 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" />
</>
);
}
Tip

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.