webdevpuneet.com

Trial Countdown Banner — Free HTML CSS JS Snippet

Trial Countdown Banner · Pricing · Plain HTML, CSS & JS · Live preview

CategoryPricing

Copy & paste

Source Code

<div class="app-shell">
  <div class="trial-banner" id="trial-banner">
    <div class="banner-left">
      <div class="trial-timer" id="timer">
        <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.2" stroke-linecap="round"><circle cx="12" cy="12" r="10"/><polyline points="12 6 12 12 16 14"/></svg>
        <span id="days-left">7 days</span> left in your free trial
      </div>
      <div class="trial-sub">Upgrade to keep your data and team access after <strong id="expire-date">Jun 7</strong></div>
    </div>
    <div class="banner-right">
      <div class="trial-progress">
        <div class="tp-labels"><span>Trial started</span><span>Trial ends</span></div>
        <div class="tp-bar"><div class="tp-fill" id="tp-fill"></div></div>
        <div class="tp-sublabel" id="tp-sub">Day 7 of 14</div>
      </div>
      <a href="#" class="upgrade-btn">Upgrade now</a>
      <button class="dismiss-btn" onclick="dismissBanner()" aria-label="Dismiss">×</button>
    </div>
  </div>

  <div class="content">
    <div class="limit-card" id="limit-card">
      <div class="limit-icon">⚡</div>
      <div class="limit-body">
        <div class="limit-title">You've used 4 of 5 free projects</div>
        <div class="limit-sub">Upgrade to Pro for unlimited projects, storage, and team collaboration.</div>
      </div>
      <a href="#" class="limit-cta">Upgrade</a>
    </div>
  </div>
</div>

Extend with AI

Take This Snippet Further With AI

The AI prompt for this one is for Patreon supporters ($3 a month), along with a site with no ads. Supporters enter the passcode once and it is remembered in this browser.

· Become a supporter

What's included

Features

Trial days remaining: computed from TRIAL_START_DATE and TRIAL_DAYS at runtime
Progress bar: elapsed/total*100 fill, indigo→amber gradient matching urgency
Expiry date: computed and formatted as "Jun 7" from start + trial length
Dark indigo gradient banner: high contrast, amber highlight for urgency signals
Amber upgrade CTA: colour-coordinated with the days remaining urgency signal
Dismiss: max-height + opacity + padding collapse animation via JS
Feature limit warning card: contextual yellow-border card in content area
Both dismiss and limit card link to same upgrade URL for conversion consistency

About this UI Snippet

Trial Countdown Banner — Days Remaining, Trial Progress Bar, Expiry Date & Upgrade CTA

Screenshot of the Trial Countdown Banner snippet rendered live

A trial countdown banner keeps free trial users aware of their remaining trial time throughout their product session — the most effective in-product conversion mechanism for SaaS products. This snippet provides a complete in-app trial countdown system: a top banner with days remaining, a trial progress bar (Day X of 14), an expiry date, a high-contrast amber upgrade CTA, a dismiss button, and a separate feature limit warning card that appears in the main content area. For a persistent page-wide variant, see the upgrade banner snippet.

The trial countdown calculation

The initTrial() function computes elapsed and remaining days from the trial start date. elapsed = floor((now - start) / 86400000) — the difference in milliseconds divided by milliseconds per day. remaining = TRIAL_DAYS - elapsed. The progress bar fill percentage = elapsed / TRIAL_DAYS * 100. The expire date is computed by adding TRIAL_DAYS to the start date.

The banner design

