Back to Widget Patterns
v2.3Urgency

Limited Time Offer Banner

Top-of-page or bottom banner with a real deadline. Composes CountdownTimer for the countdown display. Includes dismiss persistence and expired-state handling.

Live preview

Rendered with real component code. Each example demonstrates a documented variant.

Warning variant

The banner is normally fixed to the viewport edge. The demo wrapper below uses CSS containment to display it inline.

Celebratory variant

The banner is normally fixed to the viewport edge. The demo wrapper below uses CSS containment to display it inline.

React props

Configure the component via props in React or via attributes in HTML.

PropTypeDefaultDescription
messagestringrequiredThe offer copy shown in the banner. Keep to a single line on mobile.
deadlineDate | stringrequiredPassed directly to CountdownTimer. Must be a real, fixed business deadline.
cta{ label: string; href: string }undefinedOptional CTA button rendered after the countdown
position"top" | "bottom""top"Viewport edge to pin the banner to
dismissiblebooleantrueWhen true, renders a close button that persists the dismissed state to localStorage
dismissKeystring"ltob-dismissed"localStorage key scoping the dismissed state. Change per campaign to avoid cross-campaign conflicts.
variant"warning" | "celebratory" | "minimal""warning"Visual treatment; controls background and text color tokens
expiredAction"hide" | "show-expired-message""hide"Behavior when the countdown reaches zero: hide the banner entirely, or replace its content with expiredMessage
expiredMessagestring"This offer has ended"Text shown when expiredAction is "show-expired-message" and the deadline has passed
classNamestringundefinedExtra class appended to the root element

HTML usage

The HTML variant uses the same shared styles and class names. Drop into any stack.

<!-- Order matters: countdown-timer/styles.css first, then limited-time-offer-banner/styles.css -->
<link rel="stylesheet" href="path/to/countdown-timer/styles.css">
<link rel="stylesheet" href="path/to/limited-time-offer-banner/styles.css">

<div
  class="ltob ltob--top ltob--warning"
  role="complementary"
  aria-label="Promotional offer"
  data-dismiss-key="ltob-dismissed"
>
  <p class="ltob__message">Sale ends Friday at midnight. 20% off all annual plans.</p>

  <div class="ltob__countdown cdt" data-deadline="2026-06-30T23:59:59Z">
    <p class="cdt__label">Ends in</p>
    <p class="cdt__display" aria-live="off">Loading...</p>
  </div>

  <a class="ltob__cta" href="/pricing">See pricing</a>

  <button class="ltob__close" type="button" aria-label="Dismiss promotional offer">
    <svg viewBox="0 0 16 16" aria-hidden="true" width="16" height="16">
      <path d="M4 4l8 8M12 4l-8 8" stroke="currentColor" stroke-width="1.5" fill="none"/>
    </svg>
  </button>
</div>

Customization

Override these CSS custom properties to integrate the component into your brand.

.ltob {
  --ltob-bg: var(--brand-accent, #b45309);
  --ltob-text-color: #ffffff;
  --ltob-cta-bg: #ffffff;
  --ltob-cta-text-color: #b45309;
  --ltob-padding: 0.625rem 1.25rem;
  --ltob-z-index: 1000;
  --ltob-gap: 1rem;
  --ltob-font-size: 0.9375rem;
  --ltob-close-size: 2rem;
  --ltob-close-opacity: 0.75;
  --ltob-close-opacity-hover: 1;
  --ltob-cta-radius: 0.375rem;
  --ltob-cta-padding: 0.375rem 0.875rem;
  --ltob-cta-font-size: 0.875rem;
  --ltob-shadow-top: 0 2px 10px rgba(0, 0, 0, 0.14);
  --ltob-shadow-bottom: 0 -2px 10px rgba(0, 0, 0, 0.14);
}

/* Variant-specific overrides */
.ltob--warning     { --ltob-bg: var(--brand-warning-bg, #b45309); }
.ltob--celebratory { --ltob-bg: var(--brand-celebratory-bg, #166534); }
.ltob--minimal {
  --ltob-bg: var(--brand-surface, #ffffff);
  --ltob-text-color: var(--brand-ink, #102542);
  --ltob-cta-bg: var(--brand-accent, #1e5fcf);
  --ltob-cta-text-color: #ffffff;
}