Maintenance Page with Countdown — HTML CSS JS Snippet

Maintenance Page · Heroes · Plain HTML, CSS & JS · Live preview

Share & Support

What's included

Features

Live countdown timer targeting a configurable end time
Pulsing amber dot in a status pill communicating active maintenance
Rocking gear logo animation reinforcing the maintenance context
Subtle dot-grid background using CSS linear-gradient with radial mask
Email notification form with validation and disabled-after-submit state
Social/status page link row for self-service updates
Countdown fades when the expected window has elapsed
Full-screen dark layout suitable as a direct HTTP 503 response page

About this UI Snippet

Maintenance Page — Countdown Timer, Status Pill, Email Notify & Grid Background

Screenshot of the Maintenance Page snippet rendered live

A maintenance page (also called a "down for maintenance" or "we'll be right back" page) is a standard need for any production web application. Showing a polished, branded holding page instead of a server error keeps users informed and reduces support ticket volume during planned outages. This snippet provides a complete maintenance page with a dark-themed design, a subtle grid background, an animated status pill, a countdown timer, an email notification sign-up, and social/status links — for a pre-launch variant, see the coming soon hero.

The countdown timer

The timer targets a configurable end time (set 28 minutes from load in the snippet). tick() runs every second, computing the remaining hours, minutes, and seconds by dividing the millisecond diff and taking modulo values. It pads each unit to two digits with padStart(2, '0') for a consistent display width. The timer stops when the diff reaches zero and fades the countdown to indicate the expected window has passed. In production, the target time would come from a server-rendered config variable so the countdown reflects the actual maintenance window.

The status pill and pulse dot

The amber pulse dot uses a CSS keyframe animation cycling between opacity and scale — a lightweight way to convey "in progress" status. The pill's border and background both use rgba values of the brand colour so it reads against any dark background without hardcoding neutrals.

The grid background

The page background uses two overlapping CSS linear-gradient "lines" at 40px spacing to create a dot-grid pattern, masked with a radial gradient so it fades to black at the edges. This technique creates a sophisticated tech aesthetic with no images or SVG. The mask-image radial gradient is the key detail — without it the grid would be uniform and flat.

Email notification capture

The notify form validates the email client-side and shows a confirmation message on submission. In production this would POST to an endpoint that stores the email and sends a "we're back" email when the maintenance window ends. The form is disabled after submission to prevent duplicate entries.

The rocking gear animation

The logo icon uses a CSS keyframe that rotates between −6° and +6°, creating a mechanical rocking motion that reinforces the maintenance concept without requiring an external animation library or lottie file. The animation is subtle enough not to be distracting during what is a tense moment for the user.

Build with AI

Build, Understand, Optimize, and Extend It With AI

You do not have to guess why the countdown uses setTimeout instead of setInterval. Paste this snippet's HTML, CSS, and JS into an AI coding assistant like Claude and ask it to explain exactly why tick() re-schedules itself with setTimeout(tick, 1000) rather than using a single setInterval, and how that choice affects drift if the browser tab is backgrounded for a while. The same assistant can help optimize it, for instance asking whether the target end time should be read from a server-injected value instead of Date.now() plus a fixed offset, since every visitor currently gets their own independent 28-minute window rather than a shared one. It is also useful for extending the page: ask it to auto-reload the page once the countdown reaches zero so returning users land back on the live site automatically, wire the notify form to a real email-capture endpoint, or add a live status feed pulling from an incident-management API. Treat the code less like a finished artifact and more like a starting point for a conversation.

Prompt to recreate it

Copy this into your AI assistant of choice to build the effect from scratch, or as a jumping-off point for your own variant:

text
Build a "maintenance page" in plain HTML, CSS, and JavaScript with no libraries, intended to be servable as a static 503 response with no backend dependency.

Requirements:
- A full-screen dark page with a status pill containing a continuously pulsing dot (a CSS keyframe animating opacity and scale) and the text "Scheduled Maintenance", plus a heading and supporting copy.
- A live countdown made of three two-digit segments (hours, minutes, seconds) counting down toward a fixed target Date computed once at load, updating once per second by having the tick function re-schedule itself rather than relying on a repeating interval, so it is trivial to stop cleanly.
- Each countdown segment must be zero-padded to two digits regardless of its numeric value, and the whole countdown group must visually fade (reduced opacity) once the countdown reaches zero, rather than disappearing or showing negative numbers.
- An email input and "Notify me" button where clicking validates the email with a basic regex, shows a red inline error message for an invalid or empty address without submitting anything, and on a valid address shows a green confirmation message and disables both the input and the button so the same address cannot be submitted twice.
- A decorative background built from two overlapping CSS linear-gradient lines forming a grid pattern, masked with a radial gradient so the grid fades out toward the page edges instead of tiling uniformly to the viewport border.
- A small logo/icon element that continuously rocks back and forth a few degrees using a CSS keyframe, distinct from the pulsing status dot's animation.

