Skip to main content
Urbicon UI
Back to Recipes

Login Form

Complete authentication form with validation, password visibility, and demo credentials.

Live Preview

Welcome back

Sign in to your account

Forgot password?

Don't have an account? Sign up

Key Features

  • Client-side email and password validation
  • Show/hide password toggle
  • Loading state with spinner on submit
  • Dismissible error alerts
  • Success state with redirect message
  • Remember me checkbox
  • Responsive centered layout

Code

Login Form Recipe

<script lang="ts">
  import { Button, Input, Checkbox, Card, Alert } from '@urbicon-ui/blocks';

  let email = $state('');
  let password = $state('');
  let rememberMe = $state(false);
  let loading = $state(false);
  let error = $state('');

  let emailValid = $derived(
    email === '' || /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email)
  );
  let canSubmit = $derived(email !== '' && password.length >= 8 && emailValid);

  async function handleLogin() {
    if (!canSubmit) return;
    loading = true;
    error = '';
    await new Promise((r) => setTimeout(r, 1500));
    // Replace with your auth logic
    if (email === 'demo@example.com' && password === 'password123') {
      window.location.href = '/dashboard';
    } else {
      error = 'Invalid credentials';
    }
    loading = false;
  }
</script>

<Card class="mx-auto max-w-sm shadow-lg">
  <div class="p-8">
    <h3 class="mb-6 text-center text-xl font-bold">Sign In</h3>

    {#if error}
      <Alert intent="danger" variant="soft" size="sm" dismissible
        onDismiss={() => (error = '')}>{error}</Alert>
    {/if}

    <form onsubmit={(e) => { e.preventDefault(); handleLogin(); }}>
      <Input label="Email" type="email" placeholder="you@example.com"
        bind:value={email}
        error={!emailValid ? 'Invalid email' : undefined} />

      <Input label="Password" type="password"
        bind:value={password} class="mt-4" />

      <div class="mt-4 flex items-center justify-between">
        <Checkbox label="Remember me" bind:checked={rememberMe} />
        <a href="/forgot" class="text-sm text-primary">Forgot?</a>
      </div>

      <Button intent="primary" class="mt-6 w-full" type="submit"
        disabled={loading} {loading}>
        Sign in
      </Button>
    </form>
  </div>
</Card>