Open demo

CSS code

HTML
<svg width="0" height="0" style="position:absolute" aria-hidden="true" focusable="false">
  <symbol id="do-i-tick" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.4" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="9"/><path d="M8 12.5l2.8 2.8L16.5 9.5"/></symbol>
  <symbol id="do-i-out" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M4 7l8 6 8-6M4 6h16v12H4z"/><path d="M15 15l5 5M20 15l-5 5"/></symbol>
  <symbol id="do-i-redo" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M20 11a8 8 0 1 0-2.3 5.7M20 4v7h-7"/></symbol>
</svg>

<div class="demo-grid">
<div><span class="lbl">Check your inbox</span>
<section class="do do-inbox" aria-labelledby="ci-title">
  <svg class="do-env" viewBox="0 0 120 84" aria-hidden="true"><rect x="6" y="14" width="108" height="66" rx="10" fill="#eaf0fe" stroke="#1d4ed8" stroke-width="3"/><path d="M9 20l51 36 51-36" fill="none" stroke="#1d4ed8" stroke-width="3" stroke-linejoin="round"/><circle cx="100" cy="16" r="14" fill="#1d4ed8"/><path d="M94 16.5l4 4 8-8" fill="none" stroke="#fff" stroke-width="3" stroke-linecap="round" stroke-linejoin="round"/></svg>
  <h2 class="do-title" id="ci-title">Confirm your subscription</h2>
  <p class="do-text">We sent a link to <b>[email protected]</b>. Field Notes starts once you click it. The link works for 48 hours.</p>
  <ol class="do-steps">
    <li><span>Open the email from Field Notes</span></li>
    <li><span>Click <b>Yes, subscribe me</b></span></li>
    <li><span>Tuesday's issue is yours</span></li>
  </ol>
  <div class="do-actions">
    <button class="do-btn" type="button" data-resend data-email="[email protected]" aria-describedby="ci-status"><svg aria-hidden="true"><use href="#do-i-redo"/></svg>Resend the email</button>
    <a href="#change-email">Use a different address</a>
  </div>
  <p class="do-status" id="ci-status" role="status"></p>
  <p class="do-small">Nothing after five minutes? Check spam and promotions, or add [email protected] to your contacts.</p>
</section>
</div>

<div><span class="lbl">Already subscribed</span>
<section class="do do-already" aria-labelledby="as-title">
  <span class="do-ico" aria-hidden="true"><svg><use href="#do-i-tick"/></svg></span>
  <h2 class="do-title" id="as-title">You're already on the list</h2>
  <p class="do-text">Good news: there's nothing to do. This address already gets Field Notes.</p>
  <dl>
    <dt>Email</dt><dd>[email protected]</dd>
    <dt>Since</dt><dd>14 March 2025</dd>
    <dt>Arrives</dt><dd>Every Tuesday</dd>
  </dl>
  <div class="do-actions">
    <a class="do-btn" href="#preferences">Manage preferences</a>
    <a class="do-btn do-btn--ghost" href="#latest">Read the latest issue</a>
  </div>
</section>
</div>
</div>

<div class="demo-grid">
<div><span class="lbl">Manage preferences</span>
<section class="do do-prefs" aria-labelledby="mp-title">
  <form class="do-form" action="#" method="post" data-prefs>
    <h2 class="do-title" id="mp-title">Email preferences</h2>
    <p class="do-who"><span>Signed in as <b>[email protected]</b></span><a href="#not-you">Not you?</a></p>
    <fieldset class="do-set">
      <legend>What we send you</legend>
      <label class="do-switch"><span><b>Field Notes</b><small>Weekly essays on design and research</small></span><input type="checkbox" role="switch" name="lists" value="field-notes" checked></label>
      <label class="do-switch"><span><b>Product updates</b><small>New features, about once a month</small></span><input type="checkbox" role="switch" name="lists" value="product"></label>
      <label class="do-switch"><span><b>Event invitations</b><small>Talks and workshops near you</small></span><input type="checkbox" role="switch" name="lists" value="events" checked></label>
    </fieldset>
    <fieldset class="do-set">
      <legend>How often should Field Notes arrive?</legend>
      <div class="do-radios">
        <label class="do-radio"><input type="radio" name="freq" value="weekly" checked>Weekly</label>
        <label class="do-radio"><input type="radio" name="freq" value="fortnightly">Every two weeks</label>
        <label class="do-radio"><input type="radio" name="freq" value="monthly">Monthly digest</label>
      </div>
    </fieldset>
    <div class="do-actions">
      <button class="do-btn" type="submit" aria-describedby="mp-status">Save preferences</button>
      <a href="#unsubscribe-all">Unsubscribe from everything</a>
    </div>
    <p class="do-status" id="mp-status" role="status"></p>
  </form>
</section>
</div>

<div><span class="lbl">Unsubscribe</span>
<section class="do do-unsub" aria-labelledby="us-title">
  <form class="do-form" action="#" method="post" data-unsub="us-done">
    <span class="do-ico" aria-hidden="true"><svg><use href="#do-i-out"/></svg></span>
    <h2 class="do-title" id="us-title">Unsubscribe from Field Notes?</h2>
    <p class="do-text">You'll stop getting the Tuesday email at <b>[email protected]</b>.</p>
    <fieldset class="do-set">
      <legend>What would you like to do?</legend>
      <label class="do-choice"><input type="radio" name="action" value="unsubscribe" checked><span><b>Unsubscribe</b><small>No more Field Notes emails</small></span></label>
      <label class="do-choice"><input type="radio" name="action" value="monthly"><span><b>Send me less</b><small>Switch to the monthly digest instead</small></span></label>
    </fieldset>
    <label class="do-label" for="us-reason">Why are you leaving? (optional)</label>
    <select class="do-select" id="us-reason" name="reason">
      <option value="">Prefer not to say</option>
      <option>Too many emails</option>
      <option>Not relevant to me any more</option>
      <option>I never signed up</option>
      <option>Other</option>
    </select>
    <div class="do-actions">
      <button class="do-btn do-btn--dark" type="submit">Confirm</button>
      <a href="#keep">Keep my subscription</a>
    </div>
  </form>
  <div class="do-done" id="us-done" tabindex="-1" hidden>
    <span class="do-ico" aria-hidden="true"><svg><use href="#do-i-tick"/></svg></span>
    <h2 class="do-title" data-done-title>You've been unsubscribed</h2>
    <p class="do-text" data-done-text>You won't get any more Field Notes emails. It can take up to a day for a scheduled issue to stop.</p>
    <div class="do-actions"><button class="do-btn do-btn--ghost" type="button" data-resub>Subscribed by mistake? Resubscribe</button></div>
  </div>
</section>
</div>
</div>
CSS
/* The screens around a double opt-in newsletter: check your inbox (with a resend button), already subscribed,
   manage preferences and unsubscribe. Every action is one click and says what will happen; leaving is as easy as
   joining, and the unsubscribe page offers "less often" without guilt-trip copy. */
