Source Code

<footer class="nl-footer">
  <div class="nl-top">
    <div class="nl-copy">
      <span class="nl-brand">Fictional Co.</span>
      <p>Product updates and engineering notes, twice a month. No spam.</p>
    </div>

    <form class="nl-form" id="nlForm" novalidate>
      <div class="nl-input-row">
        <input type="email" id="nlEmail" placeholder="you@company.com" aria-label="Email address" />
        <button type="submit" id="nlSubmit">Subscribe</button>
      </div>
      <p class="nl-msg" id="nlMsg" role="status" aria-live="polite"></p>
    </form>
  </div>

  <div class="nl-cols">
    <div class="nl-col">
      <span class="nl-col-title">Product</span>
      <a href="#">Features</a>
      <a href="#">Pricing</a>
      <a href="#">Changelog</a>
    </div>
    <div class="nl-col">
      <span class="nl-col-title">Company</span>
      <a href="#">About</a>
      <a href="#">Careers</a>
      <a href="#">Blog</a>
    </div>
    <div class="nl-col">
      <span class="nl-col-title">Legal</span>
      <a href="#">Privacy</a>
      <a href="#">Terms</a>
    </div>
  </div>

  <div class="nl-bottom">© 2026 Fictional Co. All rights reserved.</div>
</footer>

Newsletter Subscribe Footer — Real Email Validation and Duplicate Prevention

Newsletter Subscribe Footer with Validation · Footers · Plain HTML, CSS & JS · Live preview

What's included

Features

Real email format validation runs before any submission is attempted, not just on the backend
Case-insensitive duplicate-subscription detection using a Set for efficient, correct lookup
Genuine async loading state (disabled button, "Subscribing…" text) around the simulated request
Error styling and message clear automatically as the user starts correcting an invalid email
Focus is returned to the invalid field automatically so the error is immediately actionable
role="status" aria-live="polite" on the message area announces both errors and success to screen readers
Standard multi-column footer layout (Product/Company/Legal) alongside the newsletter form, a common real-world pairing
Fully self-contained fake-subscribe layer, straightforward to swap for a real newsletter API integration

About this UI Snippet

Newsletter Subscribe Footer — Validation That Actually Runs

Screenshot of the Newsletter Subscribe Footer with Validation snippet rendered live

A footer newsletter form is one of the most common components on the web, and also one of the most frequently implemented as pure decoration — an input and a button with no actual validation behind them. This version implements the real behavior a signup form needs: format validation before submission, duplicate-subscription detection, and a genuine loading state around the (simulated) network request.

Validation runs before any request is attempted

The submit handler tests the trimmed email value against EMAIL_RE — a standard local-part@domain.tld pattern — *before* doing anything else. An invalid email never reaches the simulated subscribe call at all; it immediately gets an .invalid border style and an explicit error message, with focus returned to the input so the user can correct it right away without hunting for what went wrong.

Duplicate prevention uses a real Set, checked case-insensitively

Every successfully subscribed email is added to a Set (subscribed), keyed by its lowercased form — subscribed.add(email.toLowerCase()). Before accepting a new submission, the handler checks subscribed.has(email.toLowerCase()) first, so Person@Example.com and person@example.com are correctly treated as the same address rather than allowing a technically-different-cased duplicate through. A Set gives O(1) lookup regardless of how many emails have been collected in the session, rather than scanning an array on every submission.

The submit button reflects a real in-flight request, not an instant fake success

