Component Library

← Back to gallery

Newsletter sign-up

Category: Marketing · Tags: newsletter, email, subscribe, consent, form

How to use it

Use for a single opt-in to a recurring email, in a page footer or after an article. Do not use it to collect other details (use a full form) or tick consent on people's behalf. The submit handler only prevents submission and shows the demo success state: the developer must wire the real subscription endpoint (ideally with double opt-in), point the privacy link at the real notice, and rename the dcl-newsletter ids if it appears twice.

Accessibility

A native <form> labelled by its heading, with a visible <label for> on the email field (autocomplete="email") and the consent sentence attached through aria-describedby, so it is read before anyone subscribes. Native validation stops an empty or malformed address, and the success message is written to a role="status" region without moving focus. Text #0f172a on #eff6ff is 16.40:1, the consent text #334155 on #eff6ff 9.51:1, its link #1d4ed8 on #eff6ff 6.16:1, the button's white on #1d4ed8 (#1e40af hovered) 6.70:1 (8.72:1), and the success text #166534 on #dcfce7 6.49:1.

Source (copy-ready)

<form class="dcl-newsletter" aria-labelledby="dcl-newsletter-title">
  <h2 id="dcl-newsletter-title" class="dcl-newsletter__title">Get the monthly product notes</h2>
  <p class="dcl-newsletter__intro">One short email a month about new features and planning tips.</p>
  <label for="dcl-newsletter-email" class="dcl-newsletter__label">Email address</label>
  <div class="dcl-newsletter__row">
    <input type="email" id="dcl-newsletter-email" name="email" class="dcl-newsletter__input" autocomplete="email" required aria-describedby="dcl-newsletter-consent">
    <button type="submit" class="dcl-newsletter__submit">Subscribe</button>
  </div>
  <p id="dcl-newsletter-consent" class="dcl-newsletter__consent">By subscribing you agree to receive these emails. Unsubscribe at any time from the link in each one. See our <a href="../about.html" class="dcl-newsletter__link">privacy notice</a>.</p>
  <p class="dcl-newsletter__status" role="status"></p>
</form>
<style>
.dcl-newsletter { display: flex; flex-direction: column; gap: 0.6rem; max-width: 30rem; padding: 1.5rem; border-radius: 0.75rem; font: inherit; color: #0f172a; background-color: #eff6ff; box-sizing: border-box; }
.dcl-newsletter__title { margin: 0; font-size: 1.25rem; color: #0f172a; background-color: #eff6ff; }
.dcl-newsletter__intro { margin: 0; color: #334155; background-color: #eff6ff; }
.dcl-newsletter__label { font-weight: 600; color: #0f172a; background-color: #eff6ff; }
.dcl-newsletter__row { display: flex; flex-wrap: wrap; gap: 0.5rem; }
.dcl-newsletter__input { flex: 1 1 12rem; min-width: 0; padding: 0.55rem 0.65rem; border: 1px solid #64748b; border-radius: 6px; font: inherit; color: #0f172a; background-color: #ffffff; }
.dcl-newsletter__input:focus-visible { outline: 2px solid #1d4ed8; outline-offset: 2px; }
.dcl-newsletter__submit { flex: none; padding: 0.55rem 1.1rem; border: none; border-radius: 6px; font: inherit; font-weight: 600; cursor: pointer; color: #ffffff; background-color: #1d4ed8; }
.dcl-newsletter__submit:hover { color: #ffffff; background-color: #1e40af; }
.dcl-newsletter__submit:focus-visible { outline: 2px solid #1d4ed8; outline-offset: 2px; }
.dcl-newsletter__consent { margin: 0; font-size: 0.85rem; line-height: 1.5; color: #334155; background-color: #eff6ff; }
.dcl-newsletter__link { color: #1d4ed8; background-color: #eff6ff; }
.dcl-newsletter__link:hover { color: #1e40af; background-color: #eff6ff; }
.dcl-newsletter__link:focus-visible { outline: 2px solid #1d4ed8; outline-offset: 2px; }
.dcl-newsletter__status { margin: 0; color: #166534; background-color: #eff6ff; }
.dcl-newsletter__status.dcl-newsletter__status--done { padding: 0.6rem 0.75rem; border-radius: 6px; font-weight: 600; color: #166534; background-color: #dcfce7; }
</style>
<script>
(function () {
  document.querySelectorAll(".dcl-newsletter").forEach(function (form) {
    if (form.dataset.dclBound) {
      return;
    }
    form.dataset.dclBound = "true";
    form.addEventListener("submit", function (event) {
      event.preventDefault();
      var status = form.querySelector(".dcl-newsletter__status");
      if (status) {
        status.classList.add("dcl-newsletter__status--done");
        status.textContent = "Thanks! Check your inbox to confirm your subscription. (Demo only: nothing was sent.)";
      }
    });
  });
})();
</script>

Was this useful? Send feedback.