Login Form
A compact email and password form using Form, FormField, FormControl, and Button with no state library required.
Login form
Section titled “Login form”A compact email + password form using Form, FormField, FormControl,
and Button. No state library required — new FormData(form) at submit
is enough.
import { Button, Form, FormControl, FormField, FormLabel, FormMessage, Heading, Input, Link, Stack,} from '@arshad-shah/cynosure-react';
export function LoginForm() { return ( <Stack gap="5" maxWidth="sm" marginX="auto" padding="6"> <Heading level={1} size="2xl"> Sign in </Heading>
<Form onSubmit={async (e) => { e.preventDefault(); const data = Object.fromEntries( new FormData(e.currentTarget).entries(), ); await fetch('/api/session', { method: 'POST', body: JSON.stringify(data), }); }} > <Stack gap="4"> <FormField name="email" required> <FormLabel>Email</FormLabel> <FormControl> <Input type="email" autoComplete="email" /> </FormControl> <FormMessage /> </FormField>
<FormField name="password" required> <FormLabel>Password</FormLabel> <FormControl> <Input type="password" autoComplete="current-password" /> </FormControl> <FormMessage /> </FormField>
<Button type="submit" size="lg" fullWidth> Sign in </Button>
<Link href="/forgot-password" size="sm"> Forgot your password? </Link> </Stack> </Form> </Stack> );}With react-hook-form + Zod
Section titled “With react-hook-form + Zod”See the Form + RHF + Zod recipe that ships alongside the form composition primitives for a fully validated variant of this form.
Accessibility notes
Section titled “Accessibility notes”FormFieldwiresid/aria-describedby/aria-invalidonto the<input>automatically.FormLabelbecomes the control’s accessible name; no extraaria-labelneeded.FormMessageannounces only when the field is invalid.