Bỏ qua tới nội dung
Component / 035 / NEXOFRAME

Field

Mẫu chuẩn

Label và Input gộp thành một hàng biểu mẫu, nối bằng id, aria-describedby và aria-invalid — dây nối trợ năng mà mỗi call site sẽ quên tự làm.

Composite tầng 2Không có varianterror che status, status che hintDựng từ Label + Input

Playground

Đổi brand, theme, ghi chú (không có / hint / đang kiểm tra / còn trống / đã dùng / error) và trạng thái disabled để xem cùng một Field thích ứng.

LIVE PREVIEW

Không có ghi chú.

import { Field } from "@nexobox/ui";

<Field
  label="Tên workspace"
  placeholder="vd. Xưởng Mộc Tâm An"
/>

Bài toán

Một ô nhập trần không dùng được trong biểu mẫu: người dùng cần biết nó hỏi gì, người dùng bàn phím cần nhãn ăn khớp với ô để bấm vào nhãn là tiêu điểm nhảy vào ô, và người dùng trình đọc màn hình cần dòng lỗi được đọc như một phần của ô chứ không như một đoạn văn trôi nổi phía dưới. Input không tự làm được vì nó không biết id của nó sẽ là gì, và Label không tự làm được vì nó không biết id nào để trỏ htmlFor vào. Việc sinh một id chung và nối aria-describedby không thuộc về primitive nào trong hai primitive đó — nó thuộc về thứ chứa cả hai, và đó chính là composite này.

Khi nào sử dụng

Nên dùng

Mọi hàng biểu mẫu một dòng — tên, email, tên workspace, mã số. Khi ô nhập cần một gợi ý thường trực (hint), một dòng kiểm tra sống (status) hoặc một thông báo lỗi ở mức field (error). Khi caller không muốn tự quản lý id — đây là ca mặc định.

Khi nào không dùng

Tránh dùng

Không dùng choDùng thay
Ô nhập không nhãn trong một control lớn hơn — ô tìm kiếm, ô lọc cột bảngInput trực tiếp, với aria-label
Mật khẩuPasswordField — thêm nút hiện/ẩn và luật autoComplete
Mã OTPOtpInput — thêm lọc chữ số, inputMode và one-time-code
Vùng văn bản nhiều dòngTextarea cộng Label. Field bọc Input, không bọc Textarea
Banner lỗi ở mức biểu mẫu, không ở mức fieldFormError

Dựng từ

Primitive tầng 1Vai trong composite
LabelNhãn, nhận htmlFor bằng id đã giải quyết.
InputÔ nhập. FieldProps mở rộng InputProps nên mọi prop của Input đi xuyên qua.
Field thêm gì mà không primitive nào có
Một id chung: do caller truyền, nếu không thì useId()
aria-describedby trỏ ${id}-note — chỉ khi thật sự có error, status hoặc hint
aria-invalid bật khi error có giá trị, hoặc khi status đang hiện và statusInvalid
Luật loại trừ: error che status, status che hint
status render role="status", hoặc role="alert" khi statusInvalid. Màu theo statusTone

Anatomy

#PhầnGhi chú
1LabelhtmlFor bằng id đã giải quyết.
2Inputid, aria-describedby, aria-invalid khi có error hoặc statusInvalid.
3Ghi chú (p)id=${id}-note, chỉ render khi có error, status hoặc hint. Một dòng.

Ba phần theo thứ tự dọc. Không có biến thể nằm ngang — một nhãn đặt cạnh ô là quyết định layout của biểu mẫu, không phải của field.

States

DEFAULT

Không error, không hint. Không có aria-describedby.

CÓ GỢI Ý

Dùng tên bạn muốn khách hàng nhìn thấy.

aria-invalid không bật.

ĐANG KIỂM TRA

Đang kiểm tra…

role=status. aria-invalid không bật.

CÒN TRỐNG

Địa chỉ này chưa ai dùng.

role=status, tone success.

ĐÃ DÙNG

role=alert, aria-invalid="true".

LỖI

Tên workspace là bắt buộc.

