Blocks
Classifieds form
Block: the brief form (name, company, email, brief, four-way project size) with an error summary, inline success and error messages and an onSubmit prop; no network call.
Preview
Install
bash
npx shadcn add @eloquent/classifieds-formThis is a block: it installs to components/blocks/classifieds-form.tsx and adds button, field, form, input, label, radio-group and textarea, plus react-hook-form.
Usage
tsx
import { ClassifiedsForm } from "@/components/blocks/classifieds-form";
<ClassifiedsForm
copy={copy}
onSubmit={async (values) => {
// values: { name, company, email, brief, size }
await sendBrief(values); // your code; reject to show the error message
}}
/>copy carries every string, including the four size labels (sizes) and the error summary title (summary(count), a function, so build copy in a client module). The component never calls the network: your onSubmit does. Return normally for the success message, throw or reject for the error message.
States
Failed validation
Sent
Send failed
| State | Treatment |
|---|---|
| Failed validation | Summary at the top (2px ink left rule, ink ! icon, one entry per error); each invalid field gets a 2px ink left rule, an ink ! icon and a message; the first invalid field takes focus |
| Sending | The button reads "Sending…" and stays focusable; a second send is blocked |
| Sent | An ink check icon and a message in a role="status" line; the form is cleared |
| Send failed | A 2px ink left rule, an ink ! icon and a message in a role="alert" line; the values stay |
Keyboard
| Key | Action |
|---|---|
| Tab / Shift+Tab | Summary entries (after a failed submit), name, company, email, brief, the size group (one stop), submit |
| Arrow keys | Move through the four project sizes and select |
| Enter | In a text field, sends the form; on a summary entry, focuses that field |
| Space | Activates the focused button or selects the focused size |
Vietnamese
Ink adaptation
Brand block with no upstream. Fields are newspaper form lines, not boxes. The four project sizes are scale-of-work labels, never prices. Errors and success are shown by ink rules, icons and words, never colour. The email field is not type="email" so the form's own summary and messages show instead of the browser's bubble; inputMode="email" keeps the mobile keyboard.