Skip to main content

Draw Widget

The Draw Widget provides a complete lottery/raffle experience with entry status, countdown to draw time, and result display.

Web Component

<fanfare-draw-widget draw-id="draw_123" show-header="true" show-countdown="true" show-actions="true" />

Attributes

AttributeTypeDefaultDescription
draw-idstringRequiredThe draw identifier
show-headerstring"true"Show title and description
show-countdownstring"true"Show countdown to draw
show-actionsstring"true"Show enter/withdraw buttons
container-classstring-Custom CSS class for container

Events

EventDetailDescription
fanfare-draw-enter{ drawId: string }User entered draw
fanfare-draw-withdraw{ drawId: string }User withdrew entry
fanfare-draw-result{ drawId, won: boolean }Draw result received
fanfare-draw-proceed{ drawId, token: string }User proceeding to checkout

Event Handling Example

import { useEffect, useRef } from "react";

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

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

    const handleEnter = (e: CustomEvent) => {
      console.log("Entered draw:", e.detail.drawId);
      analytics.track("draw_entered");
    };

    const handleResult = (e: CustomEvent<{ drawId: string; won: boolean }>) => {
      if (e.detail.won) {
        console.log("Congratulations! You won!");
        showConfetti();
      } else {
        console.log("Better luck next time");
      }
    };

    const handleProceed = (e: CustomEvent<{ token: string }>) => {
      window.location.href = `/checkout?token=${e.detail.token}`;
    };

    widget.addEventListener("fanfare-draw-enter", handleEnter);
    widget.addEventListener("fanfare-draw-result", handleResult);
    widget.addEventListener("fanfare-draw-proceed", handleProceed);

    return () => {
      widget.removeEventListener("fanfare-draw-enter", handleEnter);
      widget.removeEventListener("fanfare-draw-result", handleResult);
      widget.removeEventListener("fanfare-draw-proceed", handleProceed);
    };
  }, []);

  return (
    <div className="draw-container">
      <h1>Limited Edition Raffle</h1>
      <fanfare-draw-widget ref={widgetRef} draw-id="draw_123" />
    </div>
  );
}

Draw Status States

The widget handles these draw states automatically:
StatusDescriptionUI Display
openDraw is open for entriesEntry button + Countdown
enteredUser has enteredEntered status + Countdown
drawingDraw is in progressDrawing animation
wonUser won the drawWinner message + Proceed CTA
lostUser did not winBetter luck message
endedDraw has endedEnded message

Styling

CSS Variables

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

Winner Notification

function DrawWithNotifications() {
  const widgetRef = useRef<HTMLElement>(null);
  const [showWinnerModal, setShowWinnerModal] = useState(false);

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

    const handleResult = (e: CustomEvent<{ won: boolean }>) => {
      if (e.detail.won) {
        setShowWinnerModal(true);
        // Play celebration sound
        new Audio("/sounds/win.mp3").play();
      }
    };

    widget.addEventListener("fanfare-draw-result", handleResult);
    return () => widget.removeEventListener("fanfare-draw-result", handleResult);
  }, []);

  return (
    <>
      <fanfare-draw-widget ref={widgetRef} draw-id="draw_123" />

      {showWinnerModal && <WinnerModal onClose={() => setShowWinnerModal(false)} />}
    </>
  );
}

Using with React Hook (Alternative)

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

function CustomDrawUI() {
  const { draw, status, result, timeUntilDraw, enter, withdraw, isLoading } = useDraw("draw_123");

  if (result?.won) {
    return (
      <div className="winner">
        <h2>Congratulations! You Won!</h2>
        <a href="/checkout">Claim Your Prize</a>
      </div>
    );
  }

  if (result?.won === false) {
    return (
      <div className="not-selected">
        <h2>Not Selected This Time</h2>
        <p>Better luck next time!</p>
      </div>
    );
  }

  return (
    <div className="draw-ui">
      {status === "entered" ? (
        <>
          <p>You are entered!</p>
          {timeUntilDraw && <p>Draw in: {formatTime(timeUntilDraw)}</p>}
          <button onClick={withdraw}>Withdraw Entry</button>
        </>
      ) : (
        <>
          {timeUntilDraw && <p>Draw closes in: {formatTime(timeUntilDraw)}</p>}
          <button onClick={enter} disabled={isLoading}>
            {isLoading ? "Entering..." : "Enter Draw"}
          </button>
        </>
      )}
    </div>
  );
}

TypeScript Declaration

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