Block · Account

New

Sign In SwiftUI Block

A SwiftUI login screen. The sign-in section of a welcome screen: email and password, Sign in with Apple, a passkey and Create account in one block.

Email and password on one card, checked on submit and then live, with Sign in running your closure through working, done and failed. Forgot password confirms inline, Sign in with Apple is the system button in the colour of the appearance, and a link at the foot switches to Create account with password rules that tick off.

  • SwiftUI
  • iOS 17.0+
  • sign-in
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.

  • Email and password that check on submit, then live, with Password AutoFill
  • Sign in shows working, a check, or your error's message
  • Forgot password sends a link and confirms "Check your email" inline
  • The system Sign in with Apple button, plus an optional passkey
  • Create account in the same block, with password rules that tick off

Requires

com.apple.developer.applesignin

02

Implementation notes

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

One card holds the form. Email and password stay quiet until Sign in is tapped, then show what's wrong under each field in the danger colour and keep checking live as they're corrected; Return moves from field to field and signs in from the password. The password has a reveal eye, and Password AutoFill offers saved logins. Sign in runs your closure: a spinner takes the label's place, a check follows when it returns, and a thrown error's message shows under the button. "Forgot password?" sits on the password's label row; it sends a reset link to the email typed so far and confirms "Check your email" in the card. Under an "or" hairline, Sign in with Apple is the system button, white on dark grounds and black on light ones, with its own progress and check, and "Sign in with a passkey" appears when you pass it. A plain link under the card switches to Create account, which adds a name field and password rules that tick off as they're typed and turn to the danger colour if a submit finds one unmet. A legal line with your links can close the block. Show the block redacted while a session restores and it draws grey shapes in its own layout.

Notes

  • SignInBlock(mode:email:passwordRules:legal:onSignIn:onCreateAccount:onForgotPassword:onApple:onAppleRequest:onPasskey:onSuccess:). Only onSignIn is required; every other part appears when you pass it. 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 ScrollView with .padding(.horizontal, 20), or a sheet.
  • onSignIn receives SignInBlock.Credentials (the email, trimmed, and the password). onCreateAccount receives SignInBlock.NewAccount (name, email, password) once the name is filled, the email reads right and every rule is met. Both are async throws: return to succeed, throw to fail. The block shows a thrown LocalizedError's errorDescription, so throw "That email and password don't match." in your own words; anything else shows "Couldn't sign in. Try again." A CancellationError goes back to rest quietly.
  • After a success the button holds its check for about a second, then calls onSuccess. Move to your app there, not at the end of onSignIn, so the check is seen. The block then settles back with the password cleared.
  • mode is a Binding<SignInBlock.Mode> (.signIn or .createAccount) for a screen that changes its own title with it. Leave it out and the block keeps the mode, starting on Sign in. Without onCreateAccount the block stays on Sign in and hides the link.
  • email is a Binding<String> to prefill a returning person's address. The password always stays inside the block.
  • passwordRules is a list of SignInBlock.PasswordRule, each a title and an isMet check that sees the whole NewAccount. PasswordRule.defaults is .minimumLength(8), .numberOrSymbol and .avoidsNameAndEmail. Match them to what your server enforces.
  • onForgotPassword receives the trimmed email. If the email is empty or malformed the field says so and takes focus instead. While the closure runs the link shows a spinner; when it returns, "Check your email" and the address appear under the password until the email changes. A thrown error shows under the field.
  • onApple receives Sign in with Apple's Result<ASAuthorization, Error>; send the ASAuthorizationAppleIDCredential's identityToken and authorizationCode to your server. The block asks for the name and email scopes, then calls onAppleRequest so you can set a hashed nonce or change the scopes. Closing Apple's sheet never reaches your closure. A failure Apple reports shows "Couldn't sign in with Apple. Try again." unless your closure throws its own error.
  • onPasskey runs your passkey sign-in, an ASAuthorizationController with an ASAuthorizationPlatformPublicKeyCredentialProvider assertion request. Throw ASAuthorizationError.canceled and the button goes back to rest quietly. It shows on Sign in only.
  • legal is an AttributedString shown under the block with its links underlined. SignInBlock.legalNotice(terms:privacy:) builds "By continuing, you agree to the Terms of Service and Privacy Policy." with your two URLs. Links open with the environment's openURL.
  • Loading: apply .redacted(reason: .placeholder) while a session restores, and the block draws its card, fields and buttons as grey shapes, breathing unless Reduce Motion is on.
  • Fields: Email is .username with the email keyboard, so Password AutoFill pairs it with the password (.password on Sign in, .newPassword on Create account, which offers a strong password). Name is .name. Return reads Next, then Go.
  • Haptics: success when a sign-in lands, an error when one fails, a warning when a submit is refused, and a selection tick when the mode changes.
  • VoiceOver reads each field by its label with its error as a hint, announces refused submits, failures, "Signed in" and the reset confirmation, and reads each password rule with "Done" or "Not yet". The reveal eye reads "Show password" or "Hide password". Every control is at least 44 points tall; the Forgot password link's target reaches into the space around its row. At accessibility sizes the link moves under the Password label, fields grow and messages wrap.
  • Reduce Motion turns every change into a short fade.
  • SignInBlockExample at the end of SignInBlock.swift is Folio's welcome screen from the preview: the app's name, "Welcome back" and a line under it, then the block with every option. It owns the mode, so its title becomes "Create your account" with it, and its stand-in auth refuses a password shorter than eight characters so both outcomes can be tried. It wears the Studio brand unless the host set one.

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); field groups sit 16 points apart, with 24 above the button.
  • Fields 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, input type.body in textPrimary, prompts textTertiary, errors type.footnote in danger. The reveal eye is textSecondary.
  • Sign in is the only accent: accent with accentOn in type.headline, radius.md, 52 points. Sign in with a passkey uses fill with textPrimary. Sign in with Apple takes the same height and corner, black or white by appearance as Apple asks.
  • Links are textPrimary (Forgot password in type.subhead medium, the Create account link in type.subhead semibold beside textSecondary). The "or" divider is SPHairline with type.footnote in textSecondary. Met rules are textPrimary, unmet ones textSecondary with a textTertiary circle.
  • States move with motion.snappy, the mode change with motion.smooth, the buttons' press with motion.standard.

Requirements

  • Sign in with Apple capability, when you pass onApple.
  • Associated Domains with a webcredentials: entry for your domain, for Password AutoFill to offer saved logins and for passkeys.