Pattern · Auth and Onboarding

New

Reset Password SwiftUI Block

Account recovery in one block: request a code by email, verify it, choose a new password with rules that tick off, then sign in.

Three steps on one card under a Step 1 of 3 track: the email and Send code, a six-digit code with a Resend countdown and a wrong-code error, and a new password with strong-password AutoFill, show and hide, rules that tick off and a confirm field. Each step runs your closure through working, done and failed, Back returns a step, and a done state ends on Sign in.

  • SwiftUI
  • iOS 17.0+
  • reset-password
Get SwiftPieces Pro

$199 once, every piece included. See how installing works · Sign in

01

What's included

SwiftUI source you own, built on Apple frameworks only.

  • Request, verify and new password on one card with a step track
  • A six-digit code that fills from AutoFill, verifies itself and counts down to Resend
  • A wrong code shows your error and clears the boxes
  • Strong-password AutoFill, show and hide, and rules that tick off
  • Each step shows working, a check, or your error's message, with Back between steps

02

Implementation notes

How it behaves, what it handles, and the decisions behind it.

One card carries the three steps, with "Step 1 of 3" and a short three-part track at its top. Reset your password takes the email (prefilled when you pass it), checks it when Send code is tapped, and runs your closure with a spinner and then a check on the button. Enter the code shows where the code went and six boxes over one real field, so the keyboard's AutoFill offers the code from Mail or Messages; the code verifies itself once full, a wrong one turns the boxes to the danger colour with your error under them and clears them, and "Didn't get it?" counts down before Resend code can be tapped. Choose a new password is a .newPassword field, so iOS can suggest a strong password, with a reveal eye, rules that tick off as it's typed (and turn to the danger colour if Save finds one unmet), "Both passwords match" for the confirm field, and Save password. Back under the button returns a step without losing the email. Password updated closes the flow with Sign in. Show the block redacted and it draws the first step as grey shapes.

Notes

  • ResetPasswordBlock(email:codeLength:resendAfter:passwordRules:onSendCode:onVerifyCode:onSetPassword:onSignIn:). It is a section: no navigation stack, background, padding or scroll view of its own, so place it in your own column, such as a pushed screen's ScrollView with .padding(.horizontal, 20), or a sheet.
  • onSendCode receives the trimmed email and also runs for Resend code. onVerifyCode receives ResetPasswordBlock.Verification (email and code). onSetPassword receives ResetPasswordBlock.NewPassword (email, the verified code and the password). Each is async throws: return to move on, throw to stay. The block shows a thrown LocalizedError's errorDescription, or a default for the step, such as "That code isn't right. Check the email and try again." A CancellationError goes back to rest quietly.
  • Each step's button shows a spinner while its closure runs and a brief check before the next step slides in.
  • onSignIn is Sign in on the done state; send the person to your sign-in screen. Nil hides the button.
  • email prefills the first step, for a person who came from a sign-in form. codeLength is 6 by default (4 to 8). resendAfter sets the countdown, 30 seconds by default.
  • passwordRules is a list of ResetPasswordBlock.PasswordRule, each a title and an isMet check on the password. PasswordRule.defaults is .minimumLength(8) and .numberOrSymbol; .mixedCase is also built in. "Both passwords match" is always added. Match the rules to what your server enforces.
  • Loading: apply .redacted(reason: .placeholder) and the block draws its first step as grey shapes, breathing unless Reduce Motion is on.
  • Fields: the email is .username with the email keyboard and Return reading Send; the code is .oneTimeCode on the number pad; both passwords are .newPassword, so iOS offers a strong password and saves it, with Return moving from the new password to the confirm field and saving from there.
  • Haptics: success when the password is saved, an error when a step fails, a warning when a submit is refused, and a selection tick as the step changes.
  • VoiceOver reads "Step 2 of 3" as one element, each field by its label with its error as a hint, the code field with its digits one by one, and each rule with "Done" or "Not yet". It announces "Code sent", refusals, failures and "Password updated". Back reads "Back to email" or "Back to the code". Every control is at least 44 points tall; at accessibility sizes headings, rules and errors wrap.
  • Reduce Motion turns the step slide and every other change into a short fade.
  • ResetPasswordBlockExample at the end of ResetPasswordBlock.swift is Fieldnote's Forgot password screen from the preview, with the email prefilled. Its stand-in auth accepts the code 135790 and refuses any other.

Theming

  • Reads SPTheme from @Environment(\.spTheme) and requires the design-system item.
  • The card is color.surface with radius.lg and 16 point padding (space.lg); groups inside it sit 24 points apart (space.xl).
  • "Step 1 of 3" is type.footnote in textSecondary; the track is three 20 by 4 point capsules, textPrimary up to the current step and fill after it.
  • Step titles are type.title3 in textPrimary, their lines type.subhead in textSecondary.
  • Fields and code boxes are 52 points tall on fill with radius.md and a 1 point separator hairline that turns to textPrimary when focused and to danger on an error. Labels are type.subhead in textSecondary. Code digits use the display face at 22 points, semibold at most, with tabular figures.
  • The step's button is the only accent: accent with accentOn in type.headline, radius.md, 52 points. Back and Resend code are textPrimary semibold; the countdown is textTertiary. Met rules are textPrimary with a filled check, unmet ones textSecondary with a textTertiary circle. Errors are type.footnote in danger.
  • Steps move with motion.smooth, states with motion.snappy, the buttons' press with motion.standard.

Requirements

  • Associated Domains with a webcredentials: entry for your domain, so iOS saves the new password for your sign-in.