Field
Wraps a form control with a label, hint and error message, and wires up ARIA automatically.
Tasdiqlash kodi SMS orqali yuboriladi
Email manzil noto'g'ri
'use client';
import { Field, Input } from '@akhatmirzo/ui';
export default function FieldBasic() {
return (
<div className="flex w-full max-w-sm flex-col gap-4">
<Field label="Telefon" required description="Tasdiqlash kodi SMS orqali yuboriladi">
<Input prefix="+998" placeholder="90 123 45 67" inputMode="tel" />
</Field>
<Field label="Email" error="Email manzil noto'g'ri">
<Input type="email" defaultValue="sarvar@mail" />
</Field>
</div>
);
}
Import
import { Field } from '@akhatmirzo/ui';When to use
- Around every form control —
Input,Textarea,Select,Checkbox,RadioGroup,Switchand the rest. No more hand-writtenid,htmlFor,aria-describedby,aria-invalidoraria-required. - Pass errors to
error, not to a separate<p>— that way the control turns red and screen readers announce the message. - Keep
descriptionshort — a format, a limit, or why the field is needed. Move longer text into the page. - One
Field, one control. Don't put two inputs under a single label.
Validation
When error is not empty, the field switches to its error state: the control gets
aria-invalid, its border turns red and the message appears below with an icon. Errors live in
an aria-live region, so screen readers announce them as they appear. Try submitting the form
empty.
'use client';
import { Button, Field, Input } from '@akhatmirzo/ui';
import { useState, type FormEvent } from 'react';
export default function FieldValidation() {
const [name, setName] = useState('');
const [submitted, setSubmitted] = useState(false);
const error = submitted && name.trim().length < 3 ? 'Kamida 3 ta harf kiriting' : undefined;
const submit = (event: FormEvent) => {
event.preventDefault();
setSubmitted(true);
};
return (
<form onSubmit={submit} noValidate className="flex w-full max-w-sm flex-col gap-4">
<Field label="To'liq ism" required error={error}>
<Input
value={name}
onChange={(e) => setName(e.target.value)}
placeholder="Sarvar Abduxoliqov"
autoComplete="name"
/>
</Field>
<Button type="submit" variant="primary">
Davom etish
</Button>
</form>
);
}
Horizontal layout
orientation="horizontal" puts the label on the left (160px) and the control on the right.
Useful for settings pages and wide forms.
Chekda ko'rinadi
'use client';
import { Field, Input, Textarea } from '@akhatmirzo/ui';
export default function FieldHorizontal() {
return (
<div className="flex w-full max-w-xl flex-col gap-4">
<Field orientation="horizontal" label="Do'kon nomi" description="Chekda ko'rinadi">
<Input defaultValue="Bahor Market" />
</Field>
<Field orientation="horizontal" label="Manzil">
<Textarea minRows={2} defaultValue="Toshkent, Chilonzor tumani, 9-kvartal" />
</Field>
</div>
);
}
Disabled
disabled on Field disables the control inside it too and dims the label.
Hudud administrator tomonidan belgilanadi
'use client';
import { Field, Input } from '@akhatmirzo/ui';
export default function FieldDisabled() {
return (
<div className="w-full max-w-sm">
<Field label="Hudud" description="Hudud administrator tomonidan belgilanadi" disabled>
<Input defaultValue="Toshkent shahri" />
</Field>
</div>
);
}
Your own control (useFieldControl)
Every form component in the library connects to Field through the useFieldControl hook. You
can connect your own control (a native <select>, a third-party widget) the same way: spread
controlProps onto the element and the rest is automatic.
Shaharni tanlang
'use client';
import { Field, useFieldControl } from '@akhatmirzo/ui';
function CitySelect() {
const { controlProps, invalid, disabled } = useFieldControl();
return (
<select
{...controlProps}
disabled={disabled}
data-invalid={invalid ? '' : undefined}
className="h-10 rounded-lg border border-border bg-surface px-3 text-sm text-text data-invalid:border-danger"
>
<option value="">Tanlang</option>
<option>Toshkent</option>
<option>Samarqand</option>
<option>Buxoro</option>
</select>
);
}
export default function FieldCustomControl() {
return (
<div className="w-full max-w-sm">
<Field label="Shahar" required error="Shaharni tanlang">
<CitySelect />
</Field>
</div>
);
}
useFieldControl also works outside a Field — it then generates its own id.
Props
Field accepts every other <div> attribute.
| Prop | Type | Default | Description |
|---|---|---|---|
childrenrequired | ReactNode | — | The control (Input, Select, Checkbox ...) |
label | ReactNode | — | Field name, linked to the control with <label htmlFor> |
description | ReactNode | — | Hint text under the label (aria-describedby) |
error | ReactNode | — | When set, the control becomes invalid and the message shows with an icon |
required | boolean | false | Adds * to the label and aria-required to the control |
disabled | boolean | false | Disables the control inside as well |
orientation | 'vertical' | 'horizontal' | 'vertical' | Label above or to the left |
useFieldControl
function useFieldControl(options?: FieldControlOptions): FieldControlResult;options are the control's own values; they're merged with the ones coming from Field
(invalid, required and disabled are combined with a logical OR).
| Prop | Type | Default | Description |
|---|---|---|---|
id | string | — | Own id — when set, the label points to it |
invalid | boolean | — | Error state |
required | boolean | — | Required field |
disabled | boolean | — | Disabled |
aria-describedby | string | — | Extra description ids, appended to the Field's own |
aria-invalid | boolean | 'true' | 'false' | 'grammar' | 'spelling' | — | true or 'true' works like invalid |
Return value:
| Prop | Type | Default | Description |
|---|---|---|---|
id | string | — | The id to put on the control |
labelId | string | undefined | — | The Field label's id — for aria-labelledby where htmlFor doesn't work |
invalid | boolean | — | Resolved error state |
required | boolean | — | Resolved required state |
disabled | boolean | — | Resolved disabled state |
controlProps | { id; 'aria-describedby'?; 'aria-invalid'?: true; 'aria-required'?: true } | — | Attributes to spread directly onto the control |
Data attributes
| Attribute | Value |
|---|---|
data-slot | field |
data-orientation | vertical · horizontal |
data-invalid | Present when error set |
data-disabled | Present when disabled |
Accessibility
- Linked label.
<label htmlFor>points to the control'sid; if you give the control your ownid, the label follows it. - Hint and error are read through
aria-describedby— when the control gets focus, screen readers announce them after the label. - Error announcements. The message sits in an
aria-live="polite"region that is always in the DOM, so even the first error gets announced. - Required fields. The
*isaria-hidden; the control getsaria-requiredinstead. <div>-based controls likeRadioGroupcan't usehtmlFor, so they getaria-labelledbyfromlabelIdautomatically.