.do{--do-ink:#172033;--do-muted:#4c586f;--do-line:#76819a;--do-soft:#dfe5ef;--do-accent:#1d4ed8;--do-accent-dark:#1e40af;--do-tint:#eaf0fe;--do-ring:rgba(29,78,216,.22);--do-ok:#15803d;
  background:#fff;color:var(--do-ink);border-radius:20px;padding:30px;font-size:.92rem;line-height:1.5;box-shadow:0 1px 2px rgba(23,32,51,.06),0 20px 44px -26px rgba(23,32,51,.4)}
.do a{color:var(--do-accent);font-weight:600;text-underline-offset:2px}
.do a:focus-visible{outline:2px solid var(--do-accent);outline-offset:2px;border-radius:3px}
.do-title{font-size:1.35rem;font-weight:750;letter-spacing:-.02em;line-height:1.25}
.do-text{color:var(--do-muted);margin-top:6px}
.do-text b{color:var(--do-ink);overflow-wrap:anywhere}
.do-btn{display:inline-flex;align-items:center;justify-content:center;gap:8px;font:inherit;font-weight:650;color:#fff;background:var(--do-accent);border:1.5px solid var(--do-accent);
  border-radius:10px;padding:9px 16px;cursor:pointer;text-decoration:none;transition:background-color .15s,border-color .15s,color .15s}
.do-btn:hover{background:var(--do-accent-dark);border-color:var(--do-accent-dark)}
.do-btn:focus-visible{outline:2px solid var(--do-accent);outline-offset:3px}
.do-btn svg{width:18px;height:18px}
.do a.do-btn{color:#fff}
.do-btn--ghost,.do a.do-btn--ghost{color:var(--do-ink);background:#fff;border-color:var(--do-line)}
.do-btn--ghost:hover{background:#f3f5f9;border-color:var(--do-ink)}
.do-btn--dark{background:var(--do-ink);border-color:var(--do-ink)}
.do-btn--dark:hover{background:#2a3550;border-color:#2a3550}
.do-btn[aria-disabled=true]{color:var(--do-muted);background:#f3f5f9;border-color:var(--do-soft);cursor:default}
.do-actions{display:flex;flex-wrap:wrap;align-items:center;gap:10px 14px;margin-top:20px}
.do-status{font-size:.84rem;color:var(--do-ok);font-weight:600;margin-top:12px}
.do-status:empty{display:none}
.do-ico{display:grid;place-items:center;width:52px;height:52px;border-radius:16px;margin-bottom:16px}
.do-ico svg{width:28px;height:28px}
.do-done{outline:none}
.do [hidden]{display:none}
.do-done:focus-visible{outline:2px solid var(--do-accent);outline-offset:6px;border-radius:12px}

/* 1. Check your inbox */
.do-inbox{text-align:center;padding:34px 30px 30px}
.do-env{display:block;width:120px;height:84px;margin:0 auto 18px}
.do-steps{list-style:none;display:grid;gap:8px;margin:20px auto 0;max-width:340px;text-align:left;counter-reset:s}
.do-steps li{display:flex;gap:12px;align-items:center;counter-increment:s}
.do-steps li::before{content:counter(s);flex:none;display:grid;place-items:center;width:26px;height:26px;border-radius:50%;background:var(--do-tint);color:var(--do-accent-dark);font-weight:800;font-size:.8rem}
.do-inbox .do-actions{justify-content:center}
.do-small{font-size:.8rem;color:var(--do-muted);margin-top:16px}

/* 2. Already subscribed */
.do-already .do-ico{background:#dcfce7;color:var(--do-ok)}
.do-already dl{display:grid;grid-template-columns:auto 1fr;gap:6px 16px;margin-top:18px;padding:14px 16px;border-radius:12px;background:#f5f7fb;font-size:.86rem}
.do-already dt{color:var(--do-muted)}
.do-already dd{font-weight:600;overflow-wrap:anywhere}

/* 3. Manage preferences */
.do-who{display:flex;flex-wrap:wrap;justify-content:space-between;gap:4px 12px;align-items:baseline;padding-bottom:16px;margin-bottom:6px;border-bottom:1px solid var(--do-soft)}
.do-who span{color:var(--do-muted);font-size:.86rem}
.do-who b{color:var(--do-ink);overflow-wrap:anywhere}
.do-set{border:0;min-width:0;margin-top:18px}
.do-set legend{font-weight:700;font-size:.95rem;padding:0;margin-bottom:6px}
.do-switch{display:flex;align-items:center;gap:14px;padding:12px 0;border-top:1px solid var(--do-soft);cursor:pointer}
.do-switch:first-of-type{border-top:0}
.do-switch span{flex:1;min-width:0}
.do-switch b{display:block;font-size:.92rem}
.do-switch small{font-size:.8rem;color:var(--do-muted)}
.do-switch input{appearance:none;flex:none;width:42px;height:24px;margin:0;border-radius:999px;cursor:pointer;
  background:var(--do-line) radial-gradient(circle,#fff 8px,transparent 8.5px) no-repeat left 1px center/24px 24px;transition:background-color .2s,background-position .2s}
.do-switch input:checked{background-color:var(--do-accent);background-position:right 1px center}
.do-switch input:focus-visible{outline:2px solid var(--do-accent);outline-offset:2px}
.do-radios{display:flex;flex-wrap:wrap;gap:8px}
.do-radio{display:inline-flex;align-items:center;gap:8px;padding:8px 13px;border:1.5px solid var(--do-soft);border-radius:10px;cursor:pointer;font-weight:600;font-size:.86rem;transition:border-color .15s,background-color .15s}
.do-radio:has(:checked){border-color:var(--do-accent);background:var(--do-tint)}
.do-radio input{appearance:none;width:16px;height:16px;margin:0;border:1.5px solid var(--do-line);border-radius:50%;background:#fff;cursor:pointer}
.do-radio input:checked{border:5px solid var(--do-accent)}
.do-radio input:focus-visible{outline:2px solid var(--do-accent);outline-offset:2px}
.do-prefs .do-actions{justify-content:space-between;padding-top:18px;border-top:1px solid var(--do-soft)}

/* 4. Unsubscribe */
.do-unsub .do-ico{background:#f1f3f8;color:var(--do-muted)}
.do-choice{display:flex;gap:12px;align-items:flex-start;padding:13px 14px;border:1.5px solid var(--do-soft);border-radius:12px;cursor:pointer;transition:border-color .15s,background-color .15s}
.do-choice+.do-choice{margin-top:8px}
.do-choice:has(:checked){border-color:var(--do-accent);background:var(--do-tint)}
.do-choice input{appearance:none;flex:none;width:18px;height:18px;margin:2px 0 0;border:1.5px solid var(--do-line);border-radius:50%;background:#fff;cursor:pointer}
.do-choice input:checked{border:5px solid var(--do-accent)}
.do-choice input:focus-visible{outline:2px solid var(--do-accent);outline-offset:2px}
.do-choice b{display:block;font-size:.92rem}
.do-choice small{font-size:.8rem;color:var(--do-muted)}
.do-label{display:block;font-weight:650;font-size:.86rem;margin:18px 0 6px}
.do-select{display:block;width:100%;font:inherit;color:var(--do-ink);border:1.5px solid var(--do-line);border-radius:10px;padding:9px 36px 9px 12px;cursor:pointer;appearance:none;
  background:#fff url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%234c586f' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='m7 10 5 5 5-5'/%3E%3C/svg%3E") no-repeat right 10px center/16px}
.do-select:focus{outline:none;border-color:var(--do-accent);box-shadow:0 0 0 4px var(--do-ring)}

@media (max-width:420px){.do{padding:24px 18px}.do-inbox{padding:28px 18px 24px}.do-actions .do-btn{flex:1 1 auto}}
@media (prefers-reduced-motion:reduce){.do-btn,.do-switch input,.do-radio,.do-choice{transition:none}}
JavaScript
// Front-end demo only: nothing is sent. Wire each handler to your email provider's API.
(function () {
  function time() { return new Date().toLocaleTimeString([], { hour: '2-digit', minute: '2-digit' }); }
  // Resend: confirm in a polite status region, then a 30 second cooldown. The button stays focusable (aria-disabled).
  document.querySelectorAll('[data-resend]').forEach(function (btn) {
    var status = document.getElementById(btn.getAttribute('aria-describedby'));
    var label = btn.lastChild.textContent;
    btn.addEventListener('click', function () {
      if (btn.getAttribute('aria-disabled') === 'true') return;
      status.textContent = 'We sent another link to ' + btn.getAttribute('data-email') + ' at ' + time() + '.';
      var left = 30;
      btn.setAttribute('aria-disabled', 'true');
      btn.lastChild.textContent = 'Resend in ' + left + ' s';
      var timer = setInterval(function () {
        left -= 1;
        btn.lastChild.textContent = left > 0 ? 'Resend in ' + left + ' s' : label;
        if (left <= 0) { clearInterval(timer); btn.removeAttribute('aria-disabled'); }
      }, 1000);
    });
  });
  // Preferences: save and confirm in the status region.
  document.querySelectorAll('form[data-prefs]').forEach(function (form) {
    form.addEventListener('submit', function (e) {
      e.preventDefault();
      document.getElementById(form.querySelector('[type=submit]').getAttribute('aria-describedby')).textContent = 'Preferences saved at ' + time() + '.';
    });
  });
  // Unsubscribe: swap in the result (or the monthly switch), and let a mistaken click be undone.
  document.querySelectorAll('form[data-unsub]').forEach(function (form) {
    var done = document.getElementById(form.getAttribute('data-unsub'));
    var title = done.querySelector('[data-done-title]'), text = done.querySelector('[data-done-text]'), resub = done.querySelector('[data-resub]');
    form.addEventListener('submit', function (e) {
      e.preventDefault();
      if (form.elements.action.value === 'monthly') {
        title.textContent = 'Switched to the monthly digest';
        text.textContent = 'The next one arrives on the first Tuesday of the month. Change it any time from your preferences.';
        resub.hidden = true;
      }
      form.hidden = true; done.hidden = false; done.focus();
    });
    resub.addEventListener('click', function () {
      title.textContent = "You're subscribed again";
      text.textContent = 'Field Notes will arrive next Tuesday as usual.';
      resub.hidden = true; done.focus();
    });
  });
})();

Bootstrap 5 code

Requires: Bootstrap 5.3.8 CSS

HTML
<svg width="0" height="0" style="position:absolute" aria-hidden="true" focusable="false">
  <symbol id="do-i-tick" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.4" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="9"/><path d="M8 12.5l2.8 2.8L16.5 9.5"/></symbol>
  <symbol id="do-i-out" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M4 7l8 6 8-6M4 6h16v12H4z"/><path d="M15 15l5 5M20 15l-5 5"/></symbol>
  <symbol id="do-i-redo" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M20 11a8 8 0 1 0-2.3 5.7M20 4v7h-7"/></symbol>
</svg>

<div class="demo-grid">
<div><span class="lbl">Check your inbox</span>
<section class="card do do-inbox" aria-labelledby="ci-title"><div class="card-body">
  <svg class="do-env" viewBox="0 0 120 84" aria-hidden="true"><rect x="6" y="14" width="108" height="66" rx="10" fill="#eaf0fe" stroke="#1d4ed8" stroke-width="3"/><path d="M9 20l51 36 51-36" fill="none" stroke="#1d4ed8" stroke-width="3" stroke-linejoin="round"/><circle cx="100" cy="16" r="14" fill="#1d4ed8"/><path d="M94 16.5l4 4 8-8" fill="none" stroke="#fff" stroke-width="3" stroke-linecap="round" stroke-linejoin="round"/></svg>
  <h2 class="do-title" id="ci-title">Confirm your subscription</h2>
  <p class="do-text">We sent a link to <b>[email protected]</b>. Field Notes starts once you click it. The link works for 48 hours.</p>
  <ol class="list-unstyled do-steps">
    <li><span>Open the email from Field Notes</span></li>
    <li><span>Click <b>Yes, subscribe me</b></span></li>
    <li><span>Tuesday's issue is yours</span></li>
  </ol>
  <div class="do-actions">
    <button class="btn do-btn" type="button" data-resend data-email="[email protected]" aria-describedby="ci-status"><svg aria-hidden="true"><use href="#do-i-redo"/></svg>Resend the email</button>
    <a href="#change-email">Use a different address</a>
  </div>
  <p class="do-status" id="ci-status" role="status"></p>
  <p class="do-small">Nothing after five minutes? Check spam and promotions, or add [email protected] to your contacts.</p>
</div></section>
</div>

<div><span class="lbl">Already subscribed</span>
<section class="card do do-already" aria-labelledby="as-title"><div class="card-body">
  <span class="do-ico" aria-hidden="true"><svg><use href="#do-i-tick"/></svg></span>
  <h2 class="do-title" id="as-title">You're already on the list</h2>
  <p class="do-text">Good news: there's nothing to do. This address already gets Field Notes.</p>
  <dl>
    <dt>Email</dt><dd>[email protected]</dd>
    <dt>Since</dt><dd>14 March 2025</dd>
    <dt>Arrives</dt><dd>Every Tuesday</dd>
  </dl>
  <div class="do-actions">
    <a class="btn do-btn" href="#preferences">Manage preferences</a>
    <a class="btn do-btn do-btn--ghost" href="#latest">Read the latest issue</a>
  </div>
</div></section>
</div>
</div>

<div class="demo-grid">
<div><span class="lbl">Manage preferences</span>
<section class="card do do-prefs" aria-labelledby="mp-title"><div class="card-body">
  <form action="#" method="post" data-prefs>
    <h2 class="do-title" id="mp-title">Email preferences</h2>
    <p class="do-who"><span>Signed in as <b>[email protected]</b></span><a href="#not-you">Not you?</a></p>
    <fieldset class="do-set">
      <legend>What we send you</legend>
      <div class="form-check form-switch"><input class="form-check-input" type="checkbox" role="switch" name="lists" value="field-notes" id="mp-l1" checked><label class="form-check-label" for="mp-l1"><b>Field Notes</b><small>Weekly essays on design and research</small></label></div>
      <div class="form-check form-switch"><input class="form-check-input" type="checkbox" role="switch" name="lists" value="product" id="mp-l2"><label class="form-check-label" for="mp-l2"><b>Product updates</b><small>New features, about once a month</small></label></div>
      <div class="form-check form-switch"><input class="form-check-input" type="checkbox" role="switch" name="lists" value="events" id="mp-l3" checked><label class="form-check-label" for="mp-l3"><b>Event invitations</b><small>Talks and workshops near you</small></label></div>
    </fieldset>
    <fieldset class="do-set">
      <legend>How often should Field Notes arrive?</legend>
      <div class="do-radios">
        <label class="do-radio"><input class="form-check-input" type="radio" name="freq" value="weekly" checked>Weekly</label>
        <label class="do-radio"><input class="form-check-input" type="radio" name="freq" value="fortnightly">Every two weeks</label>
        <label class="do-radio"><input class="form-check-input" type="radio" name="freq" value="monthly">Monthly digest</label>
      </div>
    </fieldset>
    <div class="do-actions">
      <button class="btn do-btn" type="submit" aria-describedby="mp-status">Save preferences</button>
      <a href="#unsubscribe-all">Unsubscribe from everything</a>
    </div>
    <p class="do-status" id="mp-status" role="status"></p>
  </form>
</div></section>
</div>

<div><span class="lbl">Unsubscribe</span>
<section class="card do do-unsub" aria-labelledby="us-title"><div class="card-body">
  <form action="#" method="post" data-unsub="us-done">
    <span class="do-ico" aria-hidden="true"><svg><use href="#do-i-out"/></svg></span>
    <h2 class="do-title" id="us-title">Unsubscribe from Field Notes?</h2>
    <p class="do-text">You'll stop getting the Tuesday email at <b>[email protected]</b>.</p>
    <fieldset class="do-set">
      <legend>What would you like to do?</legend>
      <label class="do-choice"><input class="form-check-input" type="radio" name="action" value="unsubscribe" checked><span><b>Unsubscribe</b><small>No more Field Notes emails</small></span></label>
      <label class="do-choice"><input class="form-check-input" type="radio" name="action" value="monthly"><span><b>Send me less</b><small>Switch to the monthly digest instead</small></span></label>
    </fieldset>
    <label class="form-label" for="us-reason">Why are you leaving? (optional)</label>
    <select class="form-select" id="us-reason" name="reason">
      <option value="">Prefer not to say</option>
      <option>Too many emails</option>
      <option>Not relevant to me any more</option>
      <option>I never signed up</option>
      <option>Other</option>
    </select>
    <div class="do-actions">
      <button class="btn do-btn do-btn--dark" type="submit">Confirm</button>
      <a href="#keep">Keep my subscription</a>
    </div>
  </form>
  <div class="do-done" id="us-done" tabindex="-1" hidden>
    <span class="do-ico" aria-hidden="true"><svg><use href="#do-i-tick"/></svg></span>
    <h2 class="do-title" data-done-title>You've been unsubscribed</h2>
    <p class="do-text" data-done-text>You won't get any more Field Notes emails. It can take up to a day for a scheduled issue to stop.</p>
    <div class="do-actions"><button class="btn do-btn do-btn--ghost" type="button" data-resub>Subscribed by mistake? Resubscribe</button></div>
  </div>
</div></section>
</div>
</div>
CSS
/* Bootstrap .card, .btn, .form-switch, .form-check-input, .form-select and .list-unstyled for the screens around a
   double opt-in newsletter, recoloured through Bootstrap's CSS variables. No Bootstrap JavaScript. */
.do{--do-ink:#172033;--do-muted:#4c586f;--do-line:#76819a;--do-soft:#dfe5ef;--do-accent:#1d4ed8;--do-accent-dark:#1e40af;--do-tint:#eaf0fe;--do-ring:rgba(29,78,216,.22);--do-ok:#15803d;
  --bs-card-border-width:0;--bs-card-border-radius:20px;--bs-card-spacer-x:30px;--bs-card-spacer-y:30px;
  color:var(--do-ink);font-size:.92rem;line-height:1.5;box-shadow:0 1px 2px rgba(23,32,51,.06),0 20px 44px -26px rgba(23,32,51,.4)}
.do p,.do h2,.do ol,.do dl,.do dd,.do legend{margin:0}
.do [hidden]{display:none!important}
.do a{color:var(--do-accent);font-weight:600;text-underline-offset:2px}
.do a:focus-visible{outline:2px solid var(--do-accent);outline-offset:2px;border-radius:3px}
.do-title{font-size:1.35rem;font-weight:750;letter-spacing:-.02em;line-height:1.25}
.do .do-text{color:var(--do-muted);margin-top:6px}
.do-text b{color:var(--do-ink);overflow-wrap:anywhere}
.do .do-btn{--bs-btn-color:#fff;--bs-btn-bg:var(--do-accent);--bs-btn-border-color:var(--do-accent);--bs-btn-hover-color:#fff;--bs-btn-hover-bg:var(--do-accent-dark);
  --bs-btn-hover-border-color:var(--do-accent-dark);--bs-btn-active-color:#fff;--bs-btn-active-bg:var(--do-accent-dark);--bs-btn-active-border-color:var(--do-accent-dark);
  --bs-btn-focus-box-shadow:none;--bs-btn-font-weight:650;--bs-btn-font-size:.92rem;--bs-btn-line-height:1.5;--bs-btn-padding-x:16px;--bs-btn-padding-y:9px;
  --bs-btn-border-width:1.5px;--bs-btn-border-radius:10px;display:inline-flex;align-items:center;justify-content:center;gap:8px;transition:background-color .15s,border-color .15s,color .15s}
.do .do-btn:focus-visible{outline:2px solid var(--do-accent);outline-offset:3px}
.do .do-btn svg{width:18px;height:18px}
.do a.do-btn{color:var(--bs-btn-color);text-decoration:none}
.do .do-btn--ghost{--bs-btn-color:var(--do-ink);--bs-btn-bg:#fff;--bs-btn-border-color:var(--do-line);--bs-btn-hover-color:var(--do-ink);--bs-btn-hover-bg:#f3f5f9;
  --bs-btn-hover-border-color:var(--do-ink);--bs-btn-active-color:var(--do-ink);--bs-btn-active-bg:#eceff5;--bs-btn-active-border-color:var(--do-ink)}
.do .do-btn--dark{--bs-btn-bg:var(--do-ink);--bs-btn-border-color:var(--do-ink);--bs-btn-hover-bg:#2a3550;--bs-btn-hover-border-color:#2a3550;--bs-btn-active-bg:#2a3550;--bs-btn-active-border-color:#2a3550}
.do .do-btn[aria-disabled=true]{--bs-btn-color:var(--do-muted);--bs-btn-bg:#f3f5f9;--bs-btn-border-color:var(--do-soft);--bs-btn-hover-color:var(--do-muted);--bs-btn-hover-bg:#f3f5f9;
  --bs-btn-hover-border-color:var(--do-soft);--bs-btn-active-color:var(--do-muted);--bs-btn-active-bg:#f3f5f9;--bs-btn-active-border-color:var(--do-soft);cursor:default}
.do-actions{display:flex;flex-wrap:wrap;align-items:center;gap:10px 14px;margin-top:20px}
.do .do-status{font-size:.84rem;color:var(--do-ok);font-weight:600;margin-top:12px}
.do .do-status:empty{display:none}
.do-ico{display:grid;place-items:center;width:52px;height:52px;border-radius:16px;margin-bottom:16px}
.do-ico svg{width:28px;height:28px}
.do .do-done{outline:none}
.do .do-done:focus-visible{outline:2px solid var(--do-accent);outline-offset:6px;border-radius:12px}

/* 1. Check your inbox */
.do-inbox{text-align:center}
.do-inbox .card-body{padding:34px 30px 30px}
.do-env{display:block;width:120px;height:84px;margin:0 auto 18px}
.do .do-steps{display:grid;gap:8px;margin:20px auto 0;max-width:340px;text-align:left;counter-reset:s}
.do-steps li{display:flex;gap:12px;align-items:center;counter-increment:s}
.do-steps li::before{content:counter(s);flex:none;display:grid;place-items:center;width:26px;height:26px;border-radius:50%;background:var(--do-tint);color:var(--do-accent-dark);font-weight:800;font-size:.8rem}
.do-inbox .do-actions{justify-content:center}
.do .do-small{font-size:.8rem;color:var(--do-muted);margin-top:16px}

/* 2. Already subscribed */
.do-already .do-ico{background:#dcfce7;color:var(--do-ok)}
.do-already dl{display:grid;grid-template-columns:auto 1fr;gap:6px 16px;margin-top:18px!important;padding:14px 16px;border-radius:12px;background:#f5f7fb;font-size:.86rem}
.do-already dt{color:var(--do-muted);font-weight:400}
.do-already dd{font-weight:600;overflow-wrap:anywhere}

/* 3. Manage preferences */
.do .do-who{display:flex;flex-wrap:wrap;justify-content:space-between;gap:4px 12px;align-items:baseline;padding-bottom:16px;margin-bottom:6px;border-bottom:1px solid var(--do-soft)}
.do-who span{color:var(--do-muted);font-size:.86rem}
.do-who b{color:var(--do-ink);overflow-wrap:anywhere}
.do-set{min-width:0;margin-top:18px}
.do .do-set legend{float:none;width:auto;font-weight:700;font-size:.95rem;line-height:1.5;padding:0;margin-bottom:6px}
.do .form-switch{display:flex;flex-direction:row-reverse;align-items:center;gap:14px;padding:12px 0;margin:0;border-top:1px solid var(--do-soft);min-height:0}
.do .form-switch:first-of-type{border-top:0}
.do .form-switch .form-check-label{flex:1;min-width:0;cursor:pointer}
.do .form-switch b{display:block;font-size:.92rem}
.do .form-switch small{font-size:.8rem;color:var(--do-muted)}
.do .form-switch .form-check-input{--bs-form-switch-bg:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='-4 -4 8 8'%3e%3ccircle r='3.2' fill='%23fff'/%3e%3c/svg%3e");
  flex:none;float:none;width:42px;height:24px;margin:0;border:0;background-color:var(--do-line);cursor:pointer;transition:background-color .2s,background-position .2s}
.do .form-switch .form-check-input:checked{background-color:var(--do-accent)}
.do .form-check-input:focus{box-shadow:none;border-color:var(--do-line)}
.do .form-check-input:focus-visible{outline:2px solid var(--do-accent);outline-offset:2px}
.do-radios{display:flex;flex-wrap:wrap;gap:8px}
.do-radio{display:inline-flex;align-items:center;gap:8px;padding:8px 13px;border:1.5px solid var(--do-soft);border-radius:10px;cursor:pointer;font-weight:600;font-size:.86rem;transition:border-color .15s,background-color .15s}
.do-radio:has(:checked),.do-choice:has(:checked){border-color:var(--do-accent);background:var(--do-tint)}
.do .do-radio .form-check-input,.do .do-choice .form-check-input{flex:none;width:16px;height:16px;margin:0;border:1.5px solid var(--do-line);cursor:pointer}
.do .do-radio .form-check-input:checked,.do .do-choice .form-check-input:checked{border:5px solid var(--do-accent);background:#fff}
.do-prefs .do-actions{justify-content:space-between;padding-top:18px;border-top:1px solid var(--do-soft)}

/* 4. Unsubscribe */
.do-unsub .do-ico{background:#f1f3f8;color:var(--do-muted)}
.do-choice{display:flex;gap:12px;align-items:flex-start;padding:13px 14px;border:1.5px solid var(--do-soft);border-radius:12px;cursor:pointer;transition:border-color .15s,background-color .15s}
.do-choice+.do-choice{margin-top:8px}
.do .do-choice .form-check-input{width:18px;height:18px;margin-top:2px}
.do-choice b{display:block;font-size:.92rem}
.do-choice small{font-size:.8rem;color:var(--do-muted)}
.do .form-label{display:block;font-weight:650;font-size:.86rem;margin:18px 0 6px}
.do .form-select{font-size:inherit;line-height:inherit;color:var(--do-ink);border:1.5px solid var(--do-line);border-radius:10px;padding:9px 36px 9px 12px;cursor:pointer;
  --bs-form-select-bg-img:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%234c586f' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='m7 10 5 5 5-5'/%3E%3C/svg%3E");background-position:right 10px center;background-size:16px}
.do .form-select:focus{border-color:var(--do-accent);box-shadow:0 0 0 4px var(--do-ring)}

@media (max-width:420px){.do{--bs-card-spacer-x:18px;--bs-card-spacer-y:24px}.do-inbox .card-body{padding:28px 18px 24px}.do-actions .do-btn{flex:1 1 auto}}
@media (prefers-reduced-motion:reduce){.do .do-btn,.do .form-switch .form-check-input,.do-radio,.do-choice{transition:none}}
JavaScript
// Front-end demo only: nothing is sent. Wire each handler to your email provider's API.
(function () {
  function time() { return new Date().toLocaleTimeString([], { hour: '2-digit', minute: '2-digit' }); }
  // Resend: confirm in a polite status region, then a 30 second cooldown. The button stays focusable (aria-disabled).
  document.querySelectorAll('[data-resend]').forEach(function (btn) {
    var status = document.getElementById(btn.getAttribute('aria-describedby'));
    var label = btn.lastChild.textContent;
    btn.addEventListener('click', function () {
      if (btn.getAttribute('aria-disabled') === 'true') return;
      status.textContent = 'We sent another link to ' + btn.getAttribute('data-email') + ' at ' + time() + '.';
      var left = 30;
      btn.setAttribute('aria-disabled', 'true');
      btn.lastChild.textContent = 'Resend in ' + left + ' s';
      var timer = setInterval(function () {
        left -= 1;
        btn.lastChild.textContent = left > 0 ? 'Resend in ' + left + ' s' : label;
        if (left <= 0) { clearInterval(timer); btn.removeAttribute('aria-disabled'); }
      }, 1000);
    });
  });
  // Preferences: save and confirm in the status region.
  document.querySelectorAll('form[data-prefs]').forEach(function (form) {
    form.addEventListener('submit', function (e) {
      e.preventDefault();
      document.getElementById(form.querySelector('[type=submit]').getAttribute('aria-describedby')).textContent = 'Preferences saved at ' + time() + '.';
    });
  });
  // Unsubscribe: swap in the result (or the monthly switch), and let a mistaken click be undone.
  document.querySelectorAll('form[data-unsub]').forEach(function (form) {
    var done = document.getElementById(form.getAttribute('data-unsub'));
    var title = done.querySelector('[data-done-title]'), text = done.querySelector('[data-done-text]'), resub = done.querySelector('[data-resub]');
    form.addEventListener('submit', function (e) {
      e.preventDefault();
      if (form.elements.action.value === 'monthly') {
        title.textContent = 'Switched to the monthly digest';
        text.textContent = 'The next one arrives on the first Tuesday of the month. Change it any time from your preferences.';
        resub.hidden = true;
      }
      form.hidden = true; done.hidden = false; done.focus();
    });
    resub.addEventListener('click', function () {
      title.textContent = "You're subscribed again";
      text.textContent = 'Field Notes will arrive next Tuesday as usual.';
      resub.hidden = true; done.focus();
    });
  });
})();

Tailwind 4 code

Requires: Tailwind CSS 4

HTML
<svg width="0" height="0" style="position:absolute" aria-hidden="true" focusable="false">
  <symbol id="do-i-tick" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.4" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="9"/><path d="M8 12.5l2.8 2.8L16.5 9.5"/></symbol>
  <symbol id="do-i-out" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M4 7l8 6 8-6M4 6h16v12H4z"/><path d="M15 15l5 5M20 15l-5 5"/></symbol>
  <symbol id="do-i-redo" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M20 11a8 8 0 1 0-2.3 5.7M20 4v7h-7"/></symbol>
</svg>

<div class="grid grid-cols-[repeat(auto-fit,minmax(300px,1fr))] items-start gap-[34px]">
<div><span class="mb-4 block text-[.72rem] tracking-[.12em] text-[#53607a] uppercase">Check your inbox</span>
<section class="rounded-[20px] bg-white px-[30px] pt-[34px] pb-[30px] text-center text-[.92rem] leading-normal shadow-[0_1px_2px_rgba(23,32,51,.06),0_20px_44px_-26px_rgba(23,32,51,.4)] max-[420px]:px-[18px] max-[420px]:pt-7 max-[420px]:pb-6" aria-labelledby="ci-title">
  <svg class="mx-auto mb-[18px] block h-[84px] w-[120px]" viewBox="0 0 120 84" aria-hidden="true"><rect x="6" y="14" width="108" height="66" rx="10" fill="#eaf0fe" stroke="#1d4ed8" stroke-width="3"/><path d="M9 20l51 36 51-36" fill="none" stroke="#1d4ed8" stroke-width="3" stroke-linejoin="round"/><circle cx="100" cy="16" r="14" fill="#1d4ed8"/><path d="M94 16.5l4 4 8-8" fill="none" stroke="#fff" stroke-width="3" stroke-linecap="round" stroke-linejoin="round"/></svg>
  <h2 class="text-[1.35rem] leading-[1.25] font-[750] tracking-[-.02em]" id="ci-title">Confirm your subscription</h2>
  <p class="mt-1.5 text-do-muted">We sent a link to <b class="wrap-anywhere text-do-ink">[email protected]</b>. Field Notes starts once you click it. The link works for 48 hours.</p>
  <ol class="mx-auto mt-5 grid max-w-[340px] gap-2 text-left [counter-reset:s]">
    <li class="flex items-center gap-3 [counter-increment:s] before:grid before:size-[26px] before:flex-none before:place-items-center before:rounded-full before:bg-do-tint before:text-[.8rem] before:font-extrabold before:text-do-accent-dark before:content-[counter(s)]"><span>Open the email from Field Notes</span></li>
    <li class="flex items-center gap-3 [counter-increment:s] before:grid before:size-[26px] before:flex-none before:place-items-center before:rounded-full before:bg-do-tint before:text-[.8rem] before:font-extrabold before:text-do-accent-dark before:content-[counter(s)]"><span>Click <b>Yes, subscribe me</b></span></li>
    <li class="flex items-center gap-3 [counter-increment:s] before:grid before:size-[26px] before:flex-none before:place-items-center before:rounded-full before:bg-do-tint before:text-[.8rem] before:font-extrabold before:text-do-accent-dark before:content-[counter(s)]"><span>Tuesday's issue is yours</span></li>
  </ol>
  <div class="mt-5 flex flex-wrap items-center justify-center gap-x-3.5 gap-y-2.5">
    <button class="inline-flex cursor-pointer items-center justify-center gap-2 rounded-[10px] border-[1.5px] border-do-accent bg-do-accent px-4 py-[9px] font-[650] text-white transition-colors duration-150 hover:border-do-accent-dark hover:bg-do-accent-dark focus-visible:outline-2 focus-visible:outline-offset-3 focus-visible:outline-do-accent aria-disabled:cursor-default aria-disabled:border-do-soft aria-disabled:bg-[#f3f5f9] aria-disabled:text-do-muted motion-reduce:transition-none max-[420px]:flex-auto" type="button" data-resend data-email="[email protected]" aria-describedby="ci-status"><svg class="size-[18px]" aria-hidden="true"><use href="#do-i-redo"/></svg>Resend the email</button>
    <a class="font-semibold text-do-accent underline underline-offset-2 focus-visible:rounded-[3px] focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-do-accent" href="#change-email">Use a different address</a>
  </div>
  <p class="mt-3 text-[.84rem] font-semibold text-do-ok empty:hidden" id="ci-status" role="status"></p>
  <p class="mt-4 text-[.8rem] text-do-muted">Nothing after five minutes? Check spam and promotions, or add [email protected] to your contacts.</p>
</section>
</div>

<div><span class="mb-4 block text-[.72rem] tracking-[.12em] text-[#53607a] uppercase">Already subscribed</span>
<section class="rounded-[20px] bg-white p-[30px] text-[.92rem] leading-normal shadow-[0_1px_2px_rgba(23,32,51,.06),0_20px_44px_-26px_rgba(23,32,51,.4)] max-[420px]:px-[18px] max-[420px]:py-6" aria-labelledby="as-title">
  <span class="mb-4 grid size-[52px] place-items-center rounded-2xl bg-[#dcfce7] text-do-ok" aria-hidden="true"><svg class="size-7"><use href="#do-i-tick"/></svg></span>
  <h2 class="text-[1.35rem] leading-[1.25] font-[750] tracking-[-.02em]" id="as-title">You're already on the list</h2>
  <p class="mt-1.5 text-do-muted">Good news: there's nothing to do. This address already gets Field Notes.</p>
  <dl class="mt-[18px] grid grid-cols-[auto_1fr] gap-x-4 gap-y-1.5 rounded-xl bg-[#f5f7fb] px-4 py-3.5 text-[.86rem]">
    <dt class="text-do-muted">Email</dt><dd class="font-semibold wrap-anywhere">[email protected]</dd>
    <dt class="text-do-muted">Since</dt><dd class="font-semibold">14 March 2025</dd>
    <dt class="text-do-muted">Arrives</dt><dd class="font-semibold">Every Tuesday</dd>
  </dl>
  <div class="mt-5 flex flex-wrap items-center gap-x-3.5 gap-y-2.5">
    <a class="inline-flex items-center justify-center rounded-[10px] border-[1.5px] border-do-accent bg-do-accent px-4 py-[9px] font-[650] text-white transition-colors duration-150 hover:border-do-accent-dark hover:bg-do-accent-dark focus-visible:outline-2 focus-visible:outline-offset-3 focus-visible:outline-do-accent motion-reduce:transition-none max-[420px]:flex-auto" href="#preferences">Manage preferences</a>
    <a class="inline-flex items-center justify-center rounded-[10px] border-[1.5px] border-do-line bg-white px-4 py-[9px] font-[650] text-do-ink transition-colors duration-150 hover:border-do-ink hover:bg-[#f3f5f9] focus-visible:outline-2 focus-visible:outline-offset-3 focus-visible:outline-do-accent motion-reduce:transition-none max-[420px]:flex-auto" href="#latest">Read the latest issue</a>
  </div>
</section>
</div>
</div>

<div class="grid grid-cols-[repeat(auto-fit,minmax(300px,1fr))] items-start gap-[34px]">
<div><span class="mb-4 block text-[.72rem] tracking-[.12em] text-[#53607a] uppercase">Manage preferences</span>
<section class="rounded-[20px] bg-white p-[30px] text-[.92rem] leading-normal shadow-[0_1px_2px_rgba(23,32,51,.06),0_20px_44px_-26px_rgba(23,32,51,.4)] max-[420px]:px-[18px] max-[420px]:py-6" aria-labelledby="mp-title">
  <form action="#" method="post" data-prefs>
    <h2 class="text-[1.35rem] leading-[1.25] font-[750] tracking-[-.02em]" id="mp-title">Email preferences</h2>
    <p class="mb-1.5 flex flex-wrap items-baseline justify-between gap-x-3 gap-y-1 border-b border-do-soft pb-4"><span class="text-[.86rem] text-do-muted">Signed in as <b class="wrap-anywhere text-do-ink">[email protected]</b></span><a class="font-semibold text-do-accent underline underline-offset-2 focus-visible:rounded-[3px] focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-do-accent" href="#not-you">Not you?</a></p>
    <fieldset class="mt-[18px] min-w-0">
      <legend class="mb-1.5 text-[.95rem] font-bold">What we send you</legend>
      <label class="flex cursor-pointer items-center gap-3.5 py-3"><span class="min-w-0 flex-1"><b class="block text-[.92rem]">Field Notes</b><small class="text-[.8rem] text-do-muted">Weekly essays on design and research</small></span><input class="m-0 h-6 w-[42px] flex-none cursor-pointer appearance-none rounded-full bg-do-line bg-do-knob bg-size-[24px_24px] bg-position-[left_1px_center] bg-no-repeat transition-[background-color,background-position] duration-200 checked:bg-do-accent checked:bg-position-[right_1px_center] focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-do-accent motion-reduce:transition-none" type="checkbox" role="switch" name="lists" value="field-notes" checked></label>
      <label class="flex cursor-pointer items-center gap-3.5 border-t border-do-soft py-3"><span class="min-w-0 flex-1"><b class="block text-[.92rem]">Product updates</b><small class="text-[.8rem] text-do-muted">New features, about once a month</small></span><input class="m-0 h-6 w-[42px] flex-none cursor-pointer appearance-none rounded-full bg-do-line bg-do-knob bg-size-[24px_24px] bg-position-[left_1px_center] bg-no-repeat transition-[background-color,background-position] duration-200 checked:bg-do-accent checked:bg-position-[right_1px_center] focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-do-accent motion-reduce:transition-none" type="checkbox" role="switch" name="lists" value="product"></label>
      <label class="flex cursor-pointer items-center gap-3.5 border-t border-do-soft py-3"><span class="min-w-0 flex-1"><b class="block text-[.92rem]">Event invitations</b><small class="text-[.8rem] text-do-muted">Talks and workshops near you</small></span><input class="m-0 h-6 w-[42px] flex-none cursor-pointer appearance-none rounded-full bg-do-line bg-do-knob bg-size-[24px_24px] bg-position-[left_1px_center] bg-no-repeat transition-[background-color,background-position] duration-200 checked:bg-do-accent checked:bg-position-[right_1px_center] focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-do-accent motion-reduce:transition-none" type="checkbox" role="switch" name="lists" value="events" checked></label>
    </fieldset>
    <fieldset class="mt-[18px] min-w-0">
      <legend class="mb-1.5 text-[.95rem] font-bold">How often should Field Notes arrive?</legend>
      <div class="flex flex-wrap gap-2">
        <label class="inline-flex cursor-pointer items-center gap-2 rounded-[10px] border-[1.5px] border-do-soft px-[13px] py-2 text-[.86rem] font-semibold transition-colors duration-150 has-checked:border-do-accent has-checked:bg-do-tint motion-reduce:transition-none"><input class="m-0 size-4 cursor-pointer appearance-none rounded-full border-[1.5px] border-do-line bg-white checked:border-5 checked:border-do-accent focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-do-accent" type="radio" name="freq" value="weekly" checked>Weekly</label>
        <label class="inline-flex cursor-pointer items-center gap-2 rounded-[10px] border-[1.5px] border-do-soft px-[13px] py-2 text-[.86rem] font-semibold transition-colors duration-150 has-checked:border-do-accent has-checked:bg-do-tint motion-reduce:transition-none"><input class="m-0 size-4 cursor-pointer appearance-none rounded-full border-[1.5px] border-do-line bg-white checked:border-5 checked:border-do-accent focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-do-accent" type="radio" name="freq" value="fortnightly">Every two weeks</label>
        <label class="inline-flex cursor-pointer items-center gap-2 rounded-[10px] border-[1.5px] border-do-soft px-[13px] py-2 text-[.86rem] font-semibold transition-colors duration-150 has-checked:border-do-accent has-checked:bg-do-tint motion-reduce:transition-none"><input class="m-0 size-4 cursor-pointer appearance-none rounded-full border-[1.5px] border-do-line bg-white checked:border-5 checked:border-do-accent focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-do-accent" type="radio" name="freq" value="monthly">Monthly digest</label>
      </div>
    </fieldset>
    <div class="mt-5 flex flex-wrap items-center justify-between gap-x-3.5 gap-y-2.5 border-t border-do-soft pt-[18px]">
      <button class="inline-flex cursor-pointer items-center justify-center gap-2 rounded-[10px] border-[1.5px] border-do-accent bg-do-accent px-4 py-[9px] font-[650] text-white transition-colors duration-150 hover:border-do-accent-dark hover:bg-do-accent-dark focus-visible:outline-2 focus-visible:outline-offset-3 focus-visible:outline-do-accent motion-reduce:transition-none max-[420px]:flex-auto" type="submit" aria-describedby="mp-status">Save preferences</button>
      <a class="font-semibold text-do-accent underline underline-offset-2 focus-visible:rounded-[3px] focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-do-accent" href="#unsubscribe-all">Unsubscribe from everything</a>
    </div>
    <p class="mt-3 text-[.84rem] font-semibold text-do-ok empty:hidden" id="mp-status" role="status"></p>
  </form>
</section>
</div>

<div><span class="mb-4 block text-[.72rem] tracking-[.12em] text-[#53607a] uppercase">Unsubscribe</span>
<section class="rounded-[20px] bg-white p-[30px] text-[.92rem] leading-normal shadow-[0_1px_2px_rgba(23,32,51,.06),0_20px_44px_-26px_rgba(23,32,51,.4)] max-[420px]:px-[18px] max-[420px]:py-6" aria-labelledby="us-title">
  <form action="#" method="post" data-unsub="us-done">
    <span class="mb-4 grid size-[52px] place-items-center rounded-2xl bg-[#f1f3f8] text-do-muted" aria-hidden="true"><svg class="size-7"><use href="#do-i-out"/></svg></span>
    <h2 class="text-[1.35rem] leading-[1.25] font-[750] tracking-[-.02em]" id="us-title">Unsubscribe from Field Notes?</h2>
    <p class="mt-1.5 text-do-muted">You'll stop getting the Tuesday email at <b class="wrap-anywhere text-do-ink">[email protected]</b>.</p>
    <fieldset class="mt-[18px] min-w-0">
      <legend class="mb-1.5 text-[.95rem] font-bold">What would you like to do?</legend>
      <label class="flex cursor-pointer items-start gap-3 rounded-xl border-[1.5px] border-do-soft px-3.5 py-[13px] transition-colors duration-150 has-checked:border-do-accent has-checked:bg-do-tint motion-reduce:transition-none"><input class="m-0 mt-0.5 size-[18px] flex-none cursor-pointer appearance-none rounded-full border-[1.5px] border-do-line bg-white checked:border-5 checked:border-do-accent focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-do-accent" type="radio" name="action" value="unsubscribe" checked><span><b class="block text-[.92rem]">Unsubscribe</b><small class="text-[.8rem] text-do-muted">No more Field Notes emails</small></span></label>
      <label class="mt-2 flex cursor-pointer items-start gap-3 rounded-xl border-[1.5px] border-do-soft px-3.5 py-[13px] transition-colors duration-150 has-checked:border-do-accent has-checked:bg-do-tint motion-reduce:transition-none"><input class="m-0 mt-0.5 size-[18px] flex-none cursor-pointer appearance-none rounded-full border-[1.5px] border-do-line bg-white checked:border-5 checked:border-do-accent focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-do-accent" type="radio" name="action" value="monthly"><span><b class="block text-[.92rem]">Send me less</b><small class="text-[.8rem] text-do-muted">Switch to the monthly digest instead</small></span></label>
    </fieldset>
    <label class="mt-[18px] mb-1.5 block text-[.86rem] font-[650]" for="us-reason">Why are you leaving? (optional)</label>
    <select class="block w-full cursor-pointer appearance-none rounded-[10px] border-[1.5px] border-do-line bg-white bg-do-chevron bg-size-[16px] bg-position-[right_10px_center] bg-no-repeat py-[9px] pr-9 pl-3 text-do-ink focus:border-do-accent focus:shadow-[0_0_0_4px_rgba(29,78,216,.22)] focus:outline-none" id="us-reason" name="reason">
      <option value="">Prefer not to say</option>
      <option>Too many emails</option>
      <option>Not relevant to me any more</option>
      <option>I never signed up</option>
      <option>Other</option>
    </select>
    <div class="mt-5 flex flex-wrap items-center gap-x-3.5 gap-y-2.5">
      <button class="inline-flex cursor-pointer items-center justify-center gap-2 rounded-[10px] border-[1.5px] border-do-ink bg-do-ink px-4 py-[9px] font-[650] text-white transition-colors duration-150 hover:border-[#2a3550] hover:bg-[#2a3550] focus-visible:outline-2 focus-visible:outline-offset-3 focus-visible:outline-do-accent motion-reduce:transition-none max-[420px]:flex-auto" type="submit">Confirm</button>
      <a class="font-semibold text-do-accent underline underline-offset-2 focus-visible:rounded-[3px] focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-do-accent" href="#keep">Keep my subscription</a>
    </div>
  </form>
  <div class="focus-visible:rounded-xl focus-visible:outline-2 focus-visible:outline-offset-6 focus-visible:outline-do-accent" id="us-done" tabindex="-1" hidden>
    <span class="mb-4 grid size-[52px] place-items-center rounded-2xl bg-[#f1f3f8] text-do-muted" aria-hidden="true"><svg class="size-7"><use href="#do-i-tick"/></svg></span>
    <h2 class="text-[1.35rem] leading-[1.25] font-[750] tracking-[-.02em]" data-done-title>You've been unsubscribed</h2>
    <p class="mt-1.5 text-do-muted" data-done-text>You won't get any more Field Notes emails. It can take up to a day for a scheduled issue to stop.</p>
    <div class="mt-5 flex flex-wrap items-center gap-x-3.5 gap-y-2.5"><button class="inline-flex cursor-pointer items-center justify-center rounded-[10px] border-[1.5px] border-do-line bg-white px-4 py-[9px] font-[650] text-do-ink transition-colors duration-150 hover:border-do-ink hover:bg-[#f3f5f9] focus-visible:outline-2 focus-visible:outline-offset-3 focus-visible:outline-do-accent motion-reduce:transition-none max-[420px]:flex-auto" type="button" data-resub>Subscribed by mistake? Resubscribe</button></div>
  </div>
</section>
</div>
</div>
CSS
@theme {
  --color-do-ink: #172033;
  --color-do-muted: #4c586f;
  --color-do-line: #76819a;
  --color-do-soft: #dfe5ef;
  --color-do-accent: #1d4ed8;
  --color-do-accent-dark: #1e40af;
  --color-do-tint: #eaf0fe;
  --color-do-ok: #15803d;
  --background-image-do-knob: radial-gradient(circle, #fff 8px, transparent 8.5px);
  --background-image-do-chevron: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%234c586f' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='m7 10 5 5 5-5'/%3E%3C/svg%3E");
}
JavaScript
// Front-end demo only: nothing is sent. Wire each handler to your email provider's API.
(function () {
  function time() { return new Date().toLocaleTimeString([], { hour: '2-digit', minute: '2-digit' }); }
  // Resend: confirm in a polite status region, then a 30 second cooldown. The button stays focusable (aria-disabled).
  document.querySelectorAll('[data-resend]').forEach(function (btn) {
    var status = document.getElementById(btn.getAttribute('aria-describedby'));
    var label = btn.lastChild.textContent;
    btn.addEventListener('click', function () {
      if (btn.getAttribute('aria-disabled') === 'true') return;
      status.textContent = 'We sent another link to ' + btn.getAttribute('data-email') + ' at ' + time() + '.';
      var left = 30;
      btn.setAttribute('aria-disabled', 'true');
      btn.lastChild.textContent = 'Resend in ' + left + ' s';
      var timer = setInterval(function () {
        left -= 1;
        btn.lastChild.textContent = left > 0 ? 'Resend in ' + left + ' s' : label;
        if (left <= 0) { clearInterval(timer); btn.removeAttribute('aria-disabled'); }
      }, 1000);
    });
  });
  // Preferences: save and confirm in the status region.
  document.querySelectorAll('form[data-prefs]').forEach(function (form) {
    form.addEventListener('submit', function (e) {
      e.preventDefault();
      document.getElementById(form.querySelector('[type=submit]').getAttribute('aria-describedby')).textContent = 'Preferences saved at ' + time() + '.';
    });
  });
  // Unsubscribe: swap in the result (or the monthly switch), and let a mistaken click be undone.
  document.querySelectorAll('form[data-unsub]').forEach(function (form) {
    var done = document.getElementById(form.getAttribute('data-unsub'));
    var title = done.querySelector('[data-done-title]'), text = done.querySelector('[data-done-text]'), resub = done.querySelector('[data-resub]');
    form.addEventListener('submit', function (e) {
      e.preventDefault();
      if (form.elements.action.value === 'monthly') {
        title.textContent = 'Switched to the monthly digest';
        text.textContent = 'The next one arrives on the first Tuesday of the month. Change it any time from your preferences.';
        resub.hidden = true;
      }
      form.hidden = true; done.hidden = false; done.focus();
    });
    resub.addEventListener('click', function () {
      title.textContent = "You're subscribed again";
      text.textContent = 'Field Notes will arrive next Tuesday as usual.';
      resub.hidden = true; done.focus();
    });
  });
})();

About this set

The four screens around a double opt-in newsletter, which most kits leave out. Check your inbox shows an envelope illustration, the address the link went to, how long the link lasts, three numbered steps, a Resend the email button and a link to use a different address. Resending confirms in a polite status message and starts a 30 second cooldown on the button. Already subscribed tells someone who signs up twice that there is nothing to do, with their address, start date and send day, and links to manage preferences or read the latest issue. Manage preferences has switch rows for each list and a frequency choice, with a save button that confirms in a status message and an unsubscribe-from-everything link. Unsubscribe offers a plain choice between leaving and receiving less, an optional reason, a neutral Confirm button and a Keep my subscription link; afterwards it confirms and lets a mistaken click be undone. There is no guilt-trip copy anywhere: leaving is as easy as joining. A short vanilla script handles the demo states; nothing is sent.

What’s included

  • Resend button with a status message and 30 second cooldown
  • Already subscribed screen with subscription details
  • Preference switches with role="switch" and a frequency choice
  • Unsubscribe with a send me less option and an undo
  • Bootstrap version uses .form-switch, .form-select, .btn and .card

Accessibility

Status messages for resend and save sit in role="status" regions, and the resend button stays focusable with aria-disabled during its cooldown. Preference toggles are checkboxes with role="switch" inside their labels; choices are grouped in fieldsets with legends, and the optional reason select has a visible label. The unsubscribe result is focused when it appears, focus rings are visible, and transitions switch off under prefers-reduced-motion.

Customise it

Set --do-accent, --do-accent-dark and --do-tint on .do for the brand colour, --do-ok for confirmations and --do-line for borders. The envelope is an inline SVG you can recolour. In Tailwind change the do-* colours in @theme.