ChoiceCardGroup
Mẫu chuẩnMột nhóm lựa chọn loại trừ nhau, mỗi lựa chọn là một thẻ gồm tiêu đề, mô tả và icon tuỳ chọn. Nó báo một giá trị qua một callback. Dựng trên RadioGroup và Card. AccountTypePicker của auth là một lớp mỏng trên composite này.
Playground
Chọn một thẻ, hoặc đổi layout để xem grid so với stack.
Đang chọn: Chỉ nháp
import { ChoiceCardGroup } from "@nexobox/ui";
const [value, setValue] = useState("draft-only");
<ChoiceCardGroup
options={[
{ value: "draft-only", icon: UserIcon, title: "Chỉ nháp", description: "Mọi câu trả lời chờ bạn duyệt." },
{ value: "supervised", icon: Building02Icon, title: "Có giám sát", description: "Việc rủi ro thấp tự gửi." },
]}
value={value}
onValueChange={setValue}
aria-label="Giới hạn quyền của Human AI"
layout="grid"
/>Bài toán
Khi các lựa chọn khác nhau về hệ quả, mỗi cái cần một câu giải thích: "Chỉ nháp: mọi câu trả lời chờ bạn duyệt". Một RadioGroup với nhãn một dòng không chứa được lời giải thích đó, và ghép tay Card quanh từng radio thì vùng nhấn, tiêu điểm và trạng thái chọn sẽ lệch nhau giữa các màn hình.
Khi nào sử dụng
Nên dùng
2 đến 5 lựa chọn loại trừ nhau, mỗi cái cần một câu mô tả. Lựa chọn mà người dùng cần thấy hết cùng lúc để so sánh.
Khi nào không dùng
Tránh dùng
| Không dùng cho | Dùng thay |
|---|---|
| Lựa chọn nhãn ngắn, không cần mô tả | RadioGroup |
| Chọn nhiều | CheckboxCardGroup |
| Trên năm lựa chọn | Select hoặc Combobox |
Dựng từ
| Primitive tầng 1 | Vai trong composite |
|---|---|
| RadioGroup, RadioGroupItem | Hành vi chọn một, điều hướng bằng mũi tên (Radix) |
| Card | Khung của mỗi lựa chọn |
| ChoiceCardGroup thêm gì |
|---|
| Cả thẻ là vùng nhấn; radio nằm trong thẻ |
Trạng thái chọn hiện bằng Interaction Blue trên viền (action-selected-foreground) và nền (action-selected-background), không chỉ trên chấm radio |
| Tiêu đề, mô tả, icon, và một dòng phụ tuỳ chọn cho mỗi lựa chọn |
Anatomy
| # | Phần | Ghi chú |
|---|---|---|
| 1 | Radio | RadioGroupItem, đầu thẻ |
| 2 | Icon | Tuỳ chọn, cạnh tiêu đề |
| 3 | Tiêu đề | title, kiểu chữ ui |
| 4 | Mô tả | description, tuỳ chọn, dưới tiêu đề |
States
| Trạng thái | Biểu hiện |
|---|---|
| Không chọn / chọn | data-state của Radix trên item; thẻ đổi viền và nền |
| Hover | Nền surface-hover trên thẻ chưa chọn |
| Focus | Vòng focus trên thẻ (tiêu điểm nằm ở radio, thẻ vẽ vòng qua focus-within) |
| Disabled (một lựa chọn) | Thẻ mờ, không nhấn được, mô tả vẫn đọc được |
Bàn phím & trợ năng
Seam — host sở hữu gì
Composite không biết ý nghĩa của lựa chọn và không xác nhận thay đổi. Nếu một lựa chọn có hệ quả cần xác nhận, host mở AlertDialog trước khi gọi callback của mình.
API & triển khai
| Prop | Mặc định | Quy ước |
|---|---|---|
| options | — | Bắt buộc. 2–5 mục. |
| value | — | Bắt buộc. |
| onValueChange | — | Bắt buộc. |
| aria-label | — | Bắt buộc. |
| layout | "grid" | "grid" | "stack". |
| name | undefined | Cho form gốc. |
options[].icon nhận cùng kiểu icon mà Icon nhận (IconProps["icon"]), không phải kiểu IconSvgElement mà bản nháp đầu của contract này ghi -- đó là kiểu của thư viện icon gốc, còn repo bọc icon qua Icon với kiểu riêng của nó.
Design tokens
--nf-semantic-action-selected-foreground (viền chọn), --nf-semantic-action-selected-background (nền chọn), --nf-semantic-border-control (viền nghỉ), --nf-semantic-border-strong (viền hover), --nf-semantic-surface-hover, --nf-semantic-text-primary, --nf-semantic-text-secondary, --nf-foundation-typography-ui-*, --nf-foundation-typography-caption-*, --nf-foundation-space-2, --nf-foundation-space-3, --nf-component-focus-*. Qua Card và RadioGroup: token của hai primitive đó.
Do / Don't
Nên dùng
Mô tả nói hệ quả của lựa chọn. Host hỏi xác nhận trước một lựa chọn rủi ro. Dùng cho một quyết định có hệ quả.
Tránh dùng
Mô tả nhắc lại tiêu đề. Để composite tự mở dialog. Dùng cho một bộ lọc -- bộ lọc là FilterTabs.