Skip to main content

Auction Widget

The Auction Widget provides a complete real-time bidding experience with current bid display, bid form, bid history, and countdown timer.

Web Component

<fanfare-auction-widget
  auction-id="auction_123"
  show-header="true"
  show-bid-history="true"
  show-countdown="true"
  currency-code="USD"
/>

Attributes

AttributeTypeDefaultDescription
auction-idstringRequiredThe auction identifier
show-headerstring"true"Show title and description
show-bid-historystring"true"Show recent bid history
show-countdownstring"true"Show countdown timer
currency-codestring"USD"Currency for bid display
container-classstring-Custom CSS class for container

Events

EventDetailDescription
fanfare-auction-bid{ auctionId, amount: number }Bid placed
fanfare-auction-outbid{ auctionId, newBid: number }User was outbid
fanfare-auction-win{ auctionId, amount: number }User won auction
fanfare-auction-proceed{ auctionId, token: string }User proceeding to pay

Event Handling Example

import { useEffect, useRef, useState } from "react";

function AuctionPage() {
  const widgetRef = useRef<HTMLElement>(null);
  const [outbidAlert, setOutbidAlert] = useState(false);

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

    const handleBid = (e: CustomEvent<{ amount: number }>) => {
      console.log("Bid placed:", e.detail.amount);
      analytics.track("auction_bid", { amount: e.detail.amount });
    };

    const handleOutbid = (e: CustomEvent<{ newBid: number }>) => {
      setOutbidAlert(true);
      // Play notification sound
      new Audio("/sounds/outbid.mp3").play();
      setTimeout(() => setOutbidAlert(false), 5000);
    };

    const handleWin = (e: CustomEvent) => {
      console.log("Auction won!");
      showConfetti();
    };

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

    widget.addEventListener("fanfare-auction-bid", handleBid);
    widget.addEventListener("fanfare-auction-outbid", handleOutbid);
    widget.addEventListener("fanfare-auction-win", handleWin);
    widget.addEventListener("fanfare-auction-proceed", handleProceed);

    return () => {
      widget.removeEventListener("fanfare-auction-bid", handleBid);
      widget.removeEventListener("fanfare-auction-outbid", handleOutbid);
      widget.removeEventListener("fanfare-auction-win", handleWin);
      widget.removeEventListener("fanfare-auction-proceed", handleProceed);
    };
  }, []);

  return (
    <div className="auction-container">
      {outbidAlert && <div className="outbid-alert">You have been outbid! Place a higher bid to stay in the lead.</div>}

      <h1>Exclusive Item Auction</h1>
      <fanfare-auction-widget ref={widgetRef} auction-id="auction_123" />
    </div>
  );
}

Auction Status States

The widget handles these auction states automatically:
StatusDescriptionUI Display
openAuction is activeBid form + Current bid
winningUser has highest bidWinning status + Timer
outbidUser was outbidOutbid alert + Quick rebid
wonUser won the auctionWinner message + Proceed CTA
lostAuction ended, user lostAuction ended message
endedAuction has endedFinal results

Styling

CSS Variables

fanfare-auction-widget {
  --fanfare-primary: #ef4444;
  --fanfare-primary-hover: #dc2626;
  --fanfare-success: #22c55e;
  --fanfare-warning: #f59e0b;
  --fanfare-background: #ffffff;
  --fanfare-foreground: #1f2937;
  --fanfare-radius: 0.5rem;
}

Outbid Notifications

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

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

    const handleOutbid = async (e: CustomEvent<{ newBid: number }>) => {
      // Browser notification (if permission granted)
      if (Notification.permission === "granted") {
        new Notification("You've been outbid!", {
          body: `New high bid: $${e.detail.newBid}`,
          icon: "/icons/auction.png",
        });
      }
    };

    widget.addEventListener("fanfare-auction-outbid", handleOutbid);
    return () => widget.removeEventListener("fanfare-auction-outbid", handleOutbid);
  }, []);

  return <fanfare-auction-widget ref={widgetRef} auction-id="auction_123" />;
}

Using with React Hook (Alternative)

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

function CustomAuctionUI() {
  const { auction, status, currentBid, myBid, minNextBid, bidHistory, timeRemaining, isWinning, placeBid, isLoading } =
    useAuction("auction_123");

  const [bidAmount, setBidAmount] = useState(minNextBid);

  const handleSubmitBid = async () => {
    await placeBid(bidAmount);
    setBidAmount(minNextBid);
  };

  if (status === "won") {
    return (
      <div className="winner">
        <h2>Congratulations! You Won!</h2>
        <p>Winning bid: ${myBid}</p>
        <a href="/checkout">Complete Purchase</a>
      </div>
    );
  }

  return (
    <div className="auction-ui">
      <div className="current-bid">
        <span>Current Bid:</span>
        <span className="amount">${currentBid}</span>
      </div>

      {isWinning && <div className="winning-badge">You are winning!</div>}

      {timeRemaining && <div className="countdown">Time left: {formatTime(timeRemaining)}</div>}

      <div className="bid-form">
        <input
          type="number"
          value={bidAmount}
          onChange={(e) => setBidAmount(Number(e.target.value))}
          min={minNextBid}
          step={10}
        />
        <button onClick={handleSubmitBid} disabled={isLoading}>
          {isLoading ? "Placing Bid..." : `Bid $${bidAmount}`}
        </button>
      </div>

      <div className="bid-history">
        <h4>Recent Bids</h4>
        {bidHistory.slice(0, 5).map((bid) => (
          <div key={bid.id} className="bid-entry">
            <span>${bid.amount}</span>
            <span>{bid.userLabel}</span>
          </div>
        ))}
      </div>
    </div>
  );
}

TypeScript Declaration

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