Skip to content
shadcn.io

shadcn.io is not affiliated with official shadcn/ui

Email and Password Form Block for React

The sign-in pair done well: an email named for password managers, a password with a reveal button and a Caps Lock warning, one generic failure that never says which half was wrong, and a quiet band with the demo account.

Framework
UI library

Preview

Preview width

Installation

Part of Pro
Pro unlocks the code and one-line install of every Pro button and text effect, plus the MCP for your AI editor.
Have Pro already? Sign in to open it.Opens here as soon as you're Pro.

Overview

Get the two fields of a sign-in right, with this email and password form for React with Base UI. A compact header sits over a hairline frame with a plus mark on each corner. In the first band an Input takes the email with autoComplete="username", and a Password Input takes the password with current-password and a reveal button. While the password field has focus and Caps Lock is on, the line under it says so, read from the browser's own getModifierState, and the foot repeats it once. Press Sign in with the wrong pair and the form does not say which half was wrong: both fields are marked invalid, one sentence says "That email and password do not match" and focus goes to the email. Empty fields are told so by name. A quiet second band prints the demo's account and a Fill them in button. Sign in, the only Shine Button, waits a moment and says in the page that nothing was sent. It's built from Field, Input, Password Input and Guides. This is the pair as a pattern, for sign-in pages, dialogs and settings.

FAQ

Why does the failure never say which field was wrong?

Because an attacker could use it: "no such email" lets anyone test which addresses have accounts. Here a well-formed pair that does not match marks both fields aria-invalid, shows one sentence ("That email and password do not match") under the password and moves focus to the email, so the person fixes the likelier typo first. Missing or malformed input is a different case: that is reported by field ("Enter your email address."), since it says nothing about any account. Your server should answer the same way in the same time for an unknown email and a wrong password.

How does the Caps Lock warning work, and when is it wrong?

The password field reads getModifierState("CapsLock") on each key press and release, and forgets it when the field loses focus, so the warning only shows while you are typing there. Browsers only report the key's state when a key event arrives, so the warning can appear a keystroke late, and some systems (a few Linux setups, some remote desktops) do not report it at all; the reveal button is the fallback. The warning is a plain line in the field's description slot and in the foot's single status, never a modal or a toast.

Which attributes help password managers?

autoComplete="username" on the email field (with type="email") and current-password on the password, with name set on both and the label tied to each field by htmlFor. The email is not rewritten as you type and the password is never trimmed. The reveal button is a real button in the tab order, with a pressed state, so it works without a pointer.

What stays local, and how do I connect it for real?

Everything. One demo account is typed in the file (ACCOUNT) and checked in the browser, and a good pair waits 700 milliseconds, clears the password and says "Signed in, in this demo. Nothing was sent." In your app post the pair from submit over HTTPS, set the session cookie on the server, and keep the generic wording for any refusal. Add rate limiting and a lockout on the server; the form cannot do that for you.

What does a screen reader announce?

One polite status in the foot, present from load: the Caps Lock warning, a refusal ("Not signed in: that pair does not match.") or the result, each once. The failure sentence and the empty-field messages sit under their fields and are part of each field's description, so they are read when the field is focused; the button stays enabled so nothing is hidden from people who cannot see why it was off. After a good sign-in the result takes focus, because the busy button disables itself while it works.

How do I connect it to react-hook-form or TanStack Form?

Register the two fields and keep the generic failure as a form-level error. With react-hook-form, use register for the email and Controller for the password input, and set the failure with setError("root", ...) from the submit handler, then focus the email. With TanStack Form, validate each field's shape on blur and return the server's refusal from onSubmitAsync as a form-level error, so both fields can be marked invalid at once.

  • Pro

    An identifier-first sign-in for an invoicing app: one email field, a lookup against two typed accounts, then either the password step with the address kept as a badge or account creation with the address carried over.

  • Pro

    A sign-up page for a community forum in two columns of fields: a handle with an at sign that checks itself against a typed taken list and offers three tries as buttons, then the email, a password with an eight-character hint and Create account.

  • Pro

    A master-password form with advice instead of a checklist: a four-segment meter, one sentence that names the weakest thing about what is typed, a polite confirm field and a side cell that explains the four segments.

  • Pro

    One-Time Code Input Form

    Numbers and pickers

    A six-slot confirmation code in two groups of three with its behaviours in view: paste fills all six and checks at once, a wrong code is marked, counted and cleared, and a resend button waits 30 seconds.

  • Pro

    A change-password form that says what it ends: three password fields with a line naming what the new one still needs, boxes for the other sessions, an app password and trusted devices, and a sentence that follows them.

  • Pro

    The calmest form: one page with a mark, a heading that asks one question, one field with a hidden label and one full-width button, with the answer or the one problem shown under the field.