Open demo

CSS code

HTML
<div class="demo-grid">
<div><span class="lbl">Developer sign-up</span>
<form class="dk" action="#" method="post" aria-labelledby="rl-title">
  <div class="dk-brand"><span class="dk-mark"><svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M4 17l6-6-6-6M12 19h8"/></svg></span>Relay</div>
  <h2 class="dk-title" id="rl-title">Create your Relay account</h2>
  <p class="dk-sub">A preview URL for every branch you push. Fields marked <span class="dk-req">*</span> are required.</p>
  <div class="dk-field">
    <label class="dk-label" for="rl-email">Email <span class="dk-req" aria-hidden="true">*</span></label>
    <input class="dk-input" id="rl-email" name="email" type="email" autocomplete="email" required>
  </div>
  <div class="dk-field">
    <label class="dk-label" for="rl-user">Username <span class="dk-req" aria-hidden="true">*</span></label>
    <div class="dk-group">
      <span class="dk-prefix" aria-hidden="true">relay.dev/</span>
      <input class="dk-input" id="rl-user" name="username" type="text" autocomplete="username" required pattern="[a-z0-9\-]{3,24}" aria-describedby="rl-user-hint">
    </div>
    <p class="dk-hint" id="rl-user-hint">Your projects live at relay.dev/username. 3 to 24 lowercase letters, numbers or hyphens.</p>
  </div>
  <div class="dk-field">
    <label class="dk-label" for="rl-pw">Password <span class="dk-req" aria-hidden="true">*</span></label>
    <div class="dk-group">
      <input class="dk-input" id="rl-pw" name="password" type="password" autocomplete="new-password" minlength="10" required aria-describedby="rl-pw-hint">
      <button class="dk-eye" type="button" aria-controls="rl-pw" aria-pressed="false" aria-label="Show password" data-pw-toggle hidden>
        <svg class="dk-show" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M2 12s3.6-7 10-7 10 7 10 7-3.6 7-10 7S2 12 2 12z"/><circle cx="12" cy="12" r="3"/></svg>
        <svg class="dk-hide" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M3 3l18 18M10.6 5.1A10.7 10.7 0 0 1 12 5c6.4 0 10 7 10 7a17.6 17.6 0 0 1-2.9 3.9M6.6 6.6C3.8 8.4 2 12 2 12s3.6 7 10 7a10 10 0 0 0 5.4-1.6M9.9 9.9a3 3 0 0 0 4.2 4.2"/></svg>
      </button>
    </div>
    <p class="dk-hint" id="rl-pw-hint">At least 10 characters.</p>
  </div>
  <fieldset class="dk-plans">
    <legend>Plan</legend>
    <div class="dk-plan-grid">
      <label class="dk-plan"><input class="dk-radio" type="radio" name="plan" value="hobby" checked><span><b>Hobby</b><small>Free, 3 projects</small></span></label>
      <label class="dk-plan"><input class="dk-radio" type="radio" name="plan" value="team"><span><b>Team</b><small>$12 a seat a month</small></span></label>
    </div>
  </fieldset>
  <button class="dk-btn" type="submit">Create account</button>
  <p class="dk-foot">Already have an account? <a href="#">Sign in</a></p>
</form>
</div>
<div><span class="lbl">Invite-only registration</span>
<form class="dk dk--violet" action="#" method="post" aria-labelledby="nj-title">
  <div class="dk-brand"><span class="dk-mark"><svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M20 14.5A8 8 0 1 1 9.5 4a6.5 6.5 0 0 0 10.5 10.5z"/></svg></span>Nightjar</div>
  <h2 class="dk-title" id="nj-title">Join the observing circle</h2>
  <p class="dk-sub">A members-only forum for amateur astronomers. Every field is required.</p>
  <div class="dk-field">
    <label class="dk-label" for="nj-code">Invite code</label>
    <input class="dk-input dk-code" id="nj-code" name="invite" type="text" autocomplete="off" spellcheck="false" required pattern="[A-Za-z0-9]{4}-[A-Za-z0-9]{4}" maxlength="9" aria-describedby="nj-code-hint">
    <p class="dk-hint" id="nj-code-hint">Eight letters and numbers from your invite email, like K7QD-2MXF.</p>
  </div>
  <div class="dk-field">
    <label class="dk-label" for="nj-nick">Display name</label>
    <input class="dk-input" id="nj-nick" name="nickname" type="text" autocomplete="nickname" required>
  </div>
  <div class="dk-field">
    <label class="dk-label" for="nj-email">Email</label>
    <input class="dk-input" id="nj-email" name="email" type="email" autocomplete="email" required>
  </div>
  <div class="dk-field">
    <label class="dk-label" for="nj-pw">Password</label>
    <div class="dk-group">
      <input class="dk-input" id="nj-pw" name="password" type="password" autocomplete="new-password" minlength="10" required aria-describedby="nj-pw-hint">
      <button class="dk-eye" type="button" aria-controls="nj-pw" aria-pressed="false" aria-label="Show password" data-pw-toggle hidden>
        <svg class="dk-show" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M2 12s3.6-7 10-7 10 7 10 7-3.6 7-10 7S2 12 2 12z"/><circle cx="12" cy="12" r="3"/></svg>
        <svg class="dk-hide" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M3 3l18 18M10.6 5.1A10.7 10.7 0 0 1 12 5c6.4 0 10 7 10 7a17.6 17.6 0 0 1-2.9 3.9M6.6 6.6C3.8 8.4 2 12 2 12s3.6 7 10 7a10 10 0 0 0 5.4-1.6M9.9 9.9a3 3 0 0 0 4.2 4.2"/></svg>
      </button>
    </div>
    <p class="dk-hint" id="nj-pw-hint">At least 10 characters.</p>
  </div>
  <label class="dk-check"><input class="dk-box" type="checkbox" name="directory" checked><span>List me in the member directory (you can change this later)</span></label>
  <button class="dk-btn" type="submit">Accept invite</button>
  <p class="dk-foot">No invite? <a href="#">Ask to join the waitlist</a></p>
</form>
</div>
</div>
CSS
/* Dark registration forms. Borders are lightened to keep 3:1 against the card, text stays above 4.5:1, and the
   accent only marks focus and the main action. The eye button only appears once the script runs. */
.dk{--dk-bg:#111722;--dk-field:#0b1019;--dk-ink:#e8edf5;--dk-muted:#9aa4b5;--dk-line:#6b7588;--dk-rule:#232c3b;--dk-accent:#a3e635;--dk-accent-ink:#0b1019;
  --dk-ring:rgba(163,230,53,.28);--dk-error:#f87171;
  background:var(--dk-bg);color:var(--dk-ink);border:1px solid var(--dk-rule);border-radius:20px;padding:32px 30px 28px;font-size:.92rem;line-height:1.45;
  box-shadow:0 24px 50px -24px rgba(0,0,0,.7),inset 0 1px 0 rgba(255,255,255,.04)}
.dk--violet{--dk-accent:#a78bfa;--dk-ring:rgba(167,139,250,.3)}
.dk-brand{display:flex;align-items:center;gap:10px;font-weight:700;margin-bottom:20px}
.dk-mark{width:32px;height:32px;border-radius:9px;background:var(--dk-accent);color:var(--dk-accent-ink);display:grid;place-items:center}
.dk-title{font-size:1.4rem;font-weight:750;letter-spacing:-.02em;line-height:1.2}
.dk-sub{color:var(--dk-muted);margin:6px 0 20px}
.dk-req{color:var(--dk-accent);font-weight:700}
.dk-field{margin-bottom:16px;min-width:0}
.dk-label{display:block;font-size:.84rem;font-weight:600;margin-bottom:6px}
.dk-input{display:block;width:100%;min-width:0;font:inherit;color:var(--dk-ink);background:var(--dk-field);border:1px solid var(--dk-line);border-radius:10px;padding:11px 13px;
  transition:border-color .15s,box-shadow .15s}
.dk-input:focus{outline:none;border-color:var(--dk-accent);box-shadow:0 0 0 3px var(--dk-ring)}
.dk-input:user-invalid{border-color:var(--dk-error)}
.dk-hint{font-size:.8rem;color:var(--dk-muted);margin-top:6px}
/* joined groups: fixed prefix + input, input + eye button */
.dk-group{display:flex;background:var(--dk-field);border:1px solid var(--dk-line);border-radius:10px;transition:border-color .15s,box-shadow .15s}
.dk-group:focus-within{border-color:var(--dk-accent);box-shadow:0 0 0 3px var(--dk-ring)}
.dk-group:has(:user-invalid){border-color:var(--dk-error)}
.dk-group .dk-input,.dk-group .dk-input:focus{flex:1;border:0;box-shadow:none;background:transparent}
.dk-prefix{display:flex;align-items:center;padding:0 0 0 13px;color:var(--dk-muted);font-family:ui-monospace,SFMono-Regular,Menlo,monospace;font-size:.84rem}
.dk-prefix+.dk-input{padding-left:2px}
.dk-eye{flex:none;width:46px;border:0;background:none;color:var(--dk-muted);cursor:pointer;border-radius:0 10px 10px 0;display:grid;place-items:center}
.dk-eye:hover{color:var(--dk-ink)}
.dk-eye:focus-visible{outline:2px solid var(--dk-accent);outline-offset:-5px;border-radius:8px}
.dk-eye[hidden],.dk-eye[aria-pressed="true"] .dk-show,.dk-eye[aria-pressed="false"] .dk-hide{display:none}
/* plan picker: two radio cards */
.dk-plans{border:0;margin:4px 0 18px;min-width:0}
.dk-plans legend{font-size:.84rem;font-weight:600;margin-bottom:8px}
.dk-plan-grid{display:grid;grid-template-columns:1fr 1fr;gap:10px}
.dk-plan{display:flex;gap:10px;align-items:flex-start;padding:12px;border:1px solid var(--dk-line);border-radius:12px;cursor:pointer;transition:border-color .15s,background-color .15s}
.dk-plan:has(:checked){border-color:var(--dk-accent);background:rgba(163,230,53,.07)}
.dk-plan b{display:block;font-weight:650}
.dk-plan small{font-size:.78rem;color:var(--dk-muted)}
.dk-radio,.dk-box{appearance:none;flex:none;width:18px;height:18px;margin-top:1px;border:1.5px solid var(--dk-line);background:var(--dk-field) center/12px no-repeat;cursor:pointer;
  transition:border-color .15s,background-color .15s}
.dk-radio{border-radius:50%}
.dk-radio:checked{border:5px solid var(--dk-accent);background-color:var(--dk-accent-ink)}
.dk-box{border-radius:5px}
.dk-box:checked{background-color:var(--dk-accent);border-color:var(--dk-accent);
  background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3E%3Cpath d='M3.5 8.5l3 3 6-7' fill='none' stroke='%230b1019' stroke-width='2.2' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E")}
.dk-radio:focus-visible,.dk-box:focus-visible{outline:2px solid var(--dk-accent);outline-offset:2px}
.dk-check{display:flex;gap:10px;align-items:flex-start;font-size:.86rem;margin:2px 0 18px;cursor:pointer}
.dk-code{font-family:ui-monospace,SFMono-Regular,Menlo,monospace;letter-spacing:.18em;text-transform:uppercase}
.dk-btn{display:block;width:100%;font:inherit;font-weight:700;color:var(--dk-accent-ink);background:var(--dk-accent);border:0;border-radius:10px;padding:12px 16px;cursor:pointer;
  box-shadow:0 0 0 1px rgba(255,255,255,.06),0 8px 24px -8px var(--dk-ring);transition:filter .15s,box-shadow .15s}
.dk-btn:hover{filter:brightness(1.08);box-shadow:0 0 0 1px rgba(255,255,255,.08),0 10px 30px -6px var(--dk-ring)}
.dk-btn:focus-visible{outline:2px solid var(--dk-accent);outline-offset:3px}
.dk a{color:var(--dk-accent);text-decoration:underline;text-underline-offset:2px}
.dk a:focus-visible{outline:2px solid var(--dk-accent);outline-offset:2px;border-radius:3px}
.dk-foot{margin-top:16px;text-align:center;color:var(--dk-muted);font-size:.86rem}
@media (max-width:575px){.dk-plan-grid{grid-template-columns:1fr}}
@media (max-width:420px){.dk{padding:26px 20px 22px}}
@media (prefers-reduced-motion:reduce){.dk-input,.dk-group,.dk-plan,.dk-radio,.dk-box,.dk-btn{transition:none}}
JavaScript
// Show/hide password. The button stays hidden without the script; everything else is the browser's own validation.
document.querySelectorAll('[data-pw-toggle]').forEach(function (btn) {
  var input = document.getElementById(btn.getAttribute('aria-controls'));
  btn.hidden = false;
  btn.addEventListener('click', function () {
    var show = input.type === 'password';
    input.type = show ? 'text' : 'password';
    btn.setAttribute('aria-pressed', show ? 'true' : 'false');
  });
});

Bootstrap 5 code

Requires: Bootstrap 5.3.8 CSS

HTML
<div class="demo-grid">
<div><span class="lbl">Developer sign-up</span>
<form class="card dk" data-bs-theme="dark" action="#" method="post" aria-labelledby="rl-title">
  <div class="dk-brand"><span class="dk-mark"><svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M4 17l6-6-6-6M12 19h8"/></svg></span>Relay</div>
  <h2 class="dk-title" id="rl-title">Create your Relay account</h2>
  <p class="dk-sub">A preview URL for every branch you push. Fields marked <span class="dk-req">*</span> are required.</p>
  <div class="mb-3">
    <label class="form-label" for="rl-email">Email <span class="dk-req" aria-hidden="true">*</span></label>
    <input class="form-control" id="rl-email" name="email" type="email" autocomplete="email" required>
  </div>
  <div class="mb-3">
    <label class="form-label" for="rl-user">Username <span class="dk-req" aria-hidden="true">*</span></label>
    <div class="input-group">
      <span class="input-group-text" aria-hidden="true">relay.dev/</span>
      <input class="form-control" id="rl-user" name="username" type="text" autocomplete="username" required pattern="[a-z0-9\-]{3,24}" aria-describedby="rl-user-hint">
    </div>
    <p class="form-text" id="rl-user-hint">Your projects live at relay.dev/username. 3 to 24 lowercase letters, numbers or hyphens.</p>
  </div>
  <div class="mb-3">
    <label class="form-label" for="rl-pw">Password <span class="dk-req" aria-hidden="true">*</span></label>
    <div class="input-group">
      <input class="form-control" id="rl-pw" name="password" type="password" autocomplete="new-password" minlength="10" required aria-describedby="rl-pw-hint">
      <button class="btn dk-eye" type="button" aria-controls="rl-pw" aria-pressed="false" aria-label="Show password" data-pw-toggle hidden>
        <svg class="dk-show" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M2 12s3.6-7 10-7 10 7 10 7-3.6 7-10 7S2 12 2 12z"/><circle cx="12" cy="12" r="3"/></svg>
        <svg class="dk-hide" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M3 3l18 18M10.6 5.1A10.7 10.7 0 0 1 12 5c6.4 0 10 7 10 7a17.6 17.6 0 0 1-2.9 3.9M6.6 6.6C3.8 8.4 2 12 2 12s3.6 7 10 7a10 10 0 0 0 5.4-1.6M9.9 9.9a3 3 0 0 0 4.2 4.2"/></svg>
      </button>
    </div>
    <p class="form-text" id="rl-pw-hint">At least 10 characters.</p>
  </div>
  <fieldset class="dk-plans">
    <legend>Plan</legend>
    <div class="row g-2">
      <div class="col-sm-6"><label class="dk-plan"><input class="form-check-input" type="radio" name="plan" value="hobby" checked><span><b>Hobby</b><small>Free, 3 projects</small></span></label></div>
      <div class="col-sm-6"><label class="dk-plan"><input class="form-check-input" type="radio" name="plan" value="team"><span><b>Team</b><small>$12 a seat a month</small></span></label></div>
    </div>
  </fieldset>
  <button class="btn dk-btn w-100" type="submit">Create account</button>
  <p class="dk-foot">Already have an account? <a href="#">Sign in</a></p>
</form>
</div>
<div><span class="lbl">Invite-only registration</span>
<form class="card dk dk--violet" data-bs-theme="dark" action="#" method="post" aria-labelledby="nj-title">
  <div class="dk-brand"><span class="dk-mark"><svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M20 14.5A8 8 0 1 1 9.5 4a6.5 6.5 0 0 0 10.5 10.5z"/></svg></span>Nightjar</div>
  <h2 class="dk-title" id="nj-title">Join the observing circle</h2>
  <p class="dk-sub">A members-only forum for amateur astronomers. Every field is required.</p>
  <div class="mb-3">
    <label class="form-label" for="nj-code">Invite code</label>
    <input class="form-control dk-code" id="nj-code" name="invite" type="text" autocomplete="off" spellcheck="false" required pattern="[A-Za-z0-9]{4}-[A-Za-z0-9]{4}" maxlength="9" aria-describedby="nj-code-hint">
    <p class="form-text" id="nj-code-hint">Eight letters and numbers from your invite email, like K7QD-2MXF.</p>
  </div>
  <div class="mb-3">
    <label class="form-label" for="nj-nick">Display name</label>
    <input class="form-control" id="nj-nick" name="nickname" type="text" autocomplete="nickname" required>
  </div>
  <div class="mb-3">
    <label class="form-label" for="nj-email">Email</label>
    <input class="form-control" id="nj-email" name="email" type="email" autocomplete="email" required>
  </div>
  <div class="mb-3">
    <label class="form-label" for="nj-pw">Password</label>
    <div class="input-group">
      <input class="form-control" id="nj-pw" name="password" type="password" autocomplete="new-password" minlength="10" required aria-describedby="nj-pw-hint">
      <button class="btn dk-eye" type="button" aria-controls="nj-pw" aria-pressed="false" aria-label="Show password" data-pw-toggle hidden>
        <svg class="dk-show" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M2 12s3.6-7 10-7 10 7 10 7-3.6 7-10 7S2 12 2 12z"/><circle cx="12" cy="12" r="3"/></svg>
        <svg class="dk-hide" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M3 3l18 18M10.6 5.1A10.7 10.7 0 0 1 12 5c6.4 0 10 7 10 7a17.6 17.6 0 0 1-2.9 3.9M6.6 6.6C3.8 8.4 2 12 2 12s3.6 7 10 7a10 10 0 0 0 5.4-1.6M9.9 9.9a3 3 0 0 0 4.2 4.2"/></svg>
      </button>
    </div>
    <p class="form-text" id="nj-pw-hint">At least 10 characters.</p>
  </div>
  <div class="form-check"><input class="form-check-input" id="nj-dir" type="checkbox" name="directory" checked><label class="form-check-label" for="nj-dir">List me in the member directory (you can change this later)</label></div>
  <button class="btn dk-btn w-100" type="submit">Accept invite</button>
  <p class="dk-foot">No invite? <a href="#">Ask to join the waitlist</a></p>
</form>
</div>
</div>
CSS
/* Bootstrap's dark colour mode (data-bs-theme="dark") on a .card, with .input-group, .input-group-text,
   .form-control, .form-check-input and .btn retuned through Bootstrap's CSS variables. Borders keep 3:1 against
   the card, text stays above 4.5:1. The eye button only appears once the script runs. */
.dk{--dk-bg:#111722;--dk-field:#0b1019;--dk-ink:#e8edf5;--dk-muted:#9aa4b5;--dk-line:#6b7588;--dk-rule:#232c3b;--dk-accent:#a3e635;--dk-accent-ink:#0b1019;
  --dk-ring:rgba(163,230,53,.28);--dk-error:#f87171;
  --bs-card-bg:var(--dk-bg);--bs-card-border-color:var(--dk-rule);--bs-card-border-radius:20px;--bs-body-bg:var(--dk-field);--bs-body-color:var(--dk-ink);
  --bs-border-color:var(--dk-line);--bs-border-radius:10px;--bs-secondary-color:var(--dk-muted);--bs-tertiary-bg:var(--dk-field);
  --bs-link-color-rgb:163,230,53;--bs-link-hover-color-rgb:190,242,100;
  padding:32px 30px 28px;color:var(--dk-ink);font-size:.92rem;line-height:1.45;box-shadow:0 24px 50px -24px rgba(0,0,0,.7),inset 0 1px 0 rgba(255,255,255,.04)}
.dk--violet{--dk-accent:#a78bfa;--dk-ring:rgba(167,139,250,.3);--bs-link-color-rgb:167,139,250;--bs-link-hover-color-rgb:196,181,253}
.dk p,.dk h2{margin:0}
.dk .dk-brand{display:flex;align-items:center;gap:10px;font-weight:700;margin-bottom:20px}
.dk .dk-mark{width:32px;height:32px;border-radius:9px;background:var(--dk-accent);color:var(--dk-accent-ink);display:grid;place-items:center}
.dk .dk-title{font-size:1.4rem;font-weight:750;letter-spacing:-.02em;line-height:1.2}
.dk .dk-sub{color:var(--dk-muted);margin:6px 0 20px}
.dk .dk-req{color:var(--dk-accent);font-weight:700}
.dk .form-label{display:block;font-size:.84rem;font-weight:600;margin-bottom:6px}
.dk .form-control{font-size:inherit;line-height:inherit;color:var(--dk-ink);background-color:var(--dk-field);padding:11px 13px;transition:border-color .15s,box-shadow .15s}
.dk .form-control:focus{border-color:var(--dk-accent);box-shadow:0 0 0 3px var(--dk-ring)}
.dk .form-control:user-invalid{border-color:var(--dk-error)}
.dk .form-text{font-size:.8rem;color:var(--dk-muted);margin-top:6px}
/* .input-group drawn as one bordered field */
.dk .input-group{background:var(--dk-field);border:1px solid var(--dk-line);border-radius:10px;transition:border-color .15s,box-shadow .15s}
.dk .input-group:focus-within{border-color:var(--dk-accent);box-shadow:0 0 0 3px var(--dk-ring)}
.dk .input-group:has(:user-invalid){border-color:var(--dk-error)}
.dk .input-group .form-control,.dk .input-group .form-control:focus{border:0;box-shadow:none;background:transparent}
.dk .input-group-text{border:0;background:none;padding:0 0 0 13px;color:var(--dk-muted);font-family:ui-monospace,SFMono-Regular,Menlo,monospace;font-size:.84rem}
.dk .input-group-text+.form-control{padding-left:2px}
.dk .dk-eye{width:46px;padding:0;border:0;color:var(--dk-muted);border-radius:0 10px 10px 0!important;display:grid;place-items:center}
.dk .dk-eye:hover{color:var(--dk-ink)}
.dk .dk-eye:focus-visible{box-shadow:none;outline:2px solid var(--dk-accent);outline-offset:-5px;border-radius:8px!important}
.dk .dk-eye[hidden],.dk .dk-eye[aria-pressed="true"] .dk-show,.dk .dk-eye[aria-pressed="false"] .dk-hide{display:none}
/* plan picker */
.dk .dk-plans{margin:4px 0 18px;min-width:0}
.dk .dk-plans legend{float:none;padding:0;font-size:.84rem;font-weight:600;line-height:1.45;margin-bottom:8px}
.dk .dk-plan{height:100%;display:flex;gap:10px;align-items:flex-start;padding:12px;border:1px solid var(--dk-line);border-radius:12px;cursor:pointer;transition:border-color .15s,background-color .15s}
.dk .dk-plan:has(:checked){border-color:var(--dk-accent);background:rgba(163,230,53,.07)}
.dk .dk-plan b{display:block;font-weight:650}
.dk .dk-plan small{font-size:.78rem;color:var(--dk-muted)}
.dk .form-check-input{flex:none;width:18px;height:18px;margin:1px 0 0;border:1.5px solid var(--dk-line);background-color:var(--dk-field);cursor:pointer;
  --bs-form-check-bg-image:none;transition:border-color .15s,background-color .15s}
.dk .form-check-input:focus{box-shadow:none;border-color:var(--dk-line)}
.dk .form-check-input:focus-visible{outline:2px solid var(--dk-accent);outline-offset:2px}
.dk .form-check-input[type=radio]:checked{border:5px solid var(--dk-accent);background-color:var(--dk-accent-ink)}
.dk .form-check-input[type=checkbox]{border-radius:5px}
.dk .form-check-input[type=checkbox]:checked{background-color:var(--dk-accent);border-color:var(--dk-accent);background-size:12px;
  --bs-form-check-bg-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3E%3Cpath d='M3.5 8.5l3 3 6-7' fill='none' stroke='%230b1019' stroke-width='2.2' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E")}
.dk .form-check{display:flex;gap:10px;align-items:flex-start;padding:0;margin:2px 0 18px;min-height:0;font-size:.86rem}
.dk .form-check .form-check-input{float:none}
.dk .form-check-label{cursor:pointer}
.dk .dk-code{font-family:ui-monospace,SFMono-Regular,Menlo,monospace;letter-spacing:.18em;text-transform:uppercase}
.dk .dk-btn{--bs-btn-color:var(--dk-accent-ink);--bs-btn-bg:var(--dk-accent);--bs-btn-border-color:var(--dk-accent);--bs-btn-hover-color:var(--dk-accent-ink);
  --bs-btn-hover-bg:var(--dk-accent);--bs-btn-hover-border-color:var(--dk-accent);--bs-btn-active-color:var(--dk-accent-ink);--bs-btn-active-bg:var(--dk-accent);
  --bs-btn-active-border-color:var(--dk-accent);--bs-btn-focus-box-shadow:none;--bs-btn-font-weight:700;--bs-btn-font-size:.92rem;--bs-btn-padding-y:11px;
  --bs-btn-border-radius:10px;line-height:1.45;box-shadow:0 0 0 1px rgba(255,255,255,.06),0 8px 24px -8px var(--dk-ring);transition:filter .15s,box-shadow .15s}
.dk .dk-btn:hover{filter:brightness(1.08);box-shadow:0 0 0 1px rgba(255,255,255,.08),0 10px 30px -6px var(--dk-ring)}
.dk .dk-btn:focus-visible{outline:2px solid var(--dk-accent);outline-offset:3px}
.dk a{text-underline-offset:2px}
.dk a:focus-visible{outline:2px solid var(--dk-accent);outline-offset:2px;border-radius:3px}
.dk .dk-foot{margin-top:16px;text-align:center;color:var(--dk-muted);font-size:.86rem}
.card.dk{display:block} /* plain block flow, so vertical margins match the CSS version */
@media (max-width:420px){.dk{padding:26px 20px 22px}}
@media (prefers-reduced-motion:reduce){.dk .form-control,.dk .input-group,.dk .dk-plan,.dk .form-check-input,.dk .btn{transition:none}}
JavaScript
// Show/hide password. The button stays hidden without the script; everything else is the browser's own validation.
document.querySelectorAll('[data-pw-toggle]').forEach(function (btn) {
  var input = document.getElementById(btn.getAttribute('aria-controls'));
  btn.hidden = false;
  btn.addEventListener('click', function () {
    var show = input.type === 'password';
    input.type = show ? 'text' : 'password';
    btn.setAttribute('aria-pressed', show ? 'true' : 'false');
  });
});

Tailwind 4 code

Requires: Tailwind CSS 4

HTML
<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-[#98a2b3] uppercase">Developer sign-up</span>
<form class="rounded-[20px] border border-dk-rule bg-dk-bg px-[30px] pt-8 pb-7 text-[.92rem] leading-[1.45] text-dk-ink shadow-[0_24px_50px_-24px_rgba(0,0,0,.7),inset_0_1px_0_rgba(255,255,255,.04)] max-[420px]:px-5 max-[420px]:pt-[26px] max-[420px]:pb-[22px] [--dk-accent:#a3e635] [--dk-ring:rgba(163,230,53,.28)]" action="#" method="post" aria-labelledby="rl-title">
  <div class="mb-5 flex items-center gap-2.5 font-bold"><span class="grid size-8 place-items-center rounded-[9px] bg-(--dk-accent) text-dk-field"><svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M4 17l6-6-6-6M12 19h8"/></svg></span>Relay</div>
  <h2 class="text-[1.4rem] leading-[1.2] font-[750] tracking-[-.02em]" id="rl-title">Create your Relay account</h2>
  <p class="mt-1.5 mb-5 text-dk-muted">A preview URL for every branch you push. Fields marked <span class="font-bold text-(--dk-accent)">*</span> are required.</p>
  <div class="mb-4 min-w-0">
    <label class="mb-1.5 block text-[.84rem] font-semibold" for="rl-email">Email <span class="font-bold text-(--dk-accent)" aria-hidden="true">*</span></label>
    <input class="block w-full min-w-0 rounded-[10px] border border-dk-line bg-dk-field px-[13px] py-[11px] text-dk-ink transition-[border-color,box-shadow] duration-150 focus:border-(--dk-accent) focus:shadow-[0_0_0_3px_var(--dk-ring)] focus:outline-none user-invalid:border-dk-error motion-reduce:transition-none" id="rl-email" name="email" type="email" autocomplete="email" required>
  </div>
  <div class="mb-4 min-w-0">
    <label class="mb-1.5 block text-[.84rem] font-semibold" for="rl-user">Username <span class="font-bold text-(--dk-accent)" aria-hidden="true">*</span></label>
    <div class="flex rounded-[10px] border border-dk-line bg-dk-field transition-[border-color,box-shadow] duration-150 focus-within:border-(--dk-accent) focus-within:shadow-[0_0_0_3px_var(--dk-ring)] has-user-invalid:border-dk-error motion-reduce:transition-none">
      <span class="flex items-center pl-[13px] text-[.84rem] text-dk-muted font-[ui-monospace,SFMono-Regular,Menlo,monospace]" aria-hidden="true">relay.dev/</span>
      <input class="min-w-0 flex-1 rounded-[10px] bg-transparent py-[11px] pr-[13px] text-dk-ink focus:outline-none pl-0.5" id="rl-user" name="username" type="text" autocomplete="username" required pattern="[a-z0-9\-]{3,24}" aria-describedby="rl-user-hint">
    </div>
    <p class="mt-1.5 text-[.8rem] text-dk-muted" id="rl-user-hint">Your projects live at relay.dev/username. 3 to 24 lowercase letters, numbers or hyphens.</p>
  </div>
  <div class="mb-4 min-w-0">
    <label class="mb-1.5 block text-[.84rem] font-semibold" for="rl-pw">Password <span class="font-bold text-(--dk-accent)" aria-hidden="true">*</span></label>
    <div class="flex rounded-[10px] border border-dk-line bg-dk-field transition-[border-color,box-shadow] duration-150 focus-within:border-(--dk-accent) focus-within:shadow-[0_0_0_3px_var(--dk-ring)] has-user-invalid:border-dk-error motion-reduce:transition-none">
      <input class="min-w-0 flex-1 rounded-[10px] bg-transparent py-[11px] pr-[13px] text-dk-ink focus:outline-none pl-[13px]" id="rl-pw" name="password" type="password" autocomplete="new-password" minlength="10" required aria-describedby="rl-pw-hint">
      <button class="group grid w-[46px] flex-none cursor-pointer place-items-center rounded-r-[10px] text-dk-muted hover:text-dk-ink focus-visible:rounded-lg focus-visible:outline-2 focus-visible:-outline-offset-5 focus-visible:outline-(--dk-accent)" type="button" aria-controls="rl-pw" aria-pressed="false" aria-label="Show password" data-pw-toggle hidden>
        <svg class="group-aria-pressed:hidden" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M2 12s3.6-7 10-7 10 7 10 7-3.6 7-10 7S2 12 2 12z"/><circle cx="12" cy="12" r="3"/></svg>
        <svg class="hidden group-aria-pressed:block" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M3 3l18 18M10.6 5.1A10.7 10.7 0 0 1 12 5c6.4 0 10 7 10 7a17.6 17.6 0 0 1-2.9 3.9M6.6 6.6C3.8 8.4 2 12 2 12s3.6 7 10 7a10 10 0 0 0 5.4-1.6M9.9 9.9a3 3 0 0 0 4.2 4.2"/></svg>
      </button>
    </div>
    <p class="mt-1.5 text-[.8rem] text-dk-muted" id="rl-pw-hint">At least 10 characters.</p>
  </div>
  <fieldset class="mt-1 mb-[18px] min-w-0">
    <legend class="mb-2 text-[.84rem] font-semibold">Plan</legend>
    <div class="grid grid-cols-2 gap-2.5 max-sm:grid-cols-1">
      <label class="flex cursor-pointer items-start gap-2.5 rounded-xl border border-dk-line p-3 transition-[background-color,border-color,color] duration-150 has-checked:border-(--dk-accent) has-checked:bg-[rgba(163,230,53,.07)] motion-reduce:transition-none"><input class="mt-px size-[18px] flex-none cursor-pointer appearance-none rounded-full border-[1.5px] border-dk-line bg-dk-field transition-[background-color,border-color,color] duration-150 checked:border-[5px] checked:border-(--dk-accent) focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-(--dk-accent) motion-reduce:transition-none" type="radio" name="plan" value="hobby" checked><span><b class="block font-[650]">Hobby</b><small class="text-[.78rem] text-dk-muted">Free, 3 projects</small></span></label>
      <label class="flex cursor-pointer items-start gap-2.5 rounded-xl border border-dk-line p-3 transition-[background-color,border-color,color] duration-150 has-checked:border-(--dk-accent) has-checked:bg-[rgba(163,230,53,.07)] motion-reduce:transition-none"><input class="mt-px size-[18px] flex-none cursor-pointer appearance-none rounded-full border-[1.5px] border-dk-line bg-dk-field transition-[background-color,border-color,color] duration-150 checked:border-[5px] checked:border-(--dk-accent) focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-(--dk-accent) motion-reduce:transition-none" type="radio" name="plan" value="team"><span><b class="block font-[650]">Team</b><small class="text-[.78rem] text-dk-muted">$12 a seat a month</small></span></label>
    </div>
  </fieldset>
  <button class="block w-full cursor-pointer rounded-[10px] bg-(--dk-accent) px-4 py-3 font-bold text-dk-field shadow-[0_0_0_1px_rgba(255,255,255,.06),0_8px_24px_-8px_var(--dk-ring)] transition-[filter,box-shadow] duration-150 hover:shadow-[0_0_0_1px_rgba(255,255,255,.08),0_10px_30px_-6px_var(--dk-ring)] hover:brightness-108 focus-visible:outline-2 focus-visible:outline-offset-3 focus-visible:outline-(--dk-accent) motion-reduce:transition-none" type="submit">Create account</button>
  <p class="mt-4 text-center text-[.86rem] text-dk-muted">Already have an account? <a class="text-(--dk-accent) underline underline-offset-2 focus-visible:rounded-[3px] focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-(--dk-accent)" href="#">Sign in</a></p>
</form>
</div>
<div><span class="mb-4 block text-[.72rem] tracking-[.12em] text-[#98a2b3] uppercase">Invite-only registration</span>
<form class="rounded-[20px] border border-dk-rule bg-dk-bg px-[30px] pt-8 pb-7 text-[.92rem] leading-[1.45] text-dk-ink shadow-[0_24px_50px_-24px_rgba(0,0,0,.7),inset_0_1px_0_rgba(255,255,255,.04)] max-[420px]:px-5 max-[420px]:pt-[26px] max-[420px]:pb-[22px] [--dk-accent:#a78bfa] [--dk-ring:rgba(167,139,250,.3)]" action="#" method="post" aria-labelledby="nj-title">
  <div class="mb-5 flex items-center gap-2.5 font-bold"><span class="grid size-8 place-items-center rounded-[9px] bg-(--dk-accent) text-dk-field"><svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M20 14.5A8 8 0 1 1 9.5 4a6.5 6.5 0 0 0 10.5 10.5z"/></svg></span>Nightjar</div>
  <h2 class="text-[1.4rem] leading-[1.2] font-[750] tracking-[-.02em]" id="nj-title">Join the observing circle</h2>
  <p class="mt-1.5 mb-5 text-dk-muted">A members-only forum for amateur astronomers. Every field is required.</p>
  <div class="mb-4 min-w-0">
    <label class="mb-1.5 block text-[.84rem] font-semibold" for="nj-code">Invite code</label>
    <input class="block w-full min-w-0 rounded-[10px] border border-dk-line bg-dk-field px-[13px] py-[11px] text-dk-ink transition-[border-color,box-shadow] duration-150 focus:border-(--dk-accent) focus:shadow-[0_0_0_3px_var(--dk-ring)] focus:outline-none user-invalid:border-dk-error motion-reduce:transition-none tracking-[.18em] uppercase font-[ui-monospace,SFMono-Regular,Menlo,monospace]" id="nj-code" name="invite" type="text" autocomplete="off" spellcheck="false" required pattern="[A-Za-z0-9]{4}-[A-Za-z0-9]{4}" maxlength="9" aria-describedby="nj-code-hint">
    <p class="mt-1.5 text-[.8rem] text-dk-muted" id="nj-code-hint">Eight letters and numbers from your invite email, like K7QD-2MXF.</p>
  </div>
  <div class="mb-4 min-w-0">
    <label class="mb-1.5 block text-[.84rem] font-semibold" for="nj-nick">Display name</label>
    <input class="block w-full min-w-0 rounded-[10px] border border-dk-line bg-dk-field px-[13px] py-[11px] text-dk-ink transition-[border-color,box-shadow] duration-150 focus:border-(--dk-accent) focus:shadow-[0_0_0_3px_var(--dk-ring)] focus:outline-none user-invalid:border-dk-error motion-reduce:transition-none" id="nj-nick" name="nickname" type="text" autocomplete="nickname" required>
  </div>
  <div class="mb-4 min-w-0">
    <label class="mb-1.5 block text-[.84rem] font-semibold" for="nj-email">Email</label>
    <input class="block w-full min-w-0 rounded-[10px] border border-dk-line bg-dk-field px-[13px] py-[11px] text-dk-ink transition-[border-color,box-shadow] duration-150 focus:border-(--dk-accent) focus:shadow-[0_0_0_3px_var(--dk-ring)] focus:outline-none user-invalid:border-dk-error motion-reduce:transition-none" id="nj-email" name="email" type="email" autocomplete="email" required>
  </div>
  <div class="mb-4 min-w-0">
    <label class="mb-1.5 block text-[.84rem] font-semibold" for="nj-pw">Password</label>
    <div class="flex rounded-[10px] border border-dk-line bg-dk-field transition-[border-color,box-shadow] duration-150 focus-within:border-(--dk-accent) focus-within:shadow-[0_0_0_3px_var(--dk-ring)] has-user-invalid:border-dk-error motion-reduce:transition-none">
      <input class="min-w-0 flex-1 rounded-[10px] bg-transparent py-[11px] pr-[13px] text-dk-ink focus:outline-none pl-[13px]" id="nj-pw" name="password" type="password" autocomplete="new-password" minlength="10" required aria-describedby="nj-pw-hint">
      <button class="group grid w-[46px] flex-none cursor-pointer place-items-center rounded-r-[10px] text-dk-muted hover:text-dk-ink focus-visible:rounded-lg focus-visible:outline-2 focus-visible:-outline-offset-5 focus-visible:outline-(--dk-accent)" type="button" aria-controls="nj-pw" aria-pressed="false" aria-label="Show password" data-pw-toggle hidden>
        <svg class="group-aria-pressed:hidden" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M2 12s3.6-7 10-7 10 7 10 7-3.6 7-10 7S2 12 2 12z"/><circle cx="12" cy="12" r="3"/></svg>
        <svg class="hidden group-aria-pressed:block" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M3 3l18 18M10.6 5.1A10.7 10.7 0 0 1 12 5c6.4 0 10 7 10 7a17.6 17.6 0 0 1-2.9 3.9M6.6 6.6C3.8 8.4 2 12 2 12s3.6 7 10 7a10 10 0 0 0 5.4-1.6M9.9 9.9a3 3 0 0 0 4.2 4.2"/></svg>
      </button>
    </div>
    <p class="mt-1.5 text-[.8rem] text-dk-muted" id="nj-pw-hint">At least 10 characters.</p>
  </div>
  <label class="mt-0.5 mb-[18px] flex cursor-pointer items-start gap-2.5 text-[.86rem]"><input class="mt-px size-[18px] flex-none cursor-pointer appearance-none rounded-[5px] border-[1.5px] border-dk-line bg-dk-field bg-[length:12px_12px] bg-center bg-no-repeat transition-[background-color,border-color,color] duration-150 checked:border-(--dk-accent) checked:bg-(--dk-accent) checked:dk-tick focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-(--dk-accent) motion-reduce:transition-none" type="checkbox" name="directory" checked><span>List me in the member directory (you can change this later)</span></label>
  <button class="block w-full cursor-pointer rounded-[10px] bg-(--dk-accent) px-4 py-3 font-bold text-dk-field shadow-[0_0_0_1px_rgba(255,255,255,.06),0_8px_24px_-8px_var(--dk-ring)] transition-[filter,box-shadow] duration-150 hover:shadow-[0_0_0_1px_rgba(255,255,255,.08),0_10px_30px_-6px_var(--dk-ring)] hover:brightness-108 focus-visible:outline-2 focus-visible:outline-offset-3 focus-visible:outline-(--dk-accent) motion-reduce:transition-none" type="submit">Accept invite</button>
  <p class="mt-4 text-center text-[.86rem] text-dk-muted">No invite? <a class="text-(--dk-accent) underline underline-offset-2 focus-visible:rounded-[3px] focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-(--dk-accent)" href="#">Ask to join the waitlist</a></p>
</form>
</div>
</div>
CSS
@theme {
  --color-dk-bg: #111722;
  --color-dk-field: #0b1019;
  --color-dk-ink: #e8edf5;
  --color-dk-muted: #9aa4b5;
  --color-dk-line: #6b7588;
  --color-dk-rule: #232c3b;
  --color-dk-error: #f87171;
}
/* dark tick for the checked checkbox */
@utility dk-tick {
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3E%3Cpath d='M3.5 8.5l3 3 6-7' fill='none' stroke='%230b1019' stroke-width='2.2' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");
}
JavaScript
// Show/hide password. The button stays hidden without the script; everything else is the browser's own validation.
document.querySelectorAll('[data-pw-toggle]').forEach(function (btn) {
  var input = document.getElementById(btn.getAttribute('aria-controls'));
  btn.hidden = false;
  btn.addEventListener('click', function () {
    var show = input.type === 'password';
    input.type = show ? 'text' : 'password';
    btn.setAttribute('aria-pressed', show ? 'true' : 'false');
  });
});

About this set

Two registration forms for dark interfaces such as developer tools and members’ communities. Developer sign-up has a lime accent: email, a username field with a fixed relay.dev/ prefix drawn inside the same box and a pattern that allows lowercase letters, numbers and hyphens, a password with a show and hide button, and a plan picker of two radio cards for a free and a paid tier. Invite-only registration has a violet accent and starts with an invite code field in spaced monospace capitals that must match four characters, a hyphen and four more, then a display name, email, password and a member directory checkbox. Use the first for SaaS and developer products, the second for private communities, betas and anything behind an invite. Dark forms fail when borders vanish and grey text sinks, so field borders are lightened to stay at 3:1 against the card, muted text stays above 4.5:1, and the accent is kept for focus rings, checked states and the main button, which carries a soft glow. The Bootstrap version switches the card into Bootstrap’s own dark colour mode with data-bs-theme=”dark”. JavaScript is used only for the show password button.

What’s included

  • Prefixed username field built as one bordered group
  • Invite code field with a pattern and monospace letter spacing
  • Plan picker radio cards highlighted with :has(:checked)
  • Borders and muted text tuned for contrast on a dark card
  • Bootstrap version uses data-bs-theme="dark", .input-group-text and .form-check-input

Accessibility

Every field has a visible label and an autocomplete value (email, username, nickname, new-password); the invite code turns autocomplete and spellcheck off. Hints such as the username rules are linked with aria-describedby, and the decorative prefix is aria-hidden because the hint spells it out. The plan choice is a fieldset with a legend, the password toggle uses aria-pressed, focus rings use the accent colour, and transitions switch off under prefers-reduced-motion.

Customise it

Change --dk-accent and --dk-ring on .dk for the accent (.dk--violet is the second palette) and --dk-bg, --dk-field and --dk-line for the surfaces. In Bootstrap the same variables feed --bs-card-bg and --bs-border-color; in Tailwind edit the dk-* theme colours and the [--dk-accent:…] properties.