Blog

Blog · Templates

Free Coming Soon Page Template (HTML, CSS & JS, 2026)

A polished coming-soon / launching-soon page template with a live countdown timer and an email signup — responsive, accessible and ready to collect subscribers before you launch.

XCODX Team · 5 min read

This free coming soon page template is a polished pre-launch page in HTML, CSS and a little JavaScript: a headline, a live countdown timer to your launch date and an email signup to collect subscribers. It’s responsive, accessible, and dependency-free — put it up while you build, and start growing a launch list.

What you get

  • A centered, responsive hero with headline and subtext.
  • A live countdown timer (days / hours / minutes / seconds) to a launch date.
  • An accessible email signup with a success message via aria-live.
  • CSS-variable theming and zero dependencies.

The HTML

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <title>Coming soon</title>
  <link rel="stylesheet" href="styles.css">
</head>
<body>
  <main class="wrap">
    <p class="brand">Acme</p>
    <h1>Something great is coming.</h1>
    <p class="lede">We're putting the finishing touches on it. Leave your email and
      be the first to know when we launch.</p>

    <div class="countdown" id="countdown" aria-label="Time until launch">
      <div class="unit"><span class="num" data-days>00</span><span class="lbl">Days</span></div>
      <div class="unit"><span class="num" data-hours>00</span><span class="lbl">Hours</span></div>
      <div class="unit"><span class="num" data-mins>00</span><span class="lbl">Minutes</span></div>
      <div class="unit"><span class="num" data-secs>00</span><span class="lbl">Seconds</span></div>
    </div>

    <form class="signup" id="signup" novalidate>
      <label class="visually-hidden" for="email">Email address</label>
      <input id="email" type="email" placeholder="[email protected]" autocomplete="email" required>
      <button type="submit">Notify me</button>
    </form>
    <p class="msg" id="msg" role="status" aria-live="polite"></p>
  </main>

  <script src="countdown.js"></script>
</body>
</html>

The CSS

:root {
  --bg: #0b0d14; --text: #e8ecf4; --muted: #9aa4b8; --accent: #6ea8ff;
  --surface: #141824; --border: #232838; --radius: 12px;
  color-scheme: dark;
}
* { box-sizing: border-box; margin: 0; }
body { font-family: system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
  background: radial-gradient(1200px 600px at 50% -10%, #171c2e, var(--bg));
  color: var(--text); }
.wrap { min-height: 100vh; display: flex; flex-direction: column; justify-content: center;
  align-items: center; text-align: center; padding: 24px; gap: 18px; }
.brand { font-weight: 800; letter-spacing: .02em; color: var(--accent); }
h1 { font-size: clamp(30px, 7vw, 56px); letter-spacing: -.02em; max-width: 16ch; }
.lede { color: var(--muted); max-width: 46ch; }

.countdown { display: flex; gap: clamp(10px, 3vw, 22px); margin: 10px 0; }
.unit { background: var(--surface); border: 1px solid var(--border); border-radius: var(--radius);
  padding: 14px clamp(12px, 3vw, 22px); min-width: 74px; }
.num { display: block; font-size: clamp(24px, 5vw, 34px); font-weight: 800; font-variant-numeric: tabular-nums; }
.lbl { font-size: 12px; color: var(--muted); text-transform: uppercase; letter-spacing: .06em; }

.signup { display: flex; gap: 10px; flex-wrap: wrap; justify-content: center; width: 100%; max-width: 420px; }
.signup input { flex: 1 1 200px; padding: 13px 15px; border-radius: var(--radius);
  border: 1px solid var(--border); background: #0e1119; color: var(--text); font-size: 15px; }
.signup input:focus-visible { outline: 2px solid var(--accent); outline-offset: 1px; }
.signup button { padding: 13px 22px; border: 0; border-radius: var(--radius);
  background: var(--accent); color: #06080f; font-weight: 700; cursor: pointer; }
.msg { color: var(--accent); min-height: 20px; font-size: 14px; }
.visually-hidden { position: absolute; width: 1px; height: 1px; overflow: hidden; clip: rect(0 0 0 0); }

The JavaScript

Save as countdown.js. Set your launch date, and the timer updates every second; the form shows a success message (swap the TODO for a real API call).

// set your launch date (year, monthIndex 0-11, day, hour, minute)
const launch = new Date(2026, 11, 1, 9, 0).getTime();

const els = {
  days: document.querySelector('[data-days]'),
  hours: document.querySelector('[data-hours]'),
  mins: document.querySelector('[data-mins]'),
  secs: document.querySelector('[data-secs]'),
};
const pad = (n) => String(n).padStart(2, '0');

function tick() {
  const diff = launch - Date.now();
  if (diff <= 0) { document.getElementById('countdown').textContent = "We're live!"; return; }
  const s = Math.floor(diff / 1000);
  els.days.textContent = pad(Math.floor(s / 86400));
  els.hours.textContent = pad(Math.floor((s % 86400) / 3600));
  els.mins.textContent = pad(Math.floor((s % 3600) / 60));
  els.secs.textContent = pad(s % 60);
}
tick();
setInterval(tick, 1000);

const form = document.getElementById('signup');
const msg = document.getElementById('msg');
form.addEventListener('submit', (e) => {
  e.preventDefault();
  const email = form.elements[0];
  if (!email.validity.valid) { msg.textContent = 'Please enter a valid email.'; return; }
  // TODO: POST email.value to your email service or API
  msg.textContent = "Thanks! We'll be in touch at launch.";
  form.reset();
});

How to customize

  • Launch date: change the launch date in countdown.js. Once it passes, the timer shows "We’re live!".
  • Collect real emails: replace the TODO with a POST to a hosted service (Mailchimp, Buttondown, ConvertKit) or your own API.
  • Brand it: change --accent, the background gradient, and the fonts; add a logo image above the headline.
  • Social links: add a small row of links to your social accounts under the form.
  • Keep it fast: it’s tiny already — see modern web performance checklist before you add heavy assets.

Frequently asked questions

How does the countdown timer work?
The JavaScript stores your launch date as a timestamp, then every second it computes the difference from the current time and splits it into days, hours, minutes and seconds, updating the display. When the difference reaches zero it shows a launch message. It uses padStart for two-digit numbers and tabular-nums so the digits don’t jitter as they change.
How do I collect the email signups?
Replace the TODO in the submit handler with a request to an email-collection service or your own backend. Hosted services like Mailchimp, ConvertKit or Buttondown give you a form endpoint or API you can POST the email to; if you build it yourself, send a fetch POST to your API over HTTPS and store the address.
Is the coming soon page responsive?
Yes. It’s a flex-centered layout with fluid typography (clamp()), the countdown units wrap and scale with viewport-based spacing, and the signup form’s input flexes while the button stays sized. It looks right from small phones to large screens without any extra work.
Do I need JavaScript for the countdown?
Yes — a live countdown that updates every second requires JavaScript, since it must recompute the remaining time on an interval. The rest of the page (headline, email form markup) works without JS, so if scripts fail the page still shows your message and a signup field; only the ticking timer needs the script.

Build this coming-soon page live in XCODX Studio. See also the landing page template, contact form template and how to speed up JavaScript.