Build & Push Docker Image / build (push) Has been cancelled
Refresh the homepage around new hero/services/roadmap sections, shared design tokens, and updated brand assets. Co-authored-by: Cursor <cursoragent@cursor.com>
3.0 KiB
3.0 KiB
Forms
Form UI must use shared primitives so controls match buttons, cards, and focus rings.
Building blocks
| Piece | Import |
|---|---|
| Input | @/components/ui/input |
| Textarea | @/components/ui/textarea |
| Label | @/components/ui/label |
| Checkbox / Radio / Switch / Select | @/components/ui/* |
| Field layout | @/components/ui/field (Field, FieldGroup, FieldSet, …) |
| Form (RHF) | @/components/ui/form + react-hook-form + zod resolvers |
| Button submit | @/components/ui/button |
Input spec
From components/ui/input.tsx:
| Property | Value |
|---|---|
| Height | h-9 (36px) default; align to buttons with h-[var(--btn-height-lg)] when paired with size="lg" submit |
| Radius | rounded-md (--radius-md) |
| Border | border-input |
| Background | bg-background; dark: dark:bg-surface/60 |
| Text | text-base md:text-sm (16px on mobile avoids iOS zoom) |
| Padding | px-3 py-1 |
| Shadow | shadow-xs |
| Transition | duration-200 on color/border/shadow |
| Focus | border-primary + ring-[3px] ring-primary/25 |
| Disabled | opacity-50, no pointer |
| Invalid | aria-invalid → destructive border/ring |
Field layout
- Vertical (default): label above control,
gap-3within field; groups usegap-7. - Label → control spacing: prefer
typeSpacing.labelToControl(gap-1.5) or Field defaults. - Checkbox/radio groups: tighter
gap-3. - Errors: use
text-destructiveand wirearia-invalidon the control.
import { Field, FieldLabel, FieldDescription, FieldError } from "@/components/ui/field";
import { Input } from "@/components/ui/input";
import { Button } from "@/components/ui/button";
<Field>
<FieldLabel htmlFor="email">ایمیل</FieldLabel>
<Input id="email" type="email" autoComplete="email" />
<FieldDescription>برای پیگیری درخواست با شما تماس میگیریم.</FieldDescription>
<FieldError>ایمیل معتبر نیست.</FieldError>
</Field>
<div className="flex flex-col gap-3 sm:flex-row">
<Input type="email" className="h-[var(--btn-height-lg)]" placeholder="آدرس ایمیل شما" />
<Button type="submit" size="lg">عضویت</Button>
</div>
Validation & a11y
- Associate every control with a visible
<Label>/FieldLabelviahtmlFor+id. - Announce errors with
aria-invalidand descriptive error text (not color alone). - Required fields: use
aria-requiredor nativerequiredplus clear copy. - Keep touch targets ≥ 36px height (inputs
h-9; preferlgbutton pairing for marketing forms). - Do not disable paste or obscure password managers.
Newsletter / compact patterns
Footer pattern: email input height matches Button size="lg" via --btn-height-lg.
Forbidden
- Unstyled native inputs next to themed buttons.
outline-nonewithout a visible focus replacement.- Hardcoded border colors (
border-gray-300). - Mixing different input heights in the same form row without intent.