Login form
Minimal email + password sign-in form built on FormProvider + FormField. Email is required and format-checked; the submit handler only fires onValid when both fields pass.
Preview
Source
apps/docs/app/recipes/login/recipe.tsx'use client';
import { Button, FormField, FormProvider, Input, useForm } from '@hey-mike/tungsten';
const isEmail = (v: unknown) =>
typeof v === 'string' && /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(v) ? undefined : 'Enter a valid email';
function LoginFields() {
const form = useForm();
return (
<form onSubmit={form.handleSubmit} className="flex w-full max-w-sm flex-col gap-4" noValidate>
<p className="text-ink-3 text-2xs font-mono uppercase tracking-label">
<span className="text-error-text">*</span> required
</p>
<FormField name="email" label="Email" required validate={isEmail}>
<Input type="email" placeholder="you@example.com" autoComplete="email" />
</FormField>
<FormField name="password" label="Password" required validate={(v) => (v ? undefined : 'Required')}>
<Input type="password" autoComplete="current-password" />
</FormField>
<Button type="submit" variant="brand" size="md">
Sign in
</Button>
</form>
);
}
export default function LoginRecipe() {
return (
<FormProvider>
<LoginFields />
</FormProvider>
);
}
'use client';
import { Button, FormField, FormProvider, Input, useForm } from '@hey-mike/tungsten';
const isEmail = (v: unknown) =>
typeof v === 'string' && /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(v) ? undefined : 'Enter a valid email';
function LoginFields() {
const form = useForm();
return (
<form onSubmit={form.handleSubmit} className="flex w-full max-w-sm flex-col gap-4" noValidate>
<p className="text-ink-3 text-2xs font-mono uppercase tracking-label">
<span className="text-error-text">*</span> required
</p>
<FormField name="email" label="Email" required validate={isEmail}>
<Input type="email" placeholder="you@example.com" autoComplete="email" />
</FormField>
<FormField name="password" label="Password" required validate={(v) => (v ? undefined : 'Required')}>
<Input type="password" autoComplete="current-password" />
</FormField>
<Button type="submit" variant="brand" size="md">
Sign in
</Button>
</form>
);
}
export default function LoginRecipe() {
return (
<FormProvider>
<LoginFields />
</FormProvider>
);
}