A dark indigo gradient banner (linear-gradient from #1e1b4b to #312e81) sits at the top of the app shell. White text on the dark background provides high contrast. The days remaining number is highlighted in amber (#fbbf24) — the most urgent visual signal without red. The upgrade button also uses amber, creating visual alignment between the urgency signal and the action.

The trial progress bar

A horizontal progress bar shows how far through the trial the user is. The gradient fill goes from indigo to amber — moving toward the amber urgency colour as the trial nears its end. "Trial started" and "Trial ends" labels frame the bar. "Day X of 14" below gives exact context.

The feature limit warning card

A separate limit card appears in the main content area when the user approaches a free plan limit (4 of 5 projects used). This contextual prompt converts at a higher rate than the persistent banner alone — it triggers at the exact moment the user encounters the constraint.

Dismiss handling

The dismiss button collapses the banner via JavaScript animation (max-height from scrollHeight to 0). Uncommenting the localStorage line in dismissBanner() persists the dismiss across page loads. For server-rendered apps, save the dismiss timestamp to the user's account instead. For a fully server-rendered approach, add a dismissed_at timestamp to the user table and skip the banner HTML entirely when within the TTL.

Step by step

How to Use

  1. 1
    Set your trial start date and lengthIn the JS panel, set TRIAL_START_DATE to your user's actual trial start (from your database) and TRIAL_DAYS to your trial length (14 or 30 days). The banner auto-computes days remaining, progress bar fill, and expiry date.
  2. 2
    Wire the Upgrade CTASet href="#" on .upgrade-btn and .limit-cta to your billing page, Stripe checkout session, or upgrade flow URL. Use the same destination for both to keep the upgrade path consistent.
  3. 3
    Update the feature limit cardEdit .limit-title ("You've used 4 of 5 free projects") and .limit-sub to match your actual free plan limits. Show or hide this card based on the user's actual usage relative to the free tier threshold.
  4. 4
    Persist dismiss state across page loadsUncomment the localStorage line inside dismissBanner(): localStorage.setItem("trial_banner_dismissed","1"). On page load, check: if (localStorage.getItem("trial_banner_dismissed")) { banner.style.display = "none"; }
  5. 5
    Change the banner colour schemeThe banner uses a dark indigo gradient. For a lighter scheme, change background to linear-gradient(135deg, #eff6ff, #dbeafe) and text colour to #1e40af. Update the upgrade button to background: #1e40af and colour: #fff.
  6. 6
    Export in your formatClick "HTML" for a standalone file, "JSX" for a React component using a server-fetched trialStartDate prop and useState for dismissed state, or "Tailwind" for a Tailwind CSS version.

Real-world uses

Common Use Cases

SaaS free trial expiry and upgrade conversion
Show the banner to all users during their trial period. The amber days remaining and the progress bar create escalating urgency as the trial progresses. Users who see contextual upgrade prompts during their trial convert at 2–3× the rate of those who only see email reminders.
Feature-gated limit warning prompts
Show the limit card when users approach a free tier threshold (4/5 projects, 80% storage, 9/10 API calls). The contextual timing — at the moment the user hits the limit — captures them when they have the strongest motivation to upgrade.
Freemium plan limit and plan awareness banners
Adapt for freemium products without a trial: replace "days left in trial" with "free plan features". Show current usage (API calls this month, storage used, team seats), or pair it with a usage calculator so users can model the upgrade. The progress bar becomes a usage meter rather than a time countdown.
Multi-tier plan progression and upsell prompts
Show different banners per plan tier: Starter users see a Pro upsell, Pro users see a Team upsell. Customise the banner colour, CTA label, and feature list per tier. The consistent banner position means users learn to check it for their current usage status.
Study trial duration calculation and contextual conversion patterns
The trial countdown calculation — date arithmetic with Math.floor — demonstrates how to compute days elapsed and remaining from a stored start date. The contextual limit card demonstrates the product-led conversion pattern of triggering upgrade prompts at points of friction.
Server-rendered trial data injection for Next.js and server frameworks
In a server-rendered app, compute elapsed, remaining, and pct on the server from the user's trialStartDate in the database. Pass these as props to the banner component. The banner renders with the correct values immediately — no client-side calculation needed, no flash of uncalculated state.
Related: Auto-Detected Regional Pricing
See the Auto-Detected Regional Pricing for a related pricing pattern worth pairing with this one.

Got questions?

Frequently Asked Questions

initTrial() computes elapsed days: const elapsed = Math.floor((now - start) / 86400000). Both dates are set to midnight (setHours(0,0,0,0)) before subtraction to avoid time-zone and hour-of-day drift. 86400000 is the number of milliseconds in one day. remaining = TRIAL_DAYS - elapsed. Progress percentage = elapsed / TRIAL_DAYS * 100. The expiry date is computed by adding TRIAL_DAYS days to the start date using setDate(start.getDate() + TRIAL_DAYS).

Uncomment the localStorage line in dismissBanner(): localStorage.setItem("trial_banner_dismissed", "1"). At the end of initTrial(), add: if (localStorage.getItem("trial_banner_dismissed")) { document.getElementById("trial-banner").style.display = "none"; return; }. For a more sophisticated approach, store a timestamp and re-show the banner after 3 days: const dismissed = localStorage.getItem("trial_dismissed"); if (dismissed && Date.now() - parseInt(dismissed) < 3*24*3600000) return.

In initTrial(), check the remaining days and apply a different gradient class: if (remaining <= 3) { banner.style.background = "linear-gradient(135deg, #7f1d1d, #b91c1c)"; } else if (remaining <= 7) { banner.style.background = "linear-gradient(135deg, #78350f, #92400e)"; }. This creates a colour progression from indigo (comfortable) through amber (urgent) to red (critical) as the trial countdown reaches its final days.

Click "JSX" to download. Accept trialStartDate and trialDays as props from the server (fetched from your database in getServerSideProps or a Server Component). Compute elapsed, remaining, and pct in the component body or with useMemo. Manage dismissed with useState(false). Set the dismiss handler to call setDismissed(true) and optionally write to localStorage. Conditionally render: {!dismissed && <TrialBanner ... />}.