Skip to main content

Waitlist Widget

The Waitlist Widget provides a pre-registration experience for consumers to sign up before a distribution opens, with countdown display and notification signup.

Web Component

<fanfare-waitlist-widget waitlist-id="waitlist_123" show-header="true" show-countdown="true" show-actions="true" />

Attributes

AttributeTypeDefaultDescription
waitlist-idstringRequiredThe waitlist identifier
show-headerstring"true"Show title and description
show-countdownstring"true"Show countdown to open
show-actionsstring"true"Show join/leave buttons
container-classstring-Custom CSS class for container

Events

EventDetailDescription
fanfare-waitlist-enter{ waitlistId: string }User joined waitlist
fanfare-waitlist-leave{ waitlistId: string }User left waitlist
fanfare-waitlist-open{ waitlistId: string }Waitlist period opened
fanfare-waitlist-proceed{ waitlistId: string }User proceeding

Event Handling Example

import { useEffect, useRef } from "react";

function WaitlistPage() {
  const widgetRef = useRef<HTMLElement>(null);

  useEffect(() => {
    const widget = widgetRef.current;
    if (!widget) return;

    const handleEnter = (e: CustomEvent) => {
      console.log("Joined waitlist:", e.detail.waitlistId);
      analytics.track("waitlist_joined");
      showSuccessToast("You are on the waitlist! We will notify you when it opens.");
    };

    const handleOpen = (e: CustomEvent) => {
      console.log("Waitlist opened!");
      // Redirect to the main experience
      window.location.href = `/experience/${e.detail.waitlistId}`;
    };

    widget.addEventListener("fanfare-waitlist-enter", handleEnter);
    widget.addEventListener("fanfare-waitlist-open", handleOpen);

    return () => {
      widget.removeEventListener("fanfare-waitlist-enter", handleEnter);
      widget.removeEventListener("fanfare-waitlist-open", handleOpen);
    };
  }, []);

  return (
    <div className="waitlist-container">
      <h1>Coming Soon</h1>
      <p>Sign up to be notified when we launch!</p>
      <fanfare-waitlist-widget ref={widgetRef} waitlist-id="waitlist_123" />
    </div>
  );
}

Waitlist Status States

The widget handles these waitlist states automatically:
StatusDescriptionUI Display
availableWaitlist is open for signupJoin button + Countdown
enteredUser is on the waitlistConfirmation + Countdown
openingAbout to open (< 1 minute)Urgent countdown
openedDistribution is now openProceed CTA

Styling

CSS Variables

fanfare-waitlist-widget {
  --fanfare-primary: #8b5cf6;
  --fanfare-primary-hover: #7c3aed;
  --fanfare-success: #22c55e;
  --fanfare-background: #ffffff;
  --fanfare-foreground: #1f2937;
  --fanfare-muted: #f3f4f6;
  --fanfare-radius: 0.75rem;
}

Product Launch Page Example

function ProductLaunchPage() {
  const widgetRef = useRef<HTMLElement>(null);
  const [isOnWaitlist, setIsOnWaitlist] = useState(false);

  useEffect(() => {
    const widget = widgetRef.current;
    if (!widget) return;

    const handleEnter = () => {
      setIsOnWaitlist(true);
    };

    const handleLeave = () => {
      setIsOnWaitlist(false);
    };

    widget.addEventListener("fanfare-waitlist-enter", handleEnter);
    widget.addEventListener("fanfare-waitlist-leave", handleLeave);

    return () => {
      widget.removeEventListener("fanfare-waitlist-enter", handleEnter);
      widget.removeEventListener("fanfare-waitlist-leave", handleLeave);
    };
  }, []);

  return (
    <div className="product-launch">
      <div className="hero">
        <img src="/product-teaser.jpg" alt="New Product" />
        <h1>Exclusive Limited Edition Drop</h1>
        <p>Only 100 units available worldwide</p>
      </div>

      <div className="waitlist-section">
        <fanfare-waitlist-widget ref={widgetRef} waitlist-id="waitlist_123" />

        {isOnWaitlist && (
          <div className="confirmation">
            <p>Check your email for confirmation!</p>
          </div>
        )}
      </div>

      <div className="features">
        <h2>Why Join the Waitlist?</h2>
        <ul>
          <li>Early access notification</li>
          <li>Priority checkout window</li>
          <li>Exclusive updates</li>
        </ul>
      </div>
    </div>
  );
}

Using with React Hook (Alternative)

For more control, use the useWaitlist hook:
import { useWaitlist } from "@waitify-io/fanfare-sdk-react";

function CustomWaitlistUI() {
  const { waitlist, status, opensAt, timeUntilOpen, isEntered, enter, leave, isLoading } = useWaitlist("waitlist_123");

  if (status === "opened") {
    return (
      <div className="opened">
        <h2>It is Open!</h2>
        <a href="/shop">Start Shopping</a>
      </div>
    );
  }

  return (
    <div className="waitlist-ui">
      {opensAt && (
        <div className="countdown">
          <p>Opens in:</p>
          <span className="time">{formatCountdown(timeUntilOpen)}</span>
        </div>
      )}

      {isEntered ? (
        <div className="entered">
          <p>You are on the waitlist!</p>
          <p>We will notify you when it opens.</p>
          <button onClick={leave} className="secondary">
            Leave Waitlist
          </button>
        </div>
      ) : (
        <button onClick={enter} disabled={isLoading}>
          {isLoading ? "Joining..." : "Join Waitlist"}
        </button>
      )}
    </div>
  );
}

TypeScript Declaration

declare namespace JSX {
  interface IntrinsicElements {
    "fanfare-waitlist-widget": React.DetailedHTMLProps<
      React.HTMLAttributes<HTMLElement> & {
        "waitlist-id": string;
        "show-header"?: string;
        "show-countdown"?: string;
        "show-actions"?: string;
        "container-class"?: string;
      },
      HTMLElement
    >;
  }
}