aria-invalid="true". status và hint bị che.

DISABLED

Kế thừa nguyên từ Input — Field không thêm hay ghi đè.

Hover, focus, read-only: kế thừa nguyên từ Input, Field không ghi đè. Dòng đang kiểm tra là status, host truyền câu chữ, Field giữ role và màu.

Bàn phím & trợ năng

Tab vào ô, Tab ra -- đến từ Input.
Bấm vào nhãn để tiêu điểm nhảy vào ô -- hành vi của Label + htmlFor, nhưng Field là nơi khớp htmlFor với id nên hành vi đó thật sự chạy.
Field không thêm một phím nào của riêng nó -- nó chỉ làm cho một hành vi kế thừa hoạt động đúng.

Seam — host sở hữu gì

Field không xác thực, không debounce, không gọi gì, và không biết biểu mẫu của nó nộp đi đâu. Theo ADR-UI-003 clause 2 nó không fetch, không đọc router, không giữ session và không import gì từ next.

Host sở hữuCấp qua
Giá trị và mọi thay đổivalue / onChange, hoặc để Input chạy uncontrolled
Chuỗi lỗi, và khi nào nó xuất hiệnerror
Câu chữ dòng kiểm tra sốngstatus. Field không debounce và không gọi kiểm tra
Màu dòng đó, và ô có invalid khôngstatusTone, statusInvalid
Chuỗi gợi ý thường trựchint
Ký tự đứng đầu trong ôprefix
Việc nộp biểu mẫu, xác thực phía server<form> của host cộng FormError
id cố định, khi host cần trỏ tới ô từ nơi khácid

Trạng thái duy nhất Field tự giữ là useId() — một định danh, không phải dữ liệu.

API & triển khai

PropMặc địnhQuy ước
label—Bắt buộc. Không có biến thể nhãn ẩn: dùng Input với aria-label nếu cần.
hintundefinedBị status hoặc error che.
errorundefinedCó giá trị ⇒ aria-invalid="true". Che status và hint.
statusundefinedDòng kiểm tra sống. Host sở hữu câu chữ. Chuỗi rỗng không render.
statusTonemutedmuted | success | danger. Chỉ khi status đang hiện.
statusInvalidfalseKhi status đang hiện: role="alert" và aria-invalid="true".
statusMarkundefinedpending = spinner, ready = check đặc. Đổi bằng opacity trong 180ms.
prefixundefinedaria-hidden, căn trái trong ô.
iduseId()Truyền khi host cần một id biết trước.
classNameundefinedĐi vào Input, không vào div bọc ngoài.
…InputProps—type, placeholder, required, disabled, autoComplete, value, onChange, … đi xuyên qua.

Design tokens

Field đọc --nf-component-auth-field-gap cho khoảng cách dọc, --nf-foundation-typography-caption-font-size cho cỡ chữ ghi chú, --nf-semantic-text-muted cho gợi ý và status muted, --nf-semantic-status-success-foreground cho status success, --nf-semantic-status-danger-foreground cho lỗi và status danger. Lỗ hổng đặt tên, ghi ra thay vì che: --nf-component-auth-field-gap nằm trong nhóm component.auth.* dù Field không còn là composite của auth từ ADR-UI-005 clause 5. Alias đúng là component.field.gap; đổi tên là 10 theme cộng một lần regenerate, theo dõi ở dòng ledger W10.19. Tên trong bảng trên là tên thật sự có trong CSS hôm nay.

Do / Don't

Nên dùng

Để Field sinh id. Truyền error là chuỗi người đọc hiểu được. Dùng hint cho luật thường trực. Dùng status cho dòng kiểm tra sống. Nhớ className đi vào Input. Để error che status, status che hint.

Tránh dùng

Tự nối htmlFor và aria-describedby ở call site. Tự dựng <p role="status"> dưới ô. Truyền error={true} rồi trông đợi một chuỗi mặc định — không có chuỗi mặc định. Dùng hint để báo lỗi. Truyền className mong đổi khoảng cách của cả khối. Trông đợi thấy hai dòng ghi chú cùng lúc.