Documentation Index
Fetch the complete documentation index at: https://docs.fanfare.io/llms.txt
Use this file to discover all available pages before exploring further.
Queue Widget
The Queue Widget provides a complete virtual waiting room experience with position display, estimated wait times, and enter/leave actions.
Web Component
<fanfare-queue-widget queue-id="queue_123" show-header="true" show-actions="true" show-estimated-wait="true" />
Attributes
| Attribute | Type | Default | Description |
|---|
queue-id | string | Required | The queue identifier |
show-header | string | "true" | Show title and description |
show-actions | string | "true" | Show enter/leave buttons |
show-estimated-wait | string | "true" | Show estimated wait time |
container-class | string | - | Custom CSS class for container |
Events
| Event | Detail | Description |
|---|
fanfare-queue-enter | { queueId: string } | User entered queue |
fanfare-queue-leave | { queueId: string } | User left queue |
fanfare-queue-position-change | { queueId, position: number } | Position updated |
fanfare-queue-admitted | { queueId, token: string } | User was admitted |
Event Handling Example
import { useEffect, useRef } from "react";
function QueuePage() {
const widgetRef = useRef<HTMLElement>(null);
useEffect(() => {
const widget = widgetRef.current;
if (!widget) return;
const handleEnter = (e: CustomEvent) => {
console.log("Entered queue:", e.detail.queueId);
analytics.track("queue_entered", { queueId: e.detail.queueId });
};
const handlePositionChange = (e: CustomEvent) => {
console.log("New position:", e.detail.position);
};
const handleAdmitted = (e: CustomEvent) => {
console.log("Admitted with token:", e.detail.token);
window.location.href = `/checkout?token=${e.detail.token}`;
};
widget.addEventListener("fanfare-queue-enter", handleEnter);
widget.addEventListener("fanfare-queue-position-change", handlePositionChange);
widget.addEventListener("fanfare-queue-admitted", handleAdmitted);
return () => {
widget.removeEventListener("fanfare-queue-enter", handleEnter);
widget.removeEventListener("fanfare-queue-position-change", handlePositionChange);
widget.removeEventListener("fanfare-queue-admitted", handleAdmitted);
};
}, []);
return (
<div className="queue-container">
<h1>Join Our Queue</h1>
<fanfare-queue-widget ref={widgetRef} queue-id="queue_123" />
</div>
);
}
Queue Status States
The widget handles these queue states automatically:
| Status | Description | UI Display |
|---|
enterable | Queue is open, user not in queue | Enter button |
queued | User is in queue | Position + Leave button |
admitted | User has been admitted | Success message + CTA |
error | Error occurred | Error message + Retry |
Styling
CSS Variables
Override these variables to customize the queue widget:
fanfare-queue-widget {
--fanfare-primary: #3b82f6;
--fanfare-primary-hover: #2563eb;
--fanfare-background: #ffffff;
--fanfare-foreground: #1f2937;
--fanfare-muted: #f3f4f6;
--fanfare-border: #e5e7eb;
--fanfare-success: #22c55e;
--fanfare-radius: 0.5rem;
}
Container Styling
<fanfare-queue-widget
queue-id="queue_123"
container-class="my-queue-widget"
/>
<style>
.my-queue-widget {
max-width: 400px;
margin: 0 auto;
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
}
</style>
Redirect on Admission
function QueueWithRedirect() {
const widgetRef = useRef<HTMLElement>(null);
useEffect(() => {
const widget = widgetRef.current;
if (!widget) return;
const handleAdmitted = (e: CustomEvent<{ token: string }>) => {
const { token } = e.detail;
// Option 1: Redirect to checkout
window.location.href = `/checkout?token=${token}`;
// Option 2: Navigate with React Router
// navigate(`/checkout?token=${token}`);
};
widget.addEventListener("fanfare-queue-admitted", handleAdmitted);
return () => widget.removeEventListener("fanfare-queue-admitted", handleAdmitted);
}, []);
return <fanfare-queue-widget ref={widgetRef} queue-id="queue_123" />;
}
Using with React Hook (Alternative)
For more control, use the useQueue hook instead:
import { useQueue } from "@waitify-io/fanfare-sdk-react";
function CustomQueueUI() {
const { queue, status, position, estimatedWait, enter, leave, isLoading } = useQueue("queue_123");
if (status === "admitted") {
return (
<div className="admitted">
<h2>You are in!</h2>
<a href="/checkout">Continue to Checkout</a>
</div>
);
}
return (
<div className="queue-ui">
{status === "queued" ? (
<>
<p>Position: {position}</p>
{estimatedWait && <p>Estimated wait: {estimatedWait} minutes</p>}
<button onClick={leave}>Leave Queue</button>
</>
) : (
<button onClick={enter} disabled={isLoading}>
{isLoading ? "Joining..." : "Enter Queue"}
</button>
)}
</div>
);
}
TypeScript Declaration
declare namespace JSX {
interface IntrinsicElements {
"fanfare-queue-widget": React.DetailedHTMLProps<
React.HTMLAttributes<HTMLElement> & {
"queue-id": string;
"show-header"?: string;
"show-actions"?: string;
"show-estimated-wait"?: string;
"container-class"?: string;
},
HTMLElement
>;
}
}