Want to tighten it up first? Run this prompt through the AI Prompt Studio to score it across 8 quality dimensions, catch anti-patterns, and tune the wording for Claude, ChatGPT, or Gemini before you paste it in.

Step by step

How to Use

  1. 1
    Set the maintenance end timeChange the target variable from Date.now() + 28 * 60 * 1000 to a specific end time (e.g. new Date("2026-06-16T14:00:00Z")) to reflect your actual maintenance window.
  2. 2
    Update the heading and messageChange the heading and sub-text to match your brand voice and include any relevant details (what system is being updated, why).
  3. 3
    Replace the logoSwap the ⚙️ emoji with your logo SVG or an <img> tag. The logo container already handles sizing and shadow.
  4. 4
    Wire the email formIn notifyMe(), POST the validated email to your API endpoint. Store it and send a notification email when the maintenance concludes.
  5. 5
    Update the social linksReplace the Twitter, Status Page, and Support hrefs with your actual links. The status page link is particularly important during outages.
  6. 6
    Export for your frameworkClick "React" for a component with the countdown in useEffect and useRef. Click "Vue" for a Vue 3 SFC with onMounted and onUnmounted interval cleanup.

Real-world uses

Common Use Cases

Planned maintenance and deployment windows
Serve the maintenance page via your load balancer or CDN during planned database migrations, major releases, or infrastructure upgrades. A countdown timer and a "notify me" capture turn a frustrating downtime into a managed experience that keeps users informed and gives your team a clean window to work.
Database migration or schema change window
When running a zero-downtime migration is not possible (large schema changes, data backfills), take the app offline with this page. Set the countdown to the migration's estimated completion, link to your status page for real-time updates, and capture emails to notify users when the migration completes.
Product launch "coming soon" variant
Repurpose the page as a pre-launch holding page: change the heading to "Launching Soon", swap "Scheduled Maintenance" for "Coming Soon", and use the email form to build a waitlist. The countdown becomes the launch timer, and the grid background gives the page a tech startup aesthetic.
Integrate with your status page and incident system
Read the maintenance end time from your incident management API (PagerDuty, Statuspage.io) and inject it into the page at serve time. Update the countdown target server-side so users always see an accurate remaining estimate even if they refresh the page.
Study the CSS grid-line and mask technique
The background grid is a notable pure-CSS technique: two perpendicular linear-gradient "lines" at the same spacing create a grid pattern, and a radial mask-image fades it to transparent at the edges. This technique transfers to hero sections, card backgrounds, and code editor UIs anywhere a tech-flavoured grid is needed.
503 error page in your web server or CDN config
Configure your web server (nginx, Caddy) or CDN (Cloudflare Pages, AWS CloudFront) to serve the maintenance page as a custom 503 response. This ensures the page appears even when your application server is completely unreachable, rather than the browser's generic error screen.

Got questions?

Frequently Asked Questions

Replace var target = new Date(Date.now() + 28 * 60 * 1000) with var target = new Date("2026-06-16T15:00:00Z"), using your actual maintenance window end time in ISO 8601 UTC format. All visitors then see the same remaining time regardless of when they load the page, which is the correct behaviour for a shared maintenance window. If your maintenance window is server-configured, inject the end time as a JavaScript variable from your server-side template.

When diff reaches zero, tick() stops calling itself and fades the countdown numbers to 0.4 opacity to signal that the expected window has elapsed. In production you should also add a page-reload after a short delay (e.g., setTimeout(() => location.reload(), 15000)) so users whose page was open during maintenance automatically return to the live site once it comes back up.

In nginx, add error_page 503 /maintenance.html; and return 503; in a location block. In Caddy, use the respond directive with a 503 status and the page HTML as the body, or rewrite to a static HTML file. With Cloudflare, use a Worker that returns the maintenance page with a 503 status when a kill-switch KV key is set. The page should itself be a static file with no backend dependencies so it serves even when your application is completely down.

In a useEffect, set up a setInterval(tick, 1000) that computes remaining time from a target Date and updates a timeLeft state object { h, m, s }. Clear the interval in the useEffect cleanup. The notify form keeps email and submitted in useState; on submit, validate and call your API. Because maintenance pages should work without JavaScript in some configurations, consider a server-rendered version (Next.js getServerSideProps returning the target time as a prop) so the countdown is pre-rendered on the correct value. For the Tailwind version, click "Tailwind" to get the same markup with utility classes instead of a scoped stylesheet.