Sign-in & registration blocks

Screens for getting a user into your app: sign in with a password, a provider or a magic link, create an account, prove it is them with a one-time code, and reset a forgotten password. Each block is one .svelte file built from SvTextInput, SvPasswordInput, SvOtpInput, SvButton and SvCard, themed from the --sg-* tokens.

Installation

Add the whole group, or one block by its name (shown under each demo):

See them first with npx @svgrid/ui try blocks/auth. No project needed.

Login

A two-column page: a brand panel on the left, the sign-in card on the right with provider buttons, email and password (with reveal), remember-me and a forgot-password link. Below 720 px the brand panel is hidden and the card fills the screen.

Open the live example: Login block (Blocks)

npx @svgrid/ui add login

Sign-up

A centered account-creation card: first and last name side by side, work email, a password with the live strength meter, a plan switch and a terms checkbox.

Open the live example: Sign-up block (Blocks)

npx @svgrid/ui add signup

Two-factor code

The second step of a sign-in: a six-digit SvOtpInput that advances on each digit and verifies on the last one, with a resend timer. Enter 000000 to see the error state.

Open the live example: Two-factor / OTP block (Blocks)

npx @svgrid/ui add otp

Sign-in with providers

SSO first: Google, GitHub and Microsoft buttons, and a Single sign-on (SAML) button that opens a company-domain field. Below the divider, a passwordless form emails a sign-in link and switches the card to a "Check your inbox" state with the address, a 30-second resend cooldown and a link to use a different email.

Open the live example: Sign-in with providers block (Blocks)

npx @svgrid/ui add auth-providers

Forgot password

Two states in one card. The request state takes an email, validates it and shows the button's loading state while it sends. The confirmation names the address, offers a resend after a 60-second cooldown and a link to try another email; "Back to sign-in" sits in the footer of both.

Open the live example: Forgot password block (Blocks)

npx @svgrid/ui add auth-forgot-password

Connecting your auth

Each block's core takes its requests as options, so wiring a real backend leaves the markup alone. Find the create...() call in the block's instance script and replace the demo's timer. In the login block that is createLogin({ onSubmit }). It gets { email, password, remember } once both fields validate, the submit button shows its loading state until the promise settles, and a throw keeps the form as it was and goes to onError:

const login = createLogin({
  onSubmit: async (values) => {
    const r = await fetch('/api/login', { method: 'POST', body: JSON.stringify(values) })
    if (!r.ok) throw new Error('Wrong email or password')
    location.assign('/app')
  },
  onError: (e) => toast.error(e instanceof Error ? e.message : 'Sign-in failed'),
})

In SvelteKit you can use a form action instead: give the <form> a method="POST" and drop the {...login.formProps()} spread, which calls preventDefault. The email and password fields already have a name; give any other input one too. An input with a name submits its value through a hidden field, so +page.server.ts reads it from request.formData() like a plain input.

The other blocks work the same way:

const requestReset = async (addr: string) => {
  const r = await fetch('/api/password-reset', { method: 'POST', body: JSON.stringify({ email: addr }) })
  if (!r.ok) throw new Error('Reset failed')
}

Headless

Every block here is a styled render of the core in its <script module>. To draw your own markup, take the core alone with npx @svgrid/ui add auth-forgot-password --headless (it writes auth-forgot-password.svelte.ts) and spread its prop-getters on plain elements:

<script lang="ts">
  import { createForgotPassword } from './auth-forgot-password.svelte.js'

  const forgot = createForgotPassword({
    onRequest: async (email) => {
      const r = await fetch('/api/password-reset', { method: 'POST', body: JSON.stringify({ email }) })
      if (!r.ok) throw new Error('Reset failed')
    },
  })
</script>

{#if forgot.sentTo}
  <p>Check {forgot.sentTo} for a reset link.</p>
  <button {...forgot.resendProps()}>{forgot.cooldown ? `Resend in ${forgot.cooldown}s` : 'Resend'}</button>
{:else}
  <form {...forgot.formProps()}>
    <label>Email <input {...forgot.fieldProps()} /></label>
    {#if forgot.error}<p role="alert">{forgot.error}</p>{/if}
    <button disabled={forgot.busy}>Send reset link</button>
  </form>
{/if}

See also

Live examples

  • Login block - A two-column authentication page: a branded gradient panel beside a sign-in SvCard with social SvButtons, SvTextInput + SvPasswordInput (reveal), remember-me SvCheckBox, an "or" SvDivider and forgot-password link. Drops into any route as-is.
  • Sign-up block - A centered account-creation card: two-up name fields, work email, a password with the live strength meter, a plan SvSegmented switch, terms SvCheckBox and a benefits rail. Submit fires a promise toast. Pure UI-kit.
  • Two-factor / OTP block - The verification step of a sign-in flow: SvOtpInput (6 digits, auto-advance + onComplete), a resend cooldown timer, and the waiting -> verifying -> verified states. Enter 000000 to see the error path.
  • Sign-in with providers block - SSO-first SvCard with Google, GitHub and Microsoft SvButtons, plus a SAML option that reveals a company-domain SvTextInput. Below an SvDivider, a magic-link form switches to a Check your inbox state with a 30 s resend cooldown.
  • Forgot password block - Password recovery in one SvCard. An email SvTextInput with validation and a loading SvButton leads to a check-your-email state that names the address, has a 60 s resend cooldown and a back-to-sign-in link.

Related articles