Choice
مجموعة أزرار اختيار أو مربعات اختيار: كل عنصر هو `<input>` و`<label>` المرتبط به ولوحة اختيارية.
0 kB client JS≤ 0.8 kB gzipped
Anatomy
<Choice.Group id="plan" kind="single" orientation="horizontal">
<Choice.Item defaultChecked groupId="plan" kind="single" label="Free" value="free" />
<Choice.Item
groupId="plan"
kind="single"
label="Pro"
panel={<p>Everything in Free, plus...</p>}
value="pro"
/>
</Choice.Group>Live demo
This demo also runs with JavaScript disabled.
Choice
Minimal — single
Composition — multiple with panels
Adds 50 GB of storage to your plan.
Not available on your current plan.
Choice.Group
Renders <div>. Emits data-orientation, data-uiify-choice="".
| Name | Type | Default | Notes |
|---|---|---|---|
id | string | Required. Seeds every child item's derived ids and form-control name; must be stable across SSR. | |
kind | "single" | "multiple" | `single` renders `type="radio"` items, `multiple` renders `type="checkbox"`. | |
orientation | "horizontal" | "vertical" | "horizontal" | Emits `data-orientation`. |
name | string | Documents the `choiceGroupName(id, kind)` override each item must also receive; the group does not read it. |
Choice.Item
Renders <div> wrapping <input> + <label> + optional panel <div>. Emits data-part (default "item"), data-uiify-choice="".
| Name | Type | Default | Notes |
|---|---|---|---|
value | string | Required. | |
label | ReactNode | Required. Rendered inside the `<label>`. | |
panel | ReactNode | Renders an always-present `<div data-part="panel">` after the label; reveal it with `:checked ~ [data-part=panel]`. | |
groupId | string | Required. The `Choice.Group.id` this item belongs to. | |
kind | "single" | "multiple" | Required. Must match the group's `kind`. | |
name | string | Overrides the derived `choiceGroupName(groupId, kind)` form-control name. | |
defaultChecked | boolean | false | The browser owns the state after first render. |
disabled | boolean | false | On the input; `data-disabled` on the wrapper. |
part | string | "item" | Wrapper `data-part` (custom choice consumers use `"step"`). |
labelPart | boolean | false | Adds `data-part="label"` to the label. |
inputProps / labelProps / panelProps | Record<string, unknown> | Escape hatch: extra attributes spread onto the input/label/panel. | |
onValueChange | (value: string) => void | Listens to the input's native `change`. Only client callers can pass it; uncontrolled server callers omit it. |
Rendered DOM
<div id="plan" data-orientation="horizontal" data-uiify-choice=""><div data-part="item" data-uiify-choice=""><input aria-labelledby="plan-label-free" id="plan-control-free" type="radio" name="plan" checked="" value="free"/><label for="plan-control-free" id="plan-label-free">Free</label></div><div data-part="item" data-uiify-choice=""><input aria-labelledby="plan-label-pro" id="plan-control-pro" type="radio" name="plan" value="pro"/><label for="plan-control-pro" id="plan-label-pro">Pro</label><div data-part="panel" id="plan-panel-pro"><p>Everything in Free, plus...</p></div></div></div>CSS contract
[data-part=panel] {
display: none;
}
input:checked ~ [data-part=panel] {
display: block; /* the panel is always in the DOM — reveal it per item */
}Build your own
import { Choice } from "@gunkin/uiify/elements/choice";
const filters = ["Open", "Closed", "Archived"];
export function FilterChips() {
return (
<Choice.Group id="status-filter" kind="multiple" orientation="horizontal">
{filters.map((filter) => (
<Choice.Item
groupId="status-filter"
key={filter}
kind="multiple"
label={filter}
value={filter.toLowerCase()}
/>
))}
</Choice.Group>
);
}
Used by
Gotchas
- `Choice.Group.id` seeds every child's derived ids and form-control name — it must be unique and stable across SSR, and every `Choice.Item` needs the matching `groupId`.
- There is no `Choice.Group` → `Choice.Item` context — `groupId` and `kind` are required on every item, not inherited.
- The panel is always in the DOM when given — revealing it only when checked is a CSS rule you write, not something the element does for you.
Import
import { Choice } from "@gunkin/uiify/elements/choice";