Two factor and sign in
Recovery codes
One time recovery codes in a two column grid with copy all, download as a .txt file and print. Used codes are struck through, and Continue stays disabled until "I saved these codes" is checked. Needs monsoon.js for the actions.
Needs monsoon.js. The styles work on their own, and the behavior comes from the optional interactive layer: add <script src="https://cdn.jsdelivr.net/npm/monsooncss/dist/monsoon.js" defer></script> or import 'monsooncss/js'. See the interactive layer.
Example
<div class="auth-card auth-card-wide">
<header class="auth-header auth-header-start">
<span class="auth-icon auth-icon-warning"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.75" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><rect x="5" y="10.5" width="14" height="10" rx="2.5"/><path d="M8 10.5V8a4 4 0 0 1 8 0v2.5"/><path d="M12 14.5v2"/></svg></span>
<h2 class="auth-title">Save your recovery codes</h2>
<p class="auth-description">If you lose your phone, each code lets you sign in once. Store them in a password manager or print them.</p>
</header>
<div class="backup-codes" data-m-auth-codes data-m-auth-codes-filename="example-recovery-codes.txt" data-m-auth-codes-title="Example recovery codes">
<div class="backup-codes-header">
<p class="backup-codes-title">Recovery codes</p>
<span class="backup-codes-count">8 of 10 unused</span>
</div>
<ol class="backup-codes-grid">
<li class="backup-code"><code>7KQ2-M9XA</code></li>
<li class="backup-code"><code>P4WD-38NZ</code></li>
<li class="backup-code backup-code-used"><code>H6TC-QV2R</code><span class="sr-only"> (used)</span></li>
<li class="backup-code"><code>Z9LE-5MKB</code></li>
<li class="backup-code"><code>B3YU-7FJS</code></li>
<li class="backup-code"><code>R8NX-2GHD</code></li>
<li class="backup-code backup-code-used"><code>V5CW-K4PT</code><span class="sr-only"> (used)</span></li>
<li class="backup-code"><code>E2MJ-9QLY</code></li>
<li class="backup-code"><code>T7AF-6RNU</code></li>
<li class="backup-code"><code>G4SB-X8KE</code></li>
</ol>
<div class="backup-codes-actions">
<button type="button" class="btn btn-sm btn-outline btn-neutral" data-codes-action="copy"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.75" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><rect x="9" y="9" width="11.5" height="11.5" rx="2"/><path d="M5.5 15H5a1.5 1.5 0 0 1-1.5-1.5V5A1.5 1.5 0 0 1 5 3.5h8.5A1.5 1.5 0 0 1 15 5v.5"/></svg> Copy all</button>
<button type="button" class="btn btn-sm btn-outline btn-neutral" data-codes-action="download"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.75" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M12 4v11m0 0-4.5-4.5M12 15l4.5-4.5"/><path d="M5 20h14"/></svg> Download .txt</button>
<button type="button" class="btn btn-sm btn-outline btn-neutral" data-codes-action="print"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.75" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M7 9V3.5h10V9"/><rect x="3" y="9" width="18" height="8" rx="2"/><rect x="7" y="14" width="10" height="7" rx="1"/></svg> Print</button>
</div>
<label class="backup-codes-confirm">
<input type="checkbox" class="checkbox checkbox-sm checkbox-success mt-0.5" data-codes-action="confirm">
<span>I saved these codes somewhere safe</span>
</label>
<button type="button" class="btn btn-primary btn-block" data-codes-action="continue" disabled>Continue</button>
</div>
</div>JavaScript API
Attribute
data-m-auth-codes
Options
| Option | Description |
|---|---|
data-m-auth-codes-filename="example-recovery-codes.txt" | |
data-m-auth-codes-title="Example recovery codes" | |
data-codes-action="copy | download | print | confirm | continue" on the parts |
Methods
| Method | Description |
|---|---|
Monsoon.authCodes(el).codes | |
Monsoon.authCodes(el).copy() | |
Monsoon.authCodes(el).download() | |
Monsoon.authCodes(el).print() |
Events
| Event | Description |
|---|---|
monsoon:auth-codes { action, codes } |
Classes
9 classes. Click a name to copy it. Utilities on the same element always win over component defaults, so any of them can be adjusted with plain utility classes.
| Class | Type | What it does |
|---|---|---|
| Base | Base class of the recovery codes. On a <div> in the example. Sets grid display and gap, and --tone.CSS |
|
| Part | Part of the recovery codes. On a <div> in the example. Sets flex display, alignment and gap.CSS |
|
| Part | Part of the recovery codes. On a <p> in the example. Sets margin, text size and font weight.CSS |
|
| Part | Part of the recovery codes. On a <span> in the example. Sets text size, font weight and text color.CSS |
|
| Part | Part of the recovery codes. On an <ol> in the example. Sets grid display, grid tracks, gap, margin, padding and background.CSS |
|
| Modifier | Modifier, combined with the backup-codes class. On a <li> in the example. Sets flex display, alignment, gap, text size, font weight and text style.CSS |
|
| Modifier | Modifier, combined with the backup-codes class. On a <li> in the example. Sets text color, text style and opacity.CSS |
|
| Part | Part of the recovery codes. On a <div> in the example. Sets flex display, alignment, gap, text color, border and background.CSS |
|
| Part | Part of the recovery codes. On a <label> in the example. Sets flex display, alignment, gap, padding, text size and text style.CSS |
Usage
The styles ship inside the same stylesheet as the utilities, and the behavior comes from the optional monsoon.js script, which enhances any element with a matching data-m attribute, including markup added later.
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/monsooncss">
<script src="https://cdn.jsdelivr.net/npm/monsooncss/dist/monsoon.js" defer></script>
<!-- Recovery codes: start from the base class, then add modifiers -->
<div class="auth-card auth-card-wide">
<header class="auth-header auth-header-start">
<span class="auth-icon auth-icon-warning"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.75" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><rect x="5" y="10.5" width="14" height="10" rx="2.5"/><path d="M8 10.5V8a4 4 0 0 1 8 0v2.5"/><path d="M12 14.5v2"/></svg></span>
<h2 class="auth-title">Save your recovery codes</h2>
<p class="auth-description">If you lose your phone, each code lets you sign in once. Store them in a password manager or print them.</p>
</header>
<div class="backup-codes" data-m-auth-codes data-m-auth-codes-filename="example-recovery-codes.txt" data-m-auth-codes-title="Example recovery codes">
<div class="backup-codes-header">
<p class="backup-codes-title">Recovery codes</p>
<span class="backup-codes-count">8 of 10 unused</span>
</div>
<ol class="backup-codes-grid">
<li class="backup-code"><code>7KQ2-M9XA</code></li>
<li class="backup-code"><code>P4WD-38NZ</code></li>
<!-- the full example is in the Code tab above -->Theme it with --seed on any ancestor, for example style="--seed: #0d9488", and force a scheme with class="dark" or class="light" on a wrapper.
Accessibility
- Give every control a visible
labellinked withfor, or anaria-labelwhen the purpose is obvious from context. Link help and error text witharia-describedby; invalid styles use:user-invalid, so they appear only after the user interacts. - Checkboxes and radios stay real inputs, so they keep native keyboard behavior (Space toggles, arrow keys move within a radio group) and form submission.
- Use
buttonfor actions andafor navigation. Icon only buttons need anaria-label; decorative icons carryaria-hidden="true". - Every interactive part shows a visible focus ring with
:focus-visible, and tone colors pair with-foregroundtokens that keep text at 4.5:1 or better in light and dark mode.