fakeSubscribe() returns a Promise that resolves after a randomized delay (600–1000ms), and the button is disabled with its text changed to "Subscribing…" for that entire duration — modeling a genuine network round-trip rather than resolving instantly, which is what most decorative newsletter forms actually do (or don't even bother simulating at all).

Clearing the error state as the user starts fixing it

A separate input listener removes the .invalid class and clears the error message the moment the user starts typing again, rather than leaving the red error styling in place until the next submit attempt — a small but meaningful detail that keeps the form feeling responsive to correction rather than punitive.

Why this matters even for "just a footer form"

A newsletter signup is often a visitor's very last interaction with a page before leaving — a form that silently accepts garbage input, or gives no feedback about whether a submission actually worked, either fails silently (bad data reaching whatever backend is behind it) or leaves the visitor uncertain whether anything happened at all. Real validation and real submission feedback cost little extra code and meaningfully improve both outcomes.

Build with AI

Build, Understand, Optimize, and Extend It With AI

Ask an AI assistant to explain why case-insensitive duplicate detection matters for email addresses specifically, and to discuss what additional server-side validation (beyond this client-side format check) a real newsletter signup would still need, such as double opt-in confirmation. It's also worth asking for a version that also checks for common typo domains (like "gmial.com") and suggests a correction, or one that integrates with a specific newsletter provider's API (Mailchimp, ConvertKit, etc.) using their real endpoint contract.

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 site footer with an embedded newsletter signup form in HTML, CSS and vanilla JavaScript, with real client-side validation and duplicate prevention — no external libraries.

Requirements:
- A footer with a newsletter signup section (email input plus subscribe button) alongside a standard multi-column link footer (e.g. Product, Company, Legal columns) and a copyright line.
- On submit, validate the entered email against a proper email-format regular expression before doing anything else; if invalid, prevent submission, show a clear inline error message, apply an error style to the input, and move keyboard focus to it — do not attempt any request for an invalid email.
- Track successfully subscribed emails in a case-insensitive way (e.g. using a Set of lowercased addresses) and detect and reject a duplicate resubmission of an already-subscribed email with a distinct message, without re-submitting.
- Simulate an async subscribe request using a Promise that resolves after a randomized realistic delay; while it's pending, disable the submit button and change its text to reflect the in-flight state, then restore it and show a success message (including the subscribed email) once it resolves, clearing the input.
- Automatically clear any error styling and error message as soon as the user starts typing again after a failed validation attempt.
- Use an accessible live region for the status message so both errors and success confirmations are announced to screen reader users.

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
    Try submitting an invalid emailThe input gets a red border and an inline error message, with focus returned to it — no request is attempted.
  2. 2
    Submit a valid emailThe button shows "Subscribing…" for a moment (simulating a real request), then confirms success and clears the field.
  3. 3
    Submit the same email againThe form detects the duplicate (case-insensitively) and shows a distinct "already subscribed" message without re-submitting.
  4. 4
    Replace fakeSubscribe with a real API callSwap the setTimeout simulation for an actual fetch() call to your newsletter provider's API, keeping the same async/await structure.
  5. 5
    Adjust the footer columns and copyEdit the .nl-cols links and .nl-copy text in the HTML panel to match your own site's footer content.

Real-world uses

Common Use Cases

MARKETING
Marketing Site Footers
The standard placement for a newsletter signup — bundled with the site's main footer navigation.
BLOG
Blog / Content Site Footers
Collect subscriber emails for a content newsletter with real validation instead of a decorative form.
SAAS
SaaS Product Update Signups
Let visitors opt into product update emails directly from the footer of any marketing page.
ECOM
E-commerce Footer Signups
Collect emails for promotions or restock notifications with genuine format checking before submission.
Related: Footer Live System-Status Indicator
See the Footer Live System-Status Indicator for a related footers pattern worth pairing with this one.

Got questions?

Frequently Asked Questions

Yes — the submitted value is tested against an email-format regular expression before the simulated subscribe request is even called; an invalid email is rejected immediately client-side with no request attempted at all.

Every successfully subscribed email is stored in a Set, keyed by its lowercased form. Before accepting a new submission, the handler checks whether that lowercased email already exists in the Set, so different capitalizations of the same address are correctly treated as duplicates.

The simulated subscribe function resolves after a randomized 600–1000ms delay, modeling a genuine network request round-trip, and the button is disabled with updated text for that entire duration — giving accurate feedback rather than an instant fake confirmation.

An input event listener removes the error styling and clears the error message as soon as the user begins editing the field again, rather than leaving the red error state in place until the next submit attempt.

No — it's an in-memory Set that only persists for the current page session, purely to demonstrate duplicate detection in this demo. A real implementation would check for duplicates against your actual email service provider's subscriber list server-side.

Yes — the message element has role="status" aria-live="polite", so both validation errors and success confirmations are announced automatically without requiring the user to navigate to find them.