13 / 22
All 22 in 22 Tailwind CSS Countdown Timers
- 01Accessible Tailwind CSS Countdown Timer with ARIA Live Region
- 02Pure Tailwind CSS Countdown Timer Without JavaScript
- 03Tailwind Session Timeout Warning Modal with Countdown
- 04Tailwind Circular Countdown Timer with SVG Progress Ring
- 05Tailwind OTP Input with Resend Code Countdown Timer
- 06Tailwind Rate Limit Button with Retry-After Countdown
- 07Tailwind Auction Countdown Timer with Anti-Snipe Extension
- 08Tailwind Delivery ETA Countdown with Order Tracking Steps
- 09Tailwind Waitlist Landing Page with Launch Countdown
- 10Tailwind Webinar Countdown Timer with Time Zone Display
- 11Tailwind Appointment Reminder Card with Countdown
- 12Tailwind Exam Timer with Time Remaining Warnings
- 13Tailwind Free Trial Countdown Banner for SaaS Apps
- 14Tailwind Scheduled Maintenance Countdown Status Page
- 15Tailwind Virtual Waiting Room Queue Countdown
- 16Tailwind Daily Streak Countdown Widget for Habit Apps
- 17Tailwind Flash Sale Countdown Timer for Product Pages
- 18Tailwind Sticky Announcement Bar with Countdown Timer
- 19Tailwind Shopping Cart Reservation Countdown Timer
- 20Tailwind Coming Soon Page with Launch Countdown Timer
- 21Tailwind Interval Workout Timer with Circular Progress
- 22Tailwind Retro Flip Clock Countdown Timer
Tailwind Free Trial Countdown Banner for SaaS Apps
An in-app trial banner that escalates as the window closes: a calm violet state with seven days left, a magenta critical state inside the last two days, a depleting bar in both. Dismissal costs no script — a checkbox and has-checked: — and the port now collapses smoothly with a grid-rows-[1fr] → [0fr] transition and leaves a one-click Show again link behind.
Untitled UI Pro: 5,000+ React + Tailwind CSS v4 components · from $349 one-time
Untitled UI React · Affiliate link
The code
<section class="tcd-13 w-full min-h-svh bg-tcd13-page font-tcd13-sans text-tcd13-ink antialiased" aria-labelledby="tcd-13-title">
<div class="mx-auto grid min-h-svh max-w-[880px] content-center gap-5 px-[clamp(16px,4vw,48px)] py-14">
<h2 id="tcd-13-title" class="text-[clamp(18px,3vw,24px)] font-semibold tracking-[-0.02em]">Trial banner · two escalation states</h2>
<div class="rounded-2xl border border-tcd13-rule bg-tcd13-app p-3 shadow-tcd13-app">
<div aria-hidden="true" class="flex flex-wrap items-center gap-x-3 gap-y-1 border-b border-tcd13-rule px-2 pt-1 pb-3.5">
<span class="grid size-7 place-items-center rounded-lg bg-tcd13-ink text-xs font-bold text-white">Q</span>
<span class="text-sm font-bold">Quill</span>
<em class="text-xs not-italic text-tcd13-mut">Nova workspace · Alex Chen</em>
</div>
<div class="group/w mt-3 grid grid-rows-[1fr] transition-[grid-template-rows] duration-300 ease-out has-checked:grid-rows-[0fr] motion-reduce:transition-none">
<div class="min-h-0 overflow-hidden">
<input type="checkbox" id="tcd-13-d1" class="peer sr-only">
<div role="timer" data-state="calm" style="--left: 58%" class="relative grid grid-cols-[auto_minmax(0,1fr)_auto] sm:grid-cols-[auto_minmax(0,1fr)_auto_auto] items-center gap-x-3.5 gap-y-3 overflow-hidden rounded-xl border border-tcd13-acc/25 bg-tcd13-acc/6 py-3.5 pr-2 pl-4 transition-opacity group-has-checked/w:opacity-0 data-[state=critical]:border-tcd13-crit/30 data-[state=critical]:bg-tcd13-crit/8">
<span aria-hidden="true" class="grid size-9 place-items-center rounded-lg bg-tcd13-acc text-white"><svg viewBox="0 0 20 20" width="17" height="17"><circle cx="10" cy="10" r="7.6" fill="none" stroke="currentColor" stroke-width="1.6"/><path d="M10 6v4.3l2.8 1.7" fill="none" stroke="currentColor" stroke-width="1.6" stroke-linecap="round"/></svg></span>
<p class="min-w-0 text-[14px] leading-snug text-pretty"><strong class="font-semibold"><time datetime="P7D">7 days left</time> in your trial.</strong> <span class="text-tcd13-mut">Keep unlimited documents and version history by adding a plan.</span></p>
<label for="tcd-13-d1" class="col-start-3 row-start-1 grid size-11 cursor-pointer place-items-center rounded-lg text-tcd13-mut transition hover:bg-tcd13-ink/5 hover:text-tcd13-ink peer-focus-visible:outline-2 peer-focus-visible:outline-tcd13-acc sm:col-start-4"><span class="sr-only">Dismiss trial banner for this session</span><svg viewBox="0 0 14 14" width="13" height="13" aria-hidden="true"><path d="M2.5 2.5l9 9M11.5 2.5l-9 9" stroke="currentColor" stroke-width="1.7" stroke-linecap="round"/></svg></label>
<button type="button" class="col-span-3 row-start-2 min-h-11 cursor-pointer rounded-lg bg-tcd13-acc px-4 text-sm font-semibold whitespace-nowrap text-white transition hover:brightness-110 focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-tcd13-ink sm:col-span-1 sm:col-start-3 sm:row-start-1">Choose a plan</button>
<div aria-hidden="true" class="absolute inset-x-0 bottom-0 h-[3px] bg-tcd13-acc/15"><i class="block h-full w-(--left) rounded-r-full bg-tcd13-acc"></i></div>
</div>
</div>
<label for="tcd-13-d1" class="hidden min-h-11 cursor-pointer items-center gap-2 px-2 text-[13px] font-semibold text-tcd13-acc underline-offset-4 hover:underline group-has-checked/w:flex">↺ Show the 7-day trial banner again</label>
</div>
<div class="group/w mt-2.5 grid grid-rows-[1fr] transition-[grid-template-rows] duration-300 ease-out has-checked:grid-rows-[0fr] motion-reduce:transition-none">
<div class="min-h-0 overflow-hidden">
<input type="checkbox" id="tcd-13-d2" class="peer sr-only">
<div role="timer" data-state="critical" style="--left: 9%" class="relative grid grid-cols-[auto_minmax(0,1fr)_auto] sm:grid-cols-[auto_minmax(0,1fr)_auto_auto] items-center gap-x-3.5 gap-y-3 overflow-hidden rounded-xl border border-tcd13-acc/25 bg-tcd13-acc/6 py-3.5 pr-2 pl-4 transition-opacity group-has-checked/w:opacity-0 data-[state=critical]:border-tcd13-crit/30 data-[state=critical]:bg-tcd13-crit/8">
<span aria-hidden="true" class="grid size-9 place-items-center rounded-lg bg-tcd13-crit text-white"><svg viewBox="0 0 20 20" width="17" height="17"><path d="M10 2.4 1.6 16.6h16.8L10 2.4Z" fill="none" stroke="currentColor" stroke-width="1.6" stroke-linejoin="round"/><path d="M10 7.4v4.1M10 13.4v1" stroke="currentColor" stroke-width="1.6"/></svg></span>
<p class="min-w-0 text-[14px] leading-snug text-pretty"><strong class="font-semibold text-tcd13-crit-ink"><time datetime="PT41H">41 hours left</time> — then editing locks.</strong> <span class="text-tcd13-mut">Your documents stay safe and read-only. No card on file yet.</span></p>
<label for="tcd-13-d2" class="col-start-3 row-start-1 grid size-11 cursor-pointer place-items-center rounded-lg text-tcd13-mut transition hover:bg-tcd13-ink/5 hover:text-tcd13-ink peer-focus-visible:outline-2 peer-focus-visible:outline-tcd13-crit sm:col-start-4"><span class="sr-only">Dismiss trial banner for this session</span><svg viewBox="0 0 14 14" width="13" height="13" aria-hidden="true"><path d="M2.5 2.5l9 9M11.5 2.5l-9 9" stroke="currentColor" stroke-width="1.7" stroke-linecap="round"/></svg></label>
<button type="button" class="col-span-3 row-start-2 min-h-11 cursor-pointer rounded-lg bg-tcd13-crit px-4 text-sm font-semibold whitespace-nowrap text-white transition hover:brightness-110 focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-tcd13-ink sm:col-span-1 sm:col-start-3 sm:row-start-1">Add payment method</button>
<div aria-hidden="true" class="absolute inset-x-0 bottom-0 h-[3px] bg-tcd13-crit/15"><i class="block h-full w-(--left) rounded-r-full bg-tcd13-crit animate-pulse motion-reduce:animate-none"></i></div>
</div>
</div>
<label for="tcd-13-d2" class="hidden min-h-11 cursor-pointer items-center gap-2 px-2 text-[13px] font-semibold text-tcd13-crit-ink underline-offset-4 hover:underline group-has-checked/w:flex">↺ Show the 41-hour trial banner again</label>
</div>
<div aria-hidden="true" class="mt-4 grid gap-2.5 px-2 pt-2 pb-3"><span class="h-4 w-[42%] rounded-md bg-tcd13-rule"></span><span class="h-2.5 rounded-md bg-tcd13-rule/70"></span><span class="h-2.5 rounded-md bg-tcd13-rule/70"></span><span class="h-2.5 w-[63%] rounded-md bg-tcd13-rule/70"></span></div>
</div>
<p class="text-[12.5px] leading-relaxed text-tcd13-mut text-pretty">An authenticated in-app surface scoped to one workspace, not a site-wide promo bar. Dismissal is a checkbox plus <code class="rounded bg-tcd13-rule px-1 py-0.5 text-[11.5px] text-tcd13-ink">has-checked:</code>, so it lasts for the session, animates closed and costs no script.</p>
</div>
</section><section class="tcd-13 w-full min-h-svh bg-tcd13-page font-tcd13-sans text-tcd13-ink antialiased" aria-labelledby="tcd-13-title">
<div class="mx-auto grid min-h-svh max-w-[880px] content-center gap-5 px-[clamp(16px,4vw,48px)] py-14">
<h2 id="tcd-13-title" class="text-[clamp(18px,3vw,24px)] font-semibold tracking-[-0.02em]">Trial banner · two escalation states</h2>
<div class="rounded-2xl border border-tcd13-rule bg-tcd13-app p-3 shadow-tcd13-app">
<div aria-hidden="true" class="flex flex-wrap items-center gap-x-3 gap-y-1 border-b border-tcd13-rule px-2 pt-1 pb-3.5">
<span class="grid size-7 place-items-center rounded-lg bg-tcd13-ink text-xs font-bold text-white">Q</span>
<span class="text-sm font-bold">Quill</span>
<em class="text-xs not-italic text-tcd13-mut">Nova workspace · Alex Chen</em>
</div>
<div class="group/w mt-3 grid grid-rows-[1fr] transition-[grid-template-rows] duration-300 ease-out has-checked:grid-rows-[0fr] motion-reduce:transition-none">
<div class="min-h-0 overflow-hidden">
<input type="checkbox" id="tcd-13-d1" class="peer sr-only">
<div role="timer" data-state="calm" style="--left: 58%" class="relative grid grid-cols-[auto_minmax(0,1fr)_auto] sm:grid-cols-[auto_minmax(0,1fr)_auto_auto] items-center gap-x-3.5 gap-y-3 overflow-hidden rounded-xl border border-tcd13-acc/25 bg-tcd13-acc/6 py-3.5 pr-2 pl-4 transition-opacity group-has-checked/w:opacity-0 data-[state=critical]:border-tcd13-crit/30 data-[state=critical]:bg-tcd13-crit/8">
<span aria-hidden="true" class="grid size-9 place-items-center rounded-lg bg-tcd13-acc text-white"><svg viewBox="0 0 20 20" width="17" height="17"><circle cx="10" cy="10" r="7.6" fill="none" stroke="currentColor" stroke-width="1.6"/><path d="M10 6v4.3l2.8 1.7" fill="none" stroke="currentColor" stroke-width="1.6" stroke-linecap="round"/></svg></span>
<p class="min-w-0 text-[14px] leading-snug text-pretty"><strong class="font-semibold"><time datetime="P7D">7 days left</time> in your trial.</strong> <span class="text-tcd13-mut">Keep unlimited documents and version history by adding a plan.</span></p>
<label for="tcd-13-d1" class="col-start-3 row-start-1 grid size-11 cursor-pointer place-items-center rounded-lg text-tcd13-mut transition hover:bg-tcd13-ink/5 hover:text-tcd13-ink peer-focus-visible:outline-2 peer-focus-visible:outline-tcd13-acc sm:col-start-4"><span class="sr-only">Dismiss trial banner for this session</span><svg viewBox="0 0 14 14" width="13" height="13" aria-hidden="true"><path d="M2.5 2.5l9 9M11.5 2.5l-9 9" stroke="currentColor" stroke-width="1.7" stroke-linecap="round"/></svg></label>
<button type="button" class="col-span-3 row-start-2 min-h-11 cursor-pointer rounded-lg bg-tcd13-acc px-4 text-sm font-semibold whitespace-nowrap text-white transition hover:brightness-110 focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-tcd13-ink sm:col-span-1 sm:col-start-3 sm:row-start-1">Choose a plan</button>
<div aria-hidden="true" class="absolute inset-x-0 bottom-0 h-[3px] bg-tcd13-acc/15"><i class="block h-full w-(--left) rounded-r-full bg-tcd13-acc"></i></div>
</div>
</div>
<label for="tcd-13-d1" class="hidden min-h-11 cursor-pointer items-center gap-2 px-2 text-[13px] font-semibold text-tcd13-acc underline-offset-4 hover:underline group-has-checked/w:flex">↺ Show the 7-day trial banner again</label>
</div>
<div class="group/w mt-2.5 grid grid-rows-[1fr] transition-[grid-template-rows] duration-300 ease-out has-checked:grid-rows-[0fr] motion-reduce:transition-none">
<div class="min-h-0 overflow-hidden">
<input type="checkbox" id="tcd-13-d2" class="peer sr-only">
<div role="timer" data-state="critical" style="--left: 9%" class="relative grid grid-cols-[auto_minmax(0,1fr)_auto] sm:grid-cols-[auto_minmax(0,1fr)_auto_auto] items-center gap-x-3.5 gap-y-3 overflow-hidden rounded-xl border border-tcd13-acc/25 bg-tcd13-acc/6 py-3.5 pr-2 pl-4 transition-opacity group-has-checked/w:opacity-0 data-[state=critical]:border-tcd13-crit/30 data-[state=critical]:bg-tcd13-crit/8">
<span aria-hidden="true" class="grid size-9 place-items-center rounded-lg bg-tcd13-crit text-white"><svg viewBox="0 0 20 20" width="17" height="17"><path d="M10 2.4 1.6 16.6h16.8L10 2.4Z" fill="none" stroke="currentColor" stroke-width="1.6" stroke-linejoin="round"/><path d="M10 7.4v4.1M10 13.4v1" stroke="currentColor" stroke-width="1.6"/></svg></span>
<p class="min-w-0 text-[14px] leading-snug text-pretty"><strong class="font-semibold text-tcd13-crit-ink"><time datetime="PT41H">41 hours left</time> — then editing locks.</strong> <span class="text-tcd13-mut">Your documents stay safe and read-only. No card on file yet.</span></p>
<label for="tcd-13-d2" class="col-start-3 row-start-1 grid size-11 cursor-pointer place-items-center rounded-lg text-tcd13-mut transition hover:bg-tcd13-ink/5 hover:text-tcd13-ink peer-focus-visible:outline-2 peer-focus-visible:outline-tcd13-crit sm:col-start-4"><span class="sr-only">Dismiss trial banner for this session</span><svg viewBox="0 0 14 14" width="13" height="13" aria-hidden="true"><path d="M2.5 2.5l9 9M11.5 2.5l-9 9" stroke="currentColor" stroke-width="1.7" stroke-linecap="round"/></svg></label>
<button type="button" class="col-span-3 row-start-2 min-h-11 cursor-pointer rounded-lg bg-tcd13-crit px-4 text-sm font-semibold whitespace-nowrap text-white transition hover:brightness-110 focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-tcd13-ink sm:col-span-1 sm:col-start-3 sm:row-start-1">Add payment method</button>
<div aria-hidden="true" class="absolute inset-x-0 bottom-0 h-[3px] bg-tcd13-crit/15"><i class="block h-full w-(--left) rounded-r-full bg-tcd13-crit animate-pulse motion-reduce:animate-none"></i></div>
</div>
</div>
<label for="tcd-13-d2" class="hidden min-h-11 cursor-pointer items-center gap-2 px-2 text-[13px] font-semibold text-tcd13-crit-ink underline-offset-4 hover:underline group-has-checked/w:flex">↺ Show the 41-hour trial banner again</label>
</div>
<div aria-hidden="true" class="mt-4 grid gap-2.5 px-2 pt-2 pb-3"><span class="h-4 w-[42%] rounded-md bg-tcd13-rule"></span><span class="h-2.5 rounded-md bg-tcd13-rule/70"></span><span class="h-2.5 rounded-md bg-tcd13-rule/70"></span><span class="h-2.5 w-[63%] rounded-md bg-tcd13-rule/70"></span></div>
</div>
<p class="text-[12.5px] leading-relaxed text-tcd13-mut text-pretty">An authenticated in-app surface scoped to one workspace, not a site-wide promo bar. Dismissal is a checkbox plus <code class="rounded bg-tcd13-rule px-1 py-0.5 text-[11.5px] text-tcd13-ink">has-checked:</code>, so it lasts for the session, animates closed and costs no script.</p>
</div>
</section>@import "tailwindcss";
@theme {
--color-tcd13-page: #f7f5fd;
--color-tcd13-page: oklch(0.97 0.014 300);
--color-tcd13-app: #ffffff;
--color-tcd13-app: oklch(1 0 0);
--color-tcd13-ink: #191430;
--color-tcd13-ink: oklch(0.23 0.06 300);
--color-tcd13-mut: #5c537f;
--color-tcd13-mut: oklch(0.46 0.06 300);
--color-tcd13-rule: #e6e1f5;
--color-tcd13-rule: oklch(0.92 0.02 300);
--color-tcd13-acc: #6d3ce0;
--color-tcd13-acc: oklch(0.52 0.22 295);
--color-tcd13-crit: #d61f7a;
--color-tcd13-crit: oklch(0.56 0.24 350);
--color-tcd13-crit-ink: #a3135b;
--color-tcd13-crit-ink: oklch(0.46 0.2 350);
--font-tcd13-sans: 'Space Grotesk', system-ui, sans-serif;
--shadow-tcd13-app: 0 20px 46px -30px rgb(109 60 224 / 0.5);
}
.tcd-13 {
width: 100%;
min-height: 100svh;
}@import "tailwindcss";
@theme {
--color-tcd13-page: #f7f5fd;
--color-tcd13-page: oklch(0.97 0.014 300);
--color-tcd13-app: #ffffff;
--color-tcd13-app: oklch(1 0 0);
--color-tcd13-ink: #191430;
--color-tcd13-ink: oklch(0.23 0.06 300);
--color-tcd13-mut: #5c537f;
--color-tcd13-mut: oklch(0.46 0.06 300);
--color-tcd13-rule: #e6e1f5;
--color-tcd13-rule: oklch(0.92 0.02 300);
--color-tcd13-acc: #6d3ce0;
--color-tcd13-acc: oklch(0.52 0.22 295);
--color-tcd13-crit: #d61f7a;
--color-tcd13-crit: oklch(0.56 0.24 350);
--color-tcd13-crit-ink: #a3135b;
--color-tcd13-crit-ink: oklch(0.46 0.2 350);
--font-tcd13-sans: 'Space Grotesk', system-ui, sans-serif;
--shadow-tcd13-app: 0 20px 46px -30px rgb(109 60 224 / 0.5);
}
.tcd-13 {
width: 100%;
min-height: 100svh;
}Setup — do this once per project
Skip this if your project already runs Tailwind v4.
<script src="https://cdn.jsdelivr.net/npm/@tailwindcss/browser@4"></script>
<script src="https://cdn.jsdelivr.net/npm/@tailwindcss/browser@4"></script>Compiles in the browser — perfect for a CodePen or a quick test, not for production.
npm install tailwindcss @tailwindcss/vite
npm install tailwindcss @tailwindcss/vite// vite.config.js ("type": "module" in package.json)
import { defineConfig } from 'vite'
import tailwindcss from '@tailwindcss/vite'
export default defineConfig({
plugins: [tailwindcss()],
})// vite.config.js ("type": "module" in package.json)
import { defineConfig } from 'vite'
import tailwindcss from '@tailwindcss/vite'
export default defineConfig({
plugins: [tailwindcss()],
})Any v4 setup works — Vite, PostCSS or the CLI. Nothing in this demo is bundler-specific.
@import "tailwindcss";
@theme {
--color-tcd13-page: #f7f5fd;
--color-tcd13-page: oklch(0.97 0.014 300);
--color-tcd13-app: #ffffff;
--color-tcd13-app: oklch(1 0 0);
--color-tcd13-ink: #191430;
--color-tcd13-ink: oklch(0.23 0.06 300);
--color-tcd13-mut: #5c537f;
--color-tcd13-mut: oklch(0.46 0.06 300);
--color-tcd13-rule: #e6e1f5;
--color-tcd13-rule: oklch(0.92 0.02 300);
--color-tcd13-acc: #6d3ce0;
--color-tcd13-acc: oklch(0.52 0.22 295);
--color-tcd13-crit: #d61f7a;
--color-tcd13-crit: oklch(0.56 0.24 350);
--color-tcd13-crit-ink: #a3135b;
--color-tcd13-crit-ink: oklch(0.46 0.2 350);
--font-tcd13-sans: 'Space Grotesk', system-ui, sans-serif;
--shadow-tcd13-app: 0 20px 46px -30px rgb(109 60 224 / 0.5);
}
.tcd-13 {
width: 100%;
min-height: 100svh;
}@import "tailwindcss";
@theme {
--color-tcd13-page: #f7f5fd;
--color-tcd13-page: oklch(0.97 0.014 300);
--color-tcd13-app: #ffffff;
--color-tcd13-app: oklch(1 0 0);
--color-tcd13-ink: #191430;
--color-tcd13-ink: oklch(0.23 0.06 300);
--color-tcd13-mut: #5c537f;
--color-tcd13-mut: oklch(0.46 0.06 300);
--color-tcd13-rule: #e6e1f5;
--color-tcd13-rule: oklch(0.92 0.02 300);
--color-tcd13-acc: #6d3ce0;
--color-tcd13-acc: oklch(0.52 0.22 295);
--color-tcd13-crit: #d61f7a;
--color-tcd13-crit: oklch(0.56 0.24 350);
--color-tcd13-crit-ink: #a3135b;
--color-tcd13-crit-ink: oklch(0.46 0.2 350);
--font-tcd13-sans: 'Space Grotesk', system-ui, sans-serif;
--shadow-tcd13-app: 0 20px 46px -30px rgb(109 60 224 / 0.5);
}
.tcd-13 {
width: 100%;
min-height: 100svh;
}<link rel="preconnect" href="https://fonts.googleapis.com"> <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin> <link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Space+Grotesk:wght@400;500;600;700&display=swap">
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Space+Grotesk:wght@400;500;600;700&display=swap">What changed in the port
Which parts became utilities, which stayed CSS, and why.
.cdt-13__wrap:has(.cdt-13__x:checked) .cdt-13__banner { display:none }becamehas-checked:grid-rows-[0fr]on the wrapper — the same zero-JS trigger, now animated.style="--left: 58%"survives unchanged; the bar reads it with v4'sw-(--left)shorthand instead of a.cdt-13__bar i { inline-size: var(--left) }rule.- UI upgrade: dismissal collapses smoothly and leaves a Show again label behind, so an accidental click is undoable; the close target grew to 44px with a visible focus ring via
peer-focus-visible:. - UI upgrade: the critical bar pulses, the critical headline uses a darker magenta for 6:1 contrast on the tint, and the CTA drops below the copy on phones instead of squeezing it.
Here's a working CSS demo from CodeFronts. Use it as-is or adapt to your framework. All classes are scoped under a unique prefix so the code won't collide with your existing styles. MIT licensed.
Demo: Tailwind Free Trial Countdown Banner for SaaS Apps
Source: https://codefronts.com/snippets/tailwind-css-countdown-timers/tailwind-free-trial-countdown-banner-saas/
An in-app trial banner that escalates as the window closes: a calm violet state with seven days left, a magenta critical state inside the last two days, a depleting bar in both. Dismissal costs no script — a checkbox and has-checked: — and the port now collapses smoothly with a grid-rows-[1fr] → [0fr] transition and leaves a one-click Show again link behind.
## HTML
```html
<section class="tcd-13 w-full min-h-svh bg-tcd13-page font-tcd13-sans text-tcd13-ink antialiased" aria-labelledby="tcd-13-title">
<div class="mx-auto grid min-h-svh max-w-[880px] content-center gap-5 px-[clamp(16px,4vw,48px)] py-14">
<h2 id="tcd-13-title" class="text-[clamp(18px,3vw,24px)] font-semibold tracking-[-0.02em]">Trial banner · two escalation states</h2>
<div class="rounded-2xl border border-tcd13-rule bg-tcd13-app p-3 shadow-tcd13-app">
<div aria-hidden="true" class="flex flex-wrap items-center gap-x-3 gap-y-1 border-b border-tcd13-rule px-2 pt-1 pb-3.5">
<span class="grid size-7 place-items-center rounded-lg bg-tcd13-ink text-xs font-bold text-white">Q</span>
<span class="text-sm font-bold">Quill</span>
<em class="text-xs not-italic text-tcd13-mut">Nova workspace · Alex Chen</em>
</div>
<div class="group/w mt-3 grid grid-rows-[1fr] transition-[grid-template-rows] duration-300 ease-out has-checked:grid-rows-[0fr] motion-reduce:transition-none">
<div class="min-h-0 overflow-hidden">
<input type="checkbox" id="tcd-13-d1" class="peer sr-only">
<div role="timer" data-state="calm" style="--left: 58%" class="relative grid grid-cols-[auto_minmax(0,1fr)_auto] sm:grid-cols-[auto_minmax(0,1fr)_auto_auto] items-center gap-x-3.5 gap-y-3 overflow-hidden rounded-xl border border-tcd13-acc/25 bg-tcd13-acc/6 py-3.5 pr-2 pl-4 transition-opacity group-has-checked/w:opacity-0 data-[state=critical]:border-tcd13-crit/30 data-[state=critical]:bg-tcd13-crit/8">
<span aria-hidden="true" class="grid size-9 place-items-center rounded-lg bg-tcd13-acc text-white"><svg viewBox="0 0 20 20" width="17" height="17"><circle cx="10" cy="10" r="7.6" fill="none" stroke="currentColor" stroke-width="1.6"/><path d="M10 6v4.3l2.8 1.7" fill="none" stroke="currentColor" stroke-width="1.6" stroke-linecap="round"/></svg></span>
<p class="min-w-0 text-[14px] leading-snug text-pretty"><strong class="font-semibold"><time datetime="P7D">7 days left</time> in your trial.</strong> <span class="text-tcd13-mut">Keep unlimited documents and version history by adding a plan.</span></p>
<label for="tcd-13-d1" class="col-start-3 row-start-1 grid size-11 cursor-pointer place-items-center rounded-lg text-tcd13-mut transition hover:bg-tcd13-ink/5 hover:text-tcd13-ink peer-focus-visible:outline-2 peer-focus-visible:outline-tcd13-acc sm:col-start-4"><span class="sr-only">Dismiss trial banner for this session</span><svg viewBox="0 0 14 14" width="13" height="13" aria-hidden="true"><path d="M2.5 2.5l9 9M11.5 2.5l-9 9" stroke="currentColor" stroke-width="1.7" stroke-linecap="round"/></svg></label>
<button type="button" class="col-span-3 row-start-2 min-h-11 cursor-pointer rounded-lg bg-tcd13-acc px-4 text-sm font-semibold whitespace-nowrap text-white transition hover:brightness-110 focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-tcd13-ink sm:col-span-1 sm:col-start-3 sm:row-start-1">Choose a plan</button>
<div aria-hidden="true" class="absolute inset-x-0 bottom-0 h-[3px] bg-tcd13-acc/15"><i class="block h-full w-(--left) rounded-r-full bg-tcd13-acc"></i></div>
</div>
</div>
<label for="tcd-13-d1" class="hidden min-h-11 cursor-pointer items-center gap-2 px-2 text-[13px] font-semibold text-tcd13-acc underline-offset-4 hover:underline group-has-checked/w:flex">↺ Show the 7-day trial banner again</label>
</div>
<div class="group/w mt-2.5 grid grid-rows-[1fr] transition-[grid-template-rows] duration-300 ease-out has-checked:grid-rows-[0fr] motion-reduce:transition-none">
<div class="min-h-0 overflow-hidden">
<input type="checkbox" id="tcd-13-d2" class="peer sr-only">
<div role="timer" data-state="critical" style="--left: 9%" class="relative grid grid-cols-[auto_minmax(0,1fr)_auto] sm:grid-cols-[auto_minmax(0,1fr)_auto_auto] items-center gap-x-3.5 gap-y-3 overflow-hidden rounded-xl border border-tcd13-acc/25 bg-tcd13-acc/6 py-3.5 pr-2 pl-4 transition-opacity group-has-checked/w:opacity-0 data-[state=critical]:border-tcd13-crit/30 data-[state=critical]:bg-tcd13-crit/8">
<span aria-hidden="true" class="grid size-9 place-items-center rounded-lg bg-tcd13-crit text-white"><svg viewBox="0 0 20 20" width="17" height="17"><path d="M10 2.4 1.6 16.6h16.8L10 2.4Z" fill="none" stroke="currentColor" stroke-width="1.6" stroke-linejoin="round"/><path d="M10 7.4v4.1M10 13.4v1" stroke="currentColor" stroke-width="1.6"/></svg></span>
<p class="min-w-0 text-[14px] leading-snug text-pretty"><strong class="font-semibold text-tcd13-crit-ink"><time datetime="PT41H">41 hours left</time> — then editing locks.</strong> <span class="text-tcd13-mut">Your documents stay safe and read-only. No card on file yet.</span></p>
<label for="tcd-13-d2" class="col-start-3 row-start-1 grid size-11 cursor-pointer place-items-center rounded-lg text-tcd13-mut transition hover:bg-tcd13-ink/5 hover:text-tcd13-ink peer-focus-visible:outline-2 peer-focus-visible:outline-tcd13-crit sm:col-start-4"><span class="sr-only">Dismiss trial banner for this session</span><svg viewBox="0 0 14 14" width="13" height="13" aria-hidden="true"><path d="M2.5 2.5l9 9M11.5 2.5l-9 9" stroke="currentColor" stroke-width="1.7" stroke-linecap="round"/></svg></label>
<button type="button" class="col-span-3 row-start-2 min-h-11 cursor-pointer rounded-lg bg-tcd13-crit px-4 text-sm font-semibold whitespace-nowrap text-white transition hover:brightness-110 focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-tcd13-ink sm:col-span-1 sm:col-start-3 sm:row-start-1">Add payment method</button>
<div aria-hidden="true" class="absolute inset-x-0 bottom-0 h-[3px] bg-tcd13-crit/15"><i class="block h-full w-(--left) rounded-r-full bg-tcd13-crit animate-pulse motion-reduce:animate-none"></i></div>
</div>
</div>
<label for="tcd-13-d2" class="hidden min-h-11 cursor-pointer items-center gap-2 px-2 text-[13px] font-semibold text-tcd13-crit-ink underline-offset-4 hover:underline group-has-checked/w:flex">↺ Show the 41-hour trial banner again</label>
</div>
<div aria-hidden="true" class="mt-4 grid gap-2.5 px-2 pt-2 pb-3"><span class="h-4 w-[42%] rounded-md bg-tcd13-rule"></span><span class="h-2.5 rounded-md bg-tcd13-rule/70"></span><span class="h-2.5 rounded-md bg-tcd13-rule/70"></span><span class="h-2.5 w-[63%] rounded-md bg-tcd13-rule/70"></span></div>
</div>
<p class="text-[12.5px] leading-relaxed text-tcd13-mut text-pretty">An authenticated in-app surface scoped to one workspace, not a site-wide promo bar. Dismissal is a checkbox plus <code class="rounded bg-tcd13-rule px-1 py-0.5 text-[11.5px] text-tcd13-ink">has-checked:</code>, so it lasts for the session, animates closed and costs no script.</p>
</div>
</section>
```
## CSS
```css
@import "tailwindcss";
@theme {
--color-tcd13-page: #f7f5fd;
--color-tcd13-page: oklch(0.97 0.014 300);
--color-tcd13-app: #ffffff;
--color-tcd13-app: oklch(1 0 0);
--color-tcd13-ink: #191430;
--color-tcd13-ink: oklch(0.23 0.06 300);
--color-tcd13-mut: #5c537f;
--color-tcd13-mut: oklch(0.46 0.06 300);
--color-tcd13-rule: #e6e1f5;
--color-tcd13-rule: oklch(0.92 0.02 300);
--color-tcd13-acc: #6d3ce0;
--color-tcd13-acc: oklch(0.52 0.22 295);
--color-tcd13-crit: #d61f7a;
--color-tcd13-crit: oklch(0.56 0.24 350);
--color-tcd13-crit-ink: #a3135b;
--color-tcd13-crit-ink: oklch(0.46 0.2 350);
--font-tcd13-sans: 'Space Grotesk', system-ui, sans-serif;
--shadow-tcd13-app: 0 20px 46px -30px rgb(109 60 224 / 0.5);
}
.tcd-13 {
width: 100%;
min-height: 100svh;
}
```Here's a working CSS demo from CodeFronts. Use it as-is or adapt to your framework. All classes are scoped under a unique prefix so the code won't collide with your existing styles. MIT licensed.
Demo: Tailwind Free Trial Countdown Banner for SaaS Apps
Source: https://codefronts.com/snippets/tailwind-css-countdown-timers/tailwind-free-trial-countdown-banner-saas/
An in-app trial banner that escalates as the window closes: a calm violet state with seven days left, a magenta critical state inside the last two days, a depleting bar in both. Dismissal costs no script — a checkbox and has-checked: — and the port now collapses smoothly with a grid-rows-[1fr] → [0fr] transition and leaves a one-click Show again link behind.
## HTML
```html
<section class="tcd-13 w-full min-h-svh bg-tcd13-page font-tcd13-sans text-tcd13-ink antialiased" aria-labelledby="tcd-13-title">
<div class="mx-auto grid min-h-svh max-w-[880px] content-center gap-5 px-[clamp(16px,4vw,48px)] py-14">
<h2 id="tcd-13-title" class="text-[clamp(18px,3vw,24px)] font-semibold tracking-[-0.02em]">Trial banner · two escalation states</h2>
<div class="rounded-2xl border border-tcd13-rule bg-tcd13-app p-3 shadow-tcd13-app">
<div aria-hidden="true" class="flex flex-wrap items-center gap-x-3 gap-y-1 border-b border-tcd13-rule px-2 pt-1 pb-3.5">
<span class="grid size-7 place-items-center rounded-lg bg-tcd13-ink text-xs font-bold text-white">Q</span>
<span class="text-sm font-bold">Quill</span>
<em class="text-xs not-italic text-tcd13-mut">Nova workspace · Alex Chen</em>
</div>
<div class="group/w mt-3 grid grid-rows-[1fr] transition-[grid-template-rows] duration-300 ease-out has-checked:grid-rows-[0fr] motion-reduce:transition-none">
<div class="min-h-0 overflow-hidden">
<input type="checkbox" id="tcd-13-d1" class="peer sr-only">
<div role="timer" data-state="calm" style="--left: 58%" class="relative grid grid-cols-[auto_minmax(0,1fr)_auto] sm:grid-cols-[auto_minmax(0,1fr)_auto_auto] items-center gap-x-3.5 gap-y-3 overflow-hidden rounded-xl border border-tcd13-acc/25 bg-tcd13-acc/6 py-3.5 pr-2 pl-4 transition-opacity group-has-checked/w:opacity-0 data-[state=critical]:border-tcd13-crit/30 data-[state=critical]:bg-tcd13-crit/8">
<span aria-hidden="true" class="grid size-9 place-items-center rounded-lg bg-tcd13-acc text-white"><svg viewBox="0 0 20 20" width="17" height="17"><circle cx="10" cy="10" r="7.6" fill="none" stroke="currentColor" stroke-width="1.6"/><path d="M10 6v4.3l2.8 1.7" fill="none" stroke="currentColor" stroke-width="1.6" stroke-linecap="round"/></svg></span>
<p class="min-w-0 text-[14px] leading-snug text-pretty"><strong class="font-semibold"><time datetime="P7D">7 days left</time> in your trial.</strong> <span class="text-tcd13-mut">Keep unlimited documents and version history by adding a plan.</span></p>
<label for="tcd-13-d1" class="col-start-3 row-start-1 grid size-11 cursor-pointer place-items-center rounded-lg text-tcd13-mut transition hover:bg-tcd13-ink/5 hover:text-tcd13-ink peer-focus-visible:outline-2 peer-focus-visible:outline-tcd13-acc sm:col-start-4"><span class="sr-only">Dismiss trial banner for this session</span><svg viewBox="0 0 14 14" width="13" height="13" aria-hidden="true"><path d="M2.5 2.5l9 9M11.5 2.5l-9 9" stroke="currentColor" stroke-width="1.7" stroke-linecap="round"/></svg></label>
<button type="button" class="col-span-3 row-start-2 min-h-11 cursor-pointer rounded-lg bg-tcd13-acc px-4 text-sm font-semibold whitespace-nowrap text-white transition hover:brightness-110 focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-tcd13-ink sm:col-span-1 sm:col-start-3 sm:row-start-1">Choose a plan</button>
<div aria-hidden="true" class="absolute inset-x-0 bottom-0 h-[3px] bg-tcd13-acc/15"><i class="block h-full w-(--left) rounded-r-full bg-tcd13-acc"></i></div>
</div>
</div>
<label for="tcd-13-d1" class="hidden min-h-11 cursor-pointer items-center gap-2 px-2 text-[13px] font-semibold text-tcd13-acc underline-offset-4 hover:underline group-has-checked/w:flex">↺ Show the 7-day trial banner again</label>
</div>
<div class="group/w mt-2.5 grid grid-rows-[1fr] transition-[grid-template-rows] duration-300 ease-out has-checked:grid-rows-[0fr] motion-reduce:transition-none">
<div class="min-h-0 overflow-hidden">
<input type="checkbox" id="tcd-13-d2" class="peer sr-only">
<div role="timer" data-state="critical" style="--left: 9%" class="relative grid grid-cols-[auto_minmax(0,1fr)_auto] sm:grid-cols-[auto_minmax(0,1fr)_auto_auto] items-center gap-x-3.5 gap-y-3 overflow-hidden rounded-xl border border-tcd13-acc/25 bg-tcd13-acc/6 py-3.5 pr-2 pl-4 transition-opacity group-has-checked/w:opacity-0 data-[state=critical]:border-tcd13-crit/30 data-[state=critical]:bg-tcd13-crit/8">
<span aria-hidden="true" class="grid size-9 place-items-center rounded-lg bg-tcd13-crit text-white"><svg viewBox="0 0 20 20" width="17" height="17"><path d="M10 2.4 1.6 16.6h16.8L10 2.4Z" fill="none" stroke="currentColor" stroke-width="1.6" stroke-linejoin="round"/><path d="M10 7.4v4.1M10 13.4v1" stroke="currentColor" stroke-width="1.6"/></svg></span>
<p class="min-w-0 text-[14px] leading-snug text-pretty"><strong class="font-semibold text-tcd13-crit-ink"><time datetime="PT41H">41 hours left</time> — then editing locks.</strong> <span class="text-tcd13-mut">Your documents stay safe and read-only. No card on file yet.</span></p>
<label for="tcd-13-d2" class="col-start-3 row-start-1 grid size-11 cursor-pointer place-items-center rounded-lg text-tcd13-mut transition hover:bg-tcd13-ink/5 hover:text-tcd13-ink peer-focus-visible:outline-2 peer-focus-visible:outline-tcd13-crit sm:col-start-4"><span class="sr-only">Dismiss trial banner for this session</span><svg viewBox="0 0 14 14" width="13" height="13" aria-hidden="true"><path d="M2.5 2.5l9 9M11.5 2.5l-9 9" stroke="currentColor" stroke-width="1.7" stroke-linecap="round"/></svg></label>
<button type="button" class="col-span-3 row-start-2 min-h-11 cursor-pointer rounded-lg bg-tcd13-crit px-4 text-sm font-semibold whitespace-nowrap text-white transition hover:brightness-110 focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-tcd13-ink sm:col-span-1 sm:col-start-3 sm:row-start-1">Add payment method</button>
<div aria-hidden="true" class="absolute inset-x-0 bottom-0 h-[3px] bg-tcd13-crit/15"><i class="block h-full w-(--left) rounded-r-full bg-tcd13-crit animate-pulse motion-reduce:animate-none"></i></div>
</div>
</div>
<label for="tcd-13-d2" class="hidden min-h-11 cursor-pointer items-center gap-2 px-2 text-[13px] font-semibold text-tcd13-crit-ink underline-offset-4 hover:underline group-has-checked/w:flex">↺ Show the 41-hour trial banner again</label>
</div>
<div aria-hidden="true" class="mt-4 grid gap-2.5 px-2 pt-2 pb-3"><span class="h-4 w-[42%] rounded-md bg-tcd13-rule"></span><span class="h-2.5 rounded-md bg-tcd13-rule/70"></span><span class="h-2.5 rounded-md bg-tcd13-rule/70"></span><span class="h-2.5 w-[63%] rounded-md bg-tcd13-rule/70"></span></div>
</div>
<p class="text-[12.5px] leading-relaxed text-tcd13-mut text-pretty">An authenticated in-app surface scoped to one workspace, not a site-wide promo bar. Dismissal is a checkbox plus <code class="rounded bg-tcd13-rule px-1 py-0.5 text-[11.5px] text-tcd13-ink">has-checked:</code>, so it lasts for the session, animates closed and costs no script.</p>
</div>
</section>
```
## CSS
```css
@import "tailwindcss";
@theme {
--color-tcd13-page: #f7f5fd;
--color-tcd13-page: oklch(0.97 0.014 300);
--color-tcd13-app: #ffffff;
--color-tcd13-app: oklch(1 0 0);
--color-tcd13-ink: #191430;
--color-tcd13-ink: oklch(0.23 0.06 300);
--color-tcd13-mut: #5c537f;
--color-tcd13-mut: oklch(0.46 0.06 300);
--color-tcd13-rule: #e6e1f5;
--color-tcd13-rule: oklch(0.92 0.02 300);
--color-tcd13-acc: #6d3ce0;
--color-tcd13-acc: oklch(0.52 0.22 295);
--color-tcd13-crit: #d61f7a;
--color-tcd13-crit: oklch(0.56 0.24 350);
--color-tcd13-crit-ink: #a3135b;
--color-tcd13-crit-ink: oklch(0.46 0.2 350);
--font-tcd13-sans: 'Space Grotesk', system-ui, sans-serif;
--shadow-tcd13-app: 0 20px 46px -30px rgb(109 60 224 / 0.5);
}
.tcd-13 {
width: 100%;
min-height: 100svh;
}
```How this works
Dismiss without script. Each banner sits in a wrapper with a visually hidden checkbox. The close control is its <label>; checking it matches :has(:checked) on the wrapper.
A collapse that animates. Grid rows can transition between fractions, so the wrapper holds one row and animates it to zero:
<div class="group/w grid grid-rows-[1fr]
transition-[grid-template-rows] duration-300
has-checked:grid-rows-[0fr]">
<div class="min-h-0 overflow-hidden">…banner…</div>Undo is a second label. A Show trial banner link — another label for the same checkbox — appears via group-has-checked/w:flex, so dismissal is reversible for the session.
Escalation is one attribute. data-state="critical" switches the tint, icon colour, button colour and bar colour together.
Make it yours
- Set the remaining fraction per banner with the inline
--leftvalue. - Persist dismissal across sessions by replacing the checkbox with a cookie-driven
hiddenattribute. - Add a third state (e.g.
data-state="expired") with read-only copy and no dismiss. - Retint calm and critical via
--color-tcd13-accand--color-tcd13-crit.
Gotchas — read before shipping
- This is an authenticated in-app surface; site-wide promo bars belong in a different pattern.
- A checkbox dismissal resets on reload; never use it for legal notices.
grid-rows-[0fr]needs the child to havemin-h-0andoverflow-hidden, or it will not collapse.- Do not let the critical state be undismissable — nagging erodes trust faster than a missed upgrade.
Browser support
| Chrome | Safari | Firefox | Edge |
|---|---|---|---|
| 111+ | 16.4+ | 128+ | 111+ |
:has() and grid-row transitions are supported on Tailwind v4's floor (Chrome 107+/Safari 16+/Firefox 121+ for :has(); grid track interpolation in all three).