Skip to content

CSS Tutorial Practical Projects

Project: A Login Form

Lesson 174 of 182 2 min read By Deepak Paswan Updated Oct 4, 2026

A login form looks simple and is a good test of everything in the forms chapter: labels, focus states, spacing and accessibility.

The finished form

index.html
HTML
<style>
  *, *::before, *::after { box-sizing: border-box; }
  body { margin: 0; font-family: system-ui, sans-serif; background: #f4ece6; min-height: 100vh; display: grid; place-items: center; padding: 16px; }

  .login { width: 100%; max-width: 340px; background: #fff; padding: 28px; border-radius: 14px; box-shadow: 0 8px 24px rgba(0,0,0,.1); }
  .login h1 { margin: 0 0 4px; font-size: 1.5rem; }
  .login p.sub { margin: 0 0 20px; color: #5c5750; font-size: .9375rem; }

  .field { margin-bottom: 16px; }
  .field label { display: block; margin-bottom: 4px; font-weight: 600; font-size: .9375rem; }
  .field input {
    width: 100%; min-height: 44px; padding: 8px 12px; font: inherit;
    border: 2px solid #b9b2ad; border-radius: 8px; background: #fff;
  }
  .field input:focus-visible { outline: 3px solid #1a527655; border-color: #1a5276; }
  .field input:user-invalid { border-color: #c0392b; background: #fdf2f2; }
  .field .error { display: none; margin-top: 4px; color: #b00020; font-size: .875rem; }
  .field input:user-invalid ~ .error { display: block; }

  .row { display: flex; justify-content: space-between; align-items: center; margin-bottom: 18px; font-size: .875rem; }
  .row a { color: #1a5276; }
  .row label { display: flex; align-items: center; gap: 6px; }
  .row input { accent-color: #d94a00; width: 18px; height: 18px; }

  .submit { width: 100%; min-height: 46px; border: 0; border-radius: 8px; background: #d94a00; color: #fff; font: inherit; font-weight: 700; cursor: pointer; transition: background .15s; }
  .submit:hover { background: #b84624; }
  .submit:focus-visible { outline: 3px solid #1a5276; outline-offset: 2px; }
</style>
<form class="login">
  <h1>Welcome back</h1>
  <p class="sub">Sign in to see your orders.</p>
  <div class="field">
    <label for="email">Email</label>
    <input id="email" type="email" autocomplete="email" required>
    <span class="error">Enter a valid email address.</span>
  </div>
  <div class="field">
    <label for="pw">Password</label>
    <input id="pw" type="password" autocomplete="current-password" minlength="8" required>
    <span class="error">Use at least 8 characters.</span>
  </div>
  <div class="row">
    <label><input type="checkbox"> Remember me</label>
    <a href="#">Forgot password?</a>
  </div>
  <button class="submit" type="submit">Sign in</button>
</form>

Where each idea comes from

  • display: grid; place-items: center on body centers the form on the screen.
  • max-width with width: 100% makes the form fluid on small screens.
  • Labels sit above fields, with a 44px minimum field height for touch.
  • :user-invalid ~ .error shows the error message only after the visitor has interacted, using the general sibling selector.
  • Focus uses :focus-visible with a clear ring.
  • The button is a real <button>, full width, with hover and focus styles.

Check yourself

  1. Tab through the whole form. Can you always tell where you are?
  2. Zoom the page to 200%. Does anything overlap?
  3. Type “abc” in the email field and click out. Does the error show?
lightbulb
Security note
This is only the look. A real login form needs server-side validation and a secure connection. Never rely on client-side checks alone.