Coming Soon Hero — Free HTML CSS JS Countdown Snippet
Coming Soon Hero · Heroes · Plain HTML, CSS & JS · Live preview
Copy & paste
Source Code
<section class="hero">
<div class="glow"></div>
<div class="badge">🚀 Launching soon</div>
<h1 class="headline">Something <span class="grad">amazing</span><br>is coming</h1>
<p class="sub">We are putting the finishing touches on something you will love. Be the first to know when we launch.</p>
<div class="countdown" id="countdown">
<div class="cd-block"><span class="cd-n" id="cd-d">00</span><span class="cd-l">Days</span></div>
<div class="cd-sep">:</div>
<div class="cd-block"><span class="cd-n" id="cd-h">00</span><span class="cd-l">Hours</span></div>
<div class="cd-sep">:</div>
<div class="cd-block"><span class="cd-n" id="cd-m">00</span><span class="cd-l">Minutes</span></div>
<div class="cd-sep">:</div>
<div class="cd-block"><span class="cd-n" id="cd-s">00</span><span class="cd-l">Seconds</span></div>
</div>
<form class="capture" onsubmit="handleSubmit(event)">
<input class="email" type="email" placeholder="Enter your email address" required>
<button type="submit" class="cta-btn">Notify me</button>
</form>
<p class="note">No spam, ever. Unsubscribe anytime.</p>
<div class="social-row">
<a href="#" class="soc-link">Twitter</a>
<span class="soc-dot">·</span>
<a href="#" class="soc-link">LinkedIn</a>
<span class="soc-dot">·</span>
<a href="#" class="soc-link">Instagram</a>
</div>
</section>* { box-sizing: border-box; margin: 0; padding: 0; }
body { font-family: system-ui, sans-serif; background: #050a14; min-height: 100vh; overflow: hidden; }
.hero { min-height: 100vh; display: flex; flex-direction: column; align-items: center; justify-content: center; text-align: center; padding: 60px 24px; gap: 24px; position: relative; overflow: hidden; }
.glow { position: absolute; width: 600px; height: 600px; background: radial-gradient(circle, rgba(99,102,241,0.2) 0%, transparent 70%); top: 50%; left: 50%; transform: translate(-50%,-50%); pointer-events: none; animation: pulse-glow 4s ease-in-out infinite; }
@keyframes pulse-glow { 0%,100%{opacity:0.6} 50%{opacity:1} }
.badge { position: relative; font-size: 12px; font-weight: 700; color: #a78bfa; background: rgba(99,102,241,0.1); border: 1px solid rgba(99,102,241,0.25); padding: 6px 16px; border-radius: 20px; letter-spacing: 0.3px; }
.headline { position: relative; font-size: clamp(36px,7vw,68px); font-weight: 900; color: #f1f5f9; line-height: 1.1; letter-spacing: -1.5px; max-width: 640px; }
.grad { background: linear-gradient(135deg,#6366f1,#a78bfa,#ec4899); -webkit-background-clip:text; -webkit-text-fill-color:transparent; background-clip:text; }
.sub { position: relative; font-size: 15px; color: #64748b; max-width: 420px; line-height: 1.75; }
.countdown { position: relative; display: flex; align-items: center; gap: 12px; flex-wrap: wrap; justify-content: center; }
.cd-block { display: flex; flex-direction: column; align-items: center; gap: 4px; background: rgba(255,255,255,0.04); border: 1px solid rgba(255,255,255,0.08); border-radius: 12px; padding: 14px 20px; min-width: 72px; }
.cd-n { font-size: 36px; font-weight: 800; color: #f1f5f9; font-variant-numeric: tabular-nums; line-height: 1; }
.cd-l { font-size: 10px; font-weight: 600; color: #475569; letter-spacing: 1px; text-transform: uppercase; }
.cd-sep { font-size: 32px; font-weight: 300; color: #334155; margin-bottom: 16px; }
.capture { position: relative; display: flex; gap: 8px; width: 100%; max-width: 440px; flex-wrap: wrap; }
.email { flex: 1; min-width: 200px; background: rgba(255,255,255,0.06); border: 1px solid rgba(255,255,255,0.1); border-radius: 10px; padding: 12px 16px; font-size: 14px; color: #f1f5f9; outline: none; transition: border-color 0.15s; }
.email:focus { border-color: #6366f1; }
.email::placeholder { color: #475569; }
.cta-btn { background: #6366f1; color: #fff; font-size: 14px; font-weight: 700; padding: 12px 22px; border: none; border-radius: 10px; cursor: pointer; white-space: nowrap; transition: background 0.15s; }
.cta-btn:hover { background: #4f46e5; }
.cta-btn.done { background: #16a34a; cursor: default; }
.note { position: relative; font-size: 12px; color: #334155; }
.social-row { position: relative; display: flex; align-items: center; gap: 8px; }
.soc-link { font-size: 12px; color: #475569; text-decoration: none; transition: color 0.12s; }
.soc-link:hover { color: #94a3b8; }
.soc-dot { color: #334155; font-size: 12px; }// Set your launch date here
const LAUNCH = new Date('2026-08-01T00:00:00');
function tick() {
const now = new Date();
let diff = Math.max(0, LAUNCH - now) / 1000;
const d = Math.floor(diff / 86400); diff -= d * 86400;
const h = Math.floor(diff / 3600); diff -= h * 3600;
const m = Math.floor(diff / 60); diff -= m * 60;
const s = Math.floor(diff);
const pad = n => String(n).padStart(2, '0');
document.getElementById('cd-d').textContent = pad(d);
document.getElementById('cd-h').textContent = pad(h);
document.getElementById('cd-m').textContent = pad(m);
document.getElementById('cd-s').textContent = pad(s);
}
tick();
setInterval(tick, 1000);
function handleSubmit(e) {
e.preventDefault();
const btn = e.target.querySelector('.cta-btn');
btn.textContent = "✓ You're on the list!";
btn.classList.add('done');
e.target.querySelector('.email').disabled = true;
}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.
What's included
Features
About this UI Snippet
Coming Soon Hero — Live Countdown Timer, Dark Gradient & Email Capture Form

A coming soon page gives your product a professional presence before launch while building an email waitlist of early adopters. This snippet provides a complete coming soon hero: a dark background with animated radial glow, a gradient headline, a live countdown timer (days, hours, minutes, seconds), an email capture form (see also waitlist signup) with success feedback, a spam disclaimer, and social platform links — all in plain HTML, CSS, and minimal JavaScript.
The countdown timer
The tick() function runs every second via setInterval. It computes the difference between LAUNCH (a configurable Date object) and new Date(), converts milliseconds to days/hours/minutes/seconds using integer division and modulo, and updates four CD-N elements. The pad() helper zero-pads single digits. Setting LAUNCH at the top of the JS is the only configuration needed to deploy the timer for your specific date.
The animated glow
A single div with radial-gradient background and absolute positioning creates the central glow effect. A CSS keyframe animation pulses the opacity between 0.6 and 1 on a 4-second loop, giving the impression of a breathing energy source behind the content. The glow uses pointer-events: none so it never intercepts clicks.
The gradient headline
The .grad span uses background: linear-gradient(135deg, indigo, violet, pink) with background-clip: text and -webkit-text-fill-color: transparent. The font uses clamp(36px, 7vw, 68px) for fluid sizing from mobile to wide desktop.
Countdown block design
Each time unit (Days, Hours, Minutes, Seconds) has its own card block with a dark glass background (rgba white at 4% opacity), a subtle border, border-radius: 12px, and the large number in tabular-nums font-variant for stable digit width. The colon separators between blocks use a lighter colour and sit slightly lower.
Email capture with success state
The form prevents default submission, changes the button text to "✓ You're on the list!", adds a green .done class, and disables the email input. Wire the form to your mailing list API (Mailchimp, ConvertKit, Resend) inside handleSubmit() before the UI update.
Customising for your launch
Change the LAUNCH constant to your real launch date. Update the headline text. Replace the email API endpoint. Add your real social media URLs. Change the gradient colours (#6366f1 → your brand) throughout the CSS. Update the headline .grad gradient to include your primary brand colour as the starting colour stop for fully branded gradient text.
Step by step
How to Use
- 1Set your launch dateIn the JS panel, change the LAUNCH constant: const LAUNCH = new Date("YYYY-MM-DDTHH:MM:SS"). The countdown updates automatically. The timer shows zeros once the launch date has passed.
- 2Update the headline and subtitleEdit the h1 text — change "amazing" to your product adjective and keep it in the .grad span for the gradient effect. Update the .sub paragraph with your specific product promise.
- 3Wire the email form to your APIIn handleSubmit(), add a fetch call before the UI update: await fetch("/api/waitlist", { method: "POST", body: JSON.stringify({email}) }). Show the success state on resolve and an error message on reject.
- 4Update the social media linksReplace href="#" on the three .soc-link anchors with your actual Twitter/X, LinkedIn, and Instagram URLs. Change the link labels to match your active platforms.
- 5Change the brand colourReplace #6366f1 throughout the CSS with your brand hex. Updates the glow, badge, input focus ring, and CTA button. Also update the gradient in .grad to include your brand colour.
- 6Export in your formatClick "HTML" for a standalone file, "JSX" for a React component using useEffect for the setInterval with cleanup, or "Tailwind" for a Tailwind CSS version.
Real-world uses
Common Use Cases
Got questions?
Frequently Asked Questions
At the top of the JS panel, set const LAUNCH = new Date("YYYY-MM-DDTHH:MM:SS"). The tick() function runs every 1000ms via setInterval. It computes LAUNCH - new Date() in milliseconds, converts to total seconds, then uses integer division (Math.floor(diff / 86400) for days, etc.) and modulo to extract each time unit. The pad() function zero-pads each unit to always show two digits. Setting LAUNCH is the only change needed.
In handleSubmit(), before the UI update code, add your API call. For a custom backend: const res = await fetch("/api/waitlist", { method: "POST", headers: {"Content-Type":"application/json"}, body: JSON.stringify({email: e.target.querySelector(".email").value}) }); if (!res.ok) { showError(); return; }. For Mailchimp, use their Embedded Forms or API v3 endpoint. Use a server-side proxy to hide API keys.
Math.max(0, LAUNCH - now) ensures diff never goes negative — all four blocks show 00 when the launch date has passed. To show a "We are live!" state when the timer expires, check if LAUNCH < new Date() inside tick() and update the countdown section innerHTML with a launch announcement instead of continuing to show the timer.
Click "JSX" to download a React component. Manage the countdown values in useState({d:"00",h:"00",m:"00",s:"00"}). Run the tick interval in a useEffect: const id = setInterval(tick, 1000); return () => clearInterval(id) — the return cleanup prevents the interval from running after the component unmounts. For email capture, make the form a Client Component ("use client") and use useState for the submitted state.