No.398 · Authentication· New
Recovery Kit
Backup codes handled properly: ten single-use codes in a mono grid with the used ones struck out, copy, download and print, and a new set on demand — the old codes visibly strike through before the fresh ones settle in. Continue only unlocks once you've said they're saved.
The prompt
Written for the variant you picked above: Night
Build a recovery-codes panel. Props: codes [{code, used}], account, issued (words), onRegenerate() → Promise of new codes, onContinue and theme. Codes look like 'k7m2-9fqa': two groups of four from an alphabet without look-alikes (no 0, o, 1, l or i). A card (560px max, 22px corners): a key in a rounded square, 'Save your recovery codes', and a line with how many are left and when they were issued ('8 of 10 left · issued 12 March 2026'). Then the codes in a recessed well, two columns, each with a muted two-digit index and the code in mono (select-all on click); used codes are muted with a line through them (a pseudo-element scaled from 0 to 1) and a small 'USED' label. Actions in one row: Copy (writes a text file's worth to the clipboard and swaps to a tick and 'Copied' for 2s), Download (a .txt named after the account, built from a Blob), Print (a small window with the codes in a <pre>, or a message if it's blocked), and on the right 'New codes', which swaps in place for 'Old codes stop working.' Keep these / Make new codes. Making new codes strikes through every current code in turn (40ms apart) while it waits, then the fresh list fades and un-blurs in, staggered, and the issued date reads 'just now'. A failure leaves the old codes in place and says they still work. At the bottom a custom checkbox row 'I've saved these codes somewhere safe' (a real checkbox under a drawn box that fills green with a tick) unlocks a full-width Continue; making new codes clears the tick. Every outcome is announced in a status region. Two themes; one column below 440px; reduced motion removes the strikes and the stagger. Selected variant — Night (night): Palette for this theme (Night): --rk-accent #f1f2f5; --rk-card #15161b; --rk-danger #ff8475; --rk-good #6fe0a5; --rk-ink #f1f2f5; --rk-line rgba(255, 255, 255, 0.09); --rk-muted #9da1ab; --rk-on-accent #0e0f13; --rk-well #0e0f13. Treat these as the root colour tokens, one value per role, and name them to suit your code. Select it with the theme option set to "night". Keep every dimension, spacing value, state and motion from the brief unchanged, and keep text at 4.5:1 contrast or better on these surfaces. This selection takes precedence over references to other themes or options in the general brief. Implement this selected appearance; do not add a variant picker or alternative appearances unless requested. Implementation requirements: Use React and TypeScript. Keep the component self-contained, with uniquely scoped CSS and no animation libraries. Include required imports, styles and font setup in the result. Interaction: Copy, download or print the codes; make a new set (confirm first); tick that you've saved them to continue. Motion: Lines strike through old codes one by one over about 600ms; new codes fade and un-blur in, staggered by 35ms; Copied shows for 2s. Reduced motion removes the motion. Accessibility: A section labelled by its heading; the codes are an ordered list with real text; used codes say so in words. Actions are real buttons; the confirm is a labelled group with focus on the destructive choice. The checkbox is a real input. Outcomes are announced in a status region. Responsive behavior: Two columns of codes, one below 440px; actions wrap. Touch: Nothing depends on hover; codes can be selected with a tap. Preserve keyboard access, visible focus and reduced-motion behavior. Keep fictional demo data and simulated service calls in a separate usage example; expose callbacks for real actions and recover from rejected requests. Keep usage-example links inside the demo: use local buttons or prevent navigation. Demonstration links must not navigate to Vitrine routes or open other pages; preserve real URL support in the reusable component itself. Verify the result at narrow and wide viewport sizes, with keyboard input and reduced motion enabled.
Notes
- Interaction
- Copy, download or print the codes; make a new set (confirm first); tick that you've saved them to continue.
- Motion
- Lines strike through old codes one by one over about 600ms; new codes fade and un-blur in, staggered by 35ms; Copied shows for 2s. Reduced motion removes the motion.
- Accessibility
- A section labelled by its heading; the codes are an ordered list with real text; used codes say so in words. Actions are real buttons; the confirm is a labelled group with focus on the destructive choice. The checkbox is a real input. Outcomes are announced in a status region.
- Responsive
- Two columns of codes, one below 440px; actions wrap.
- On touch
- Nothing depends on hover; codes can be selected with a tap.