Billing SDK/Billing SDK
Subscription ManagementLimited Offer Dialog

Limited Offer Dialog

The Limited Offer Dialog component provides a compelling interface for displaying time-sensitive offers and promotions. It features customizable content, loading states, error handling, and smooth animations to maximize conversion rates.

Playground
src/components/limited-offer-dialog-demo.tsx
"use client";

import { LimitedOfferDialog } from "@/components/billingsdk/limited-offer-dialog";

// Sample offer data
const sampleOffer = {
  id: "limited-offer-dialog",
  title: "Special Offer",
  description: "Limited time deal",
  discount: "50% OFF",
  features: [
    { name: "50% off your first month" },
    { name: "Valid until December 31, 2024" },
    { name: "First 100 users only" }
  ]
};

export function LimitedOfferDialogDemo() {
  const handleClaimOffer = async (offerId: string) => {
    console.log("Claiming offer:", offerId);
    // Simulate API call
    await new Promise(resolve => setTimeout(resolve, 1000));
    alert("Offer claimed successfully!");
  };

  const handleDeclineOffer = async (offerId: string) => {
    console.log("Declining offer:", offerId);
    // Simulate API call
    await new Promise(resolve => setTimeout(resolve, 500));
    alert("Offer declined. You can always come back later!");
  };

  const handleDialogClose = () => {
    console.log("Dialog closed");
  };

  return (
    <div className="flex flex-1 flex-col justify-center text-center p-4 mx-auto min-h-[300px]">
      <LimitedOfferDialog
        title="🔥 Limited Time Offer!"
        description="Grab this deal before it's gone"
        offer={sampleOffer}
        triggerButtonText="Open Offer Dialog"
        warningTitle="Don't miss out!"
        warningText="This exclusive offer won't last long. Claim it now before it's gone forever."
        claimButtonText="👉 Claim Offer Now"
        declineButtonText="No thanks, I'll pay full price"
        onClaimOffer={handleClaimOffer}
        onDeclineOffer={handleDeclineOffer}
        onDialogClose={handleDialogClose}
        className="w-auto"
      />
    </div>
  );
}

Installation

npx shadcn@latest add @billingsdk/limited-offer-dialog
pnpm dlx shadcn@latest add @billingsdk/limited-offer-dialog
yarn dlx shadcn@latest add @billingsdk/limited-offer-dialog
bunx shadcn@latest add @billingsdk/limited-offer-dialog
npx @billingsdk/cli add limited-offer-dialog
pnpm dlx @billingsdk/cli add limited-offer-dialog
yarn dlx @billingsdk/cli add limited-offer-dialog
bunx @billingsdk/cli add limited-offer-dialog

Usage

import { LimitedOfferDialog } from "@/components/billingsdk/limited-offer-dialog";
<LimitedOfferDialog
  title="🔥 Limited Time Offer!"
  description="Grab this deal before it's gone"
  offer={{
    id: "limited-offer-dialog",
    title: "Special Offer",
    description: "Limited time deal",
    discount: "50% OFF",
    features: [
      { name: "50% off your first month" },
      { name: "Valid until December 31, 2024" },
      { name: "First 100 users only" }
    ]
  }}
  triggerButtonText="Open Offer Dialog"
  warningTitle="Don't miss out!"
  warningText="This exclusive offer won't last long. Claim it now before it's gone forever."
  claimButtonText="👉 Claim Offer Now"
  declineButtonText="No thanks, I'll pay full price"
  onClaimOffer={async (offerId) => {
    console.log("Claiming offer:", offerId);
    // Simulate API call
    await new Promise(resolve => setTimeout(resolve, 1000));
    alert("Offer claimed successfully!");
  }}
  onDeclineOffer={async (offerId) => {
    console.log("Declining offer:", offerId);
    // Simulate API call
    await new Promise(resolve => setTimeout(resolve, 500));
    alert("Offer declined. You can always come back later!");
  }}
  onDialogClose={() => {
    // Handle dialog close
    console.log("Dialog closed");
  }}
/>

Props

PropTypeRequiredDescription
titlestringMain dialog title (default: "🔥 Limited Time Offer!")
descriptionstringDialog description text (default: "Grab this deal before it's gone")
offerOfferOffer object containing offer details (uses defaultOffer if not provided)
triggerButtonTextstringText for the trigger button (default: "Open Offer Dialog")
warningTitlestringTitle for warning section (default: "Don't miss out!")
warningTextstringWarning message text (default: "This exclusive offer won't last long. Claim it now before it's gone forever.")
claimButtonTextstringText for claim offer button (default: "👉 Claim Offer Now")
declineButtonTextstringText for decline button (default: "No thanks, I'll pay full price")
onClaimOffer(offerId: string) => Promise<void> | voidCallback when offer is claimed
onDeclineOffer(offerId: string) => Promise<void> | voidCallback when offer is declined
onDialogClose() => voidCallback when dialog is closed
classNamestringAdditional CSS classes

Offer Interface

interface Offer {
  id: string;
  title: string;
  description: string;
  discount: string;
  features: Array<{
    name: string;
    icon?: string;
    iconColor?: string;
  }>;
}

Theming

The limited offer dialog component is styled using the shadcn/ui library. You can customize the colors and fonts by overriding the CSS variables. You can also get the theme from the Theming page.

Example

src/components/limited-offer-dialog-demo.tsx
"use client";

import { LimitedOfferDialog } from "@/components/billingsdk/limited-offer-dialog";

// Sample offer data
const sampleOffer = {
  id: "limited-offer-dialog",
  title: "Special Offer",
  description: "Limited time deal",
  discount: "50% OFF",
  features: [
    { name: "50% off your first month" },
    { name: "Valid until December 31, 2024" },
    { name: "First 100 users only" }
  ]
};

export function LimitedOfferDialogDemo() {
  const handleClaimOffer = async (offerId: string) => {
    console.log("Claiming offer:", offerId);
    // Simulate API call
    await new Promise(resolve => setTimeout(resolve, 1000));
    alert("Offer claimed successfully!");
  };

  const handleDeclineOffer = async (offerId: string) => {
    console.log("Declining offer:", offerId);
    // Simulate API call
    await new Promise(resolve => setTimeout(resolve, 500));
    alert("Offer declined. You can always come back later!");
  };

  const handleDialogClose = () => {
    console.log("Dialog closed");
  };

  return (
    <div className="flex flex-1 flex-col justify-center text-center p-4 mx-auto min-h-[300px]">
      <LimitedOfferDialog
        title="🔥 Limited Time Offer!"
        description="Grab this deal before it's gone"
        offer={sampleOffer}
        triggerButtonText="Open Offer Dialog"
        warningTitle="Don't miss out!"
        warningText="This exclusive offer won't last long. Claim it now before it's gone forever."
        claimButtonText="👉 Claim Offer Now"
        declineButtonText="No thanks, I'll pay full price"
        onClaimOffer={handleClaimOffer}
        onDeclineOffer={handleDeclineOffer}
        onDialogClose={handleDialogClose}
        className="w-auto"
      />
    </div>
  );
}

Credits