react.form.checkbox-group
A question answered by ticking any of several checkboxes, with item hints and an exclusive "None" (GOV.UK checkboxes).
React ^19 · TypeScript only A React component: use it from a TypeScript project with React installed. A client component ("use client").
1.0.1 · published 2026-10-03 by charlie · Anterra
Pinned by 24 tests, run in TypeScript.toggleValue 12 · CheckboxGroup 12
What it does
A question answered by ticking any number of checkboxes - "Which types of waste do you transport? Select all that apply" - inside a fieldset whose legend asks it. It is the GOV.UK Design System checkboxes component: item hints, an "or" divider and an exclusive "None of these" option included. `toggleValue` is the list arithmetic behind every click, a pure function you can also use on the server.
"use client";
import { CheckboxGroup } from "#fune/react.form.checkbox-group@^1";
<CheckboxGroup id="countries" legend="Will you travel to any of these countries?"
hint="Select all that apply" error={errors.countries}
values={countries} onChange={setCountries}
options={[
{ value: "france", label: "France" },
{ value: "portugal", label: "Portugal" },
{ value: "spain", label: "Spain" },
{ value: "none", label: "No, I will not be travelling to any of these countries", divider: "or", exclusive: true },
]} />
The functions
A group: 2 functions that work together, each in its own file, each pinned by its own tests, written for React ^19. A project can install only the ones it calls.
A React capability: React ^19 · TypeScript only. This capability has no Rust implementation, so it is shown in TypeScript. A Rust project cannot use it: fune build stops and names where it was required. Your choice of Rust is kept for every other page.
- toggleValue (options: CheckboxOption[], values: string[], value: string, checked: bool) -> string[]
- CheckboxGroup (props: CheckboxGroupProps) -> element
The types it declares, generated into your project
/** One checkbox in a group. */
export interface CheckboxOption {
/** what is submitted when it is ticked */
readonly value: string;
/** shown to the right of the box */
readonly label: ReactNode;
/** help under the label, describing this checkbox only */
readonly hint?: ReactNode;
/** shown but not changeable */
readonly disabled?: boolean;
/** shown between this option and the one before, such as "or" */
readonly divider?: ReactNode;
/** ticking it clears every other option, and ticking another clears it: "None of these" */
readonly exclusive?: boolean;
}
/** A question with several answers, any number of which may be ticked. */
export interface CheckboxGroupProps {
/** the question the group asks */
readonly legend: ReactNode;
/** the checkboxes, in order */
readonly options: readonly CheckboxOption[];
/** the first checkbox's id; the others are <id>-2, <id>-3 ...; React's useId() when left out */
readonly id?: string;
/** what every checkbox is submitted as; the id when left out */
readonly name?: string;
/** the ticked values, for a controlled group (with onChange) */
readonly values?: readonly string[];
/** the values ticked at first, for an uncontrolled one */
readonly defaultValues?: readonly string[];
/** called with every ticked value, in the options' order, after each change */
readonly onChange?: (value: readonly string[]) => void;
/** called when any checkbox in the group loses focus, to mark the field touched */
readonly onBlur?: () => void;
/** help under the legend, such as "Select all that apply" */
readonly hint?: ReactNode;
/** what is wrong with the answer; describes the whole group */
readonly error?: ReactNode;
/** the legend is the page's heading */
readonly isPageHeading?: boolean;
/** smaller checkboxes, for a filter or a dense page */
readonly small?: boolean;
/** every checkbox is shown but not changeable */
readonly disabled?: boolean;
/** added to the wrapper's classes */
readonly className?: string;
}
Once installed, your code imports each one from the group's module.
toggleValue throws on bad input 12 tests
export function toggleValue(options: readonly CheckboxOption[], values: readonly string[], value: string, checked: boolean): readonly string[]
| options | CheckboxOption[] | the group's options, in the order they are shown |
| values | string[] | the values ticked before the change |
| value | string | the option that was ticked or cleared |
| checked | bool | true when it was ticked, false when it was cleared |
| returns | string[] | the values ticked after the change, in the options' order, each once |
For example
toggleValue(options ×3, , a, true)→ a ticking the first boxtoggleValue(options ×3, c, a, true)→ a, c ticking keeps the options' order, not the click ordertoggleValue(options ×3, a, b, c, b, false)→ a, c clearing a box removes only it
import { toggleValue } from "#fune/react.form.checkbox-group@^1";
import type { CheckboxOption } from "./react_form_checkbox_group_types.ts";
/**
* The ticked values after one checkbox changes. The answer is always in the
* options' order, whatever order the boxes were ticked in, and holds each
* value once, so a form posts the same list for the same ticks. A value that
* is not an option any more (the options changed) drops out. An exclusive
* option ("None of these") cannot be ticked alongside anything else: ticking
* it clears the rest, and ticking another clears it (GOV.UK's
* data-behaviour="exclusive").
*/
export function toggleValue(options: readonly CheckboxOption[], values: readonly string[], value: string, checked: boolean): readonly string[] {
const option = options.find((o) => o.value === value);
if (option === undefined) throw new Error(`"${value}" is not one of the checkbox options`);
let next: Set<string>;
if (!checked) {
next = new Set(values.filter((v) => v !== value));
} else if (option.exclusive) {
next = new Set([value]);
} else {
const exclusive = new Set(options.filter((o) => o.exclusive).map((o) => o.value));
next = new Set([...values.filter((v) => !exclusive.has(v)), value]);
}
const out: string[] = [];
for (const o of options) if (next.has(o.value) && !out.includes(o.value)) out.push(o.value);
return out;
}CheckboxGroup 12 tests
export function CheckboxGroup(props: CheckboxGroupProps): JSX.Element
Its props, CheckboxGroupProps. A ? marks one the caller may leave out.
| legend | ReactNode | the question the group asks |
| options | readonly CheckboxOption[] | the checkboxes, in order |
| id? | string | the first checkbox's id; the others are <id>-2, <id>-3 ...; React's useId() when left out |
| name? | string | what every checkbox is submitted as; the id when left out |
| values? | readonly string[] | the ticked values, for a controlled group (with onChange) |
| defaultValues? | readonly string[] | the values ticked at first, for an uncontrolled one |
| onChange? | (value: readonly string[]) => void | called with every ticked value, in the options' order, after each change |
| onBlur? | () => void | called when any checkbox in the group loses focus, to mark the field touched |
| hint? | ReactNode | help under the legend, such as "Select all that apply" |
| error? | ReactNode | what is wrong with the answer; describes the whole group |
| isPageHeading? | boolean | the legend is the page's heading |
| small? | boolean | smaller checkboxes, for a filter or a dense page |
| disabled? | boolean | every checkbox is shown but not changeable |
| className? | string | added to the wrapper's classes |
| renders | JSX.Element |
For example
-
a legend and three checkboxes: the first takes the id, the rest -2 and -3
<CheckboxGroup id="waste" legend="Which types of waste do you transport?" options={[{"value":"carcasses","label":"Waste from animal carcasses"},{"value":"mines","label":"Waste from mines or quarries"},{"value":"farm","label":"Farm or agricultural waste"}]} />renders
<div class="fune-field"><fieldset class="fune-fieldset"><legend class="fune-legend">Which types of waste do you transport?</legend><div class="fune-checkboxes"><div class="fune-checkbox"><input class="fune-checkbox-input" id="waste" type="checkbox" name="waste" value="carcasses"/><label class="fune-label fune-checkbox-label" for="waste">Waste from animal carcasses</label></div><div class="fune-checkbox"><input class="fune-checkbox-input" id="waste-2" type="checkbox" name="waste" value="mines"/><label class="fune-label fune-checkbox-label" for="waste-2">Waste from mines or quarries</label></div><div class="fune-checkbox"><input class="fune-checkbox-input" id="waste-3" type="checkbox" name="waste" value="farm"/><label class="fune-label fune-checkbox-label" for="waste-3">Farm or agricultural waste</label></div></div></fieldset></div> -
controlled values tick their boxes
<CheckboxGroup id="c" name="colours" legend="Colours" values={["blue"]} options={[{"value":"red","label":"Red"},{"value":"blue","label":"Blue"}]} />renders
<div class="fune-field"><fieldset class="fune-fieldset"><legend class="fune-legend">Colours</legend><div class="fune-checkboxes"><div class="fune-checkbox"><input class="fune-checkbox-input" id="c" type="checkbox" name="colours" value="red"/><label class="fune-label fune-checkbox-label" for="c">Red</label></div><div class="fune-checkbox"><input class="fune-checkbox-input" id="c-2" type="checkbox" name="colours" checked="" value="blue"/><label class="fune-label fune-checkbox-label" for="c-2">Blue</label></div></div></fieldset></div>
import { CheckboxGroup } from "#fune/react.form.checkbox-group@^1";
Imports name this capability’s declared dependencies, which fune builds next to it in your project; each one links to its page.
"use client";
import { Fragment, useId, useState, type JSX, type ReactNode } from "react";
import { Fieldset } from "./react_form_fieldset.ts"; ← from react.form.fieldset ^1.0.0 · built alongside by fune
import { toggleValue } from "./react_form_checkbox_group_toggle_value.ts"; ← toggleValue, another function of this group · built into the same file, even by a slim install
import type { CheckboxGroupProps } from "./react_form_checkbox_group_types.ts";
function present(node: ReactNode): boolean {
return node !== null && node !== undefined && node !== false && node !== "";
}
/**
* GOV.UK checkboxes: a fieldset whose legend asks the question, its hint and
* error describing the whole group, then one checkbox per option. The first
* checkbox takes the id, so an error summary's link lands on it, and the
* rest are <id>-2, <id>-3...; the group's hint and error are <id>-hint and
* <id>-error. Every box is controlled from one list,
* held here when the caller passes defaultValues, so onChange always gets
* the whole list from toggleValue.
*/
export function CheckboxGroup(props: CheckboxGroupProps): JSX.Element {
const auto = useId();
const { legend, options, values, defaultValues, onChange, onBlur, hint, error, isPageHeading, small, disabled, className } = props;
const id = props.id ?? auto;
const name = props.name ?? id;
const [own, setOwn] = useState<readonly string[]>(defaultValues ?? []);
if (options.length === 0) throw new Error("a checkbox group needs at least one option");
const seen = new Set<string>();
for (const o of options) {
if (seen.has(o.value)) throw new Error(`checkbox option values must be unique: "${o.value}" is there twice`);
seen.add(o.value);
}
const current = values ?? own;
const change = (value: string, checked: boolean) => {
const next = toggleValue(options, current, value, checked);
if (values === undefined) setOwn(next);
onChange?.(next);
};
return (
<Fieldset id={id} legend={legend} hint={hint} error={error} isPageHeading={isPageHeading} className={className}>
<div className={small ? "fune-checkboxes fune-checkboxes--small" : "fune-checkboxes"}>
{options.map((o, i) => {
const itemId = i === 0 ? id : `${id}-${i + 1}`;
const hintId = present(o.hint) ? `${itemId}-item-hint` : undefined;
return (
<Fragment key={o.value}>
{present(o.divider) ? <div className="fune-checkboxes-divider">{o.divider}</div> : null}
<div className="fune-checkbox">
<input
className="fune-checkbox-input"
id={itemId}
name={name}
type="checkbox"
value={o.value}
checked={current.includes(o.value)}
disabled={disabled || o.disabled}
aria-describedby={hintId}
data-behaviour={o.exclusive ? "exclusive" : undefined}
onBlur={onBlur ? () => onBlur() : undefined}
onChange={(event) => change(o.value, event.target.checked)}
/>
<label className="fune-label fune-checkbox-label" htmlFor={itemId}>
{o.label}
</label>
{hintId ? (
<div className="fune-hint fune-checkbox-hint" id={hintId}>
{o.hint}
</div>
) : null}
</div>
</Fragment>
);
})}
</div>
</Fieldset>
);
}Install
npm install react react-dom
fune build
With that line in your source, in a TypeScript project (language typescript in fune.project) with React ^19 installed (Functional Weave does not ship it, and fune build stops with the npm install line if it is missing), fune build resolves it and its 1 dependency, pins them in fune.lock, downloads only the TypeScript package of each, and builds the code above into your project’s .fune/build, one readable file per capability with a header linking back here. Or pin a range in fune.project and build in one step:
fune add react.form.checkbox-group
That builds the whole group. To build only what you call, and whatever it uses inside the group:
fune add react.form.checkbox-group --only toggleValue
The manifest, vectors and README with only the TypeScript implementation. Install it without the registry with fune add ./react.form.checkbox-group-1.0.1-typescript.fune, or fetch it from a terminal with fune pull react.form.checkbox-group@1.0.1:typescript.
It is React ^19 · TypeScript only, so there is no package for Python or Rust. The full package is one file too: react.form.checkbox-group-1.0.1.fune, 30,539 bytes, sha256 963bedc570f4f5372600ea3f65c2cfd809c700eb96f382a75842021a62ee99a7.
Customise it in your app
The seams this capability offers. Put a marker directly above a function of your own and fune build wires it into the built code; the package on the registry is not changed, the built file’s header lists it under CUSTOMISED, and fune hooks lists every hook in the project. How hooks work.
before — your function gets the arguments and returns them, changed or not, or throws to refuse the call.
// fune: before react.form.checkbox-group.toggleValue
// fune: before react.form.checkbox-group.CheckboxGroup
after — your function gets the result and the arguments, and returns the final result.
// fune: after react.form.checkbox-group.toggleValue
// fune: after react.form.checkbox-group.CheckboxGroup
replace — inside this capability’s code only, calls to a dependency go to your function, with the same signature. Other capabilities that use it are unaffected; write in * to replace it everywhere.
// fune: replace react.form.fieldset in react.form.checkbox-group
step — your function runs at a numbered point inside a function’s body, receives the in-scope values it names as parameters, and may return replacements. List the points with fune show react.form.checkbox-group --steps.
// fune: step react.form.checkbox-group.<fn> after <n|label>
Tests
A version published now needs at least 8 tests for every function, and one that expects the error for each function that throws; the registry refuses it otherwise. fune verify --all runs each case in TypeScript alone, with the React in tooling/react, and a project runs them again with fune verify. This page lists the cases; it does not run them. The exact JSON is vectors.json. A component’s tests are render tests: the props go in, and the HTML renderToStaticMarkup makes of them has to match exactly; a React warning during the render fails the test.
toggleValue 12 tests
| Case | Arguments | Expected | |
|---|---|---|---|
| ticking the first box | options ×3, , a, true | → | a |
| ticking keeps the options' order, not the click order | options ×3, c, a, true | → | a, c |
| clearing a box removes only it | options ×3, a, b, c, b, false | → | a, c |
| clearing the last box leaves an empty list | options ×2, b, b, false | → | |
| ticking a box already ticked lists it once | options ×2, b, a, a, true | → | a, b |
| clearing a box that was not ticked only puts the list in order | options ×3, c, a, b, false | → | a, c |
| duplicates and values no longer offered drop out | options ×2, b, old, b, a, false | → | b |
| ticking the exclusive None clears every other box | options ×3, france, spain, none, true | → | none |
| ticking another box clears the exclusive None | options ×3, none, spain, true | → | spain |
| clearing the exclusive None leaves nothing ticked | options ×2, none, none, false | → |
Show the other 2 tests
| Case | Arguments | Expected | |
|---|---|---|---|
| exclusive false is an ordinary option | options ×2, a, b, true | → | a, b |
| a value that is not an option is refused | options ×1, a, z, true | → | error: "z" is not one of the checkbox options |
CheckboxGroup 12 tests
-
a legend and three checkboxes: the first takes the id, the rest -2 and -3
<CheckboxGroup id="waste" legend="Which types of waste do you transport?" options={[{"value":"carcasses","label":"Waste from animal carcasses"},{"value":"mines","label":"Waste from mines or quarries"},{"value":"farm","label":"Farm or agricultural waste"}]} />renders
<div class="fune-field"><fieldset class="fune-fieldset"><legend class="fune-legend">Which types of waste do you transport?</legend><div class="fune-checkboxes"><div class="fune-checkbox"><input class="fune-checkbox-input" id="waste" type="checkbox" name="waste" value="carcasses"/><label class="fune-label fune-checkbox-label" for="waste">Waste from animal carcasses</label></div><div class="fune-checkbox"><input class="fune-checkbox-input" id="waste-2" type="checkbox" name="waste" value="mines"/><label class="fune-label fune-checkbox-label" for="waste-2">Waste from mines or quarries</label></div><div class="fune-checkbox"><input class="fune-checkbox-input" id="waste-3" type="checkbox" name="waste" value="farm"/><label class="fune-label fune-checkbox-label" for="waste-3">Farm or agricultural waste</label></div></div></fieldset></div> -
controlled values tick their boxes
<CheckboxGroup id="c" name="colours" legend="Colours" values={["blue"]} options={[{"value":"red","label":"Red"},{"value":"blue","label":"Blue"}]} />renders
<div class="fune-field"><fieldset class="fune-fieldset"><legend class="fune-legend">Colours</legend><div class="fune-checkboxes"><div class="fune-checkbox"><input class="fune-checkbox-input" id="c" type="checkbox" name="colours" value="red"/><label class="fune-label fune-checkbox-label" for="c">Red</label></div><div class="fune-checkbox"><input class="fune-checkbox-input" id="c-2" type="checkbox" name="colours" checked="" value="blue"/><label class="fune-label fune-checkbox-label" for="c-2">Blue</label></div></div></fieldset></div> -
default values tick their boxes too
<CheckboxGroup id="c" legend="Colours" defaultValues={["red","blue"]} options={[{"value":"red","label":"Red"},{"value":"blue","label":"Blue"}]} />renders
<div class="fune-field"><fieldset class="fune-fieldset"><legend class="fune-legend">Colours</legend><div class="fune-checkboxes"><div class="fune-checkbox"><input class="fune-checkbox-input" id="c" type="checkbox" name="c" checked="" value="red"/><label class="fune-label fune-checkbox-label" for="c">Red</label></div><div class="fune-checkbox"><input class="fune-checkbox-input" id="c-2" type="checkbox" name="c" checked="" value="blue"/><label class="fune-label fune-checkbox-label" for="c-2">Blue</label></div></div></fieldset></div> -
a hint describes the group; an item hint describes its own box
<CheckboxGroup id="nationality" legend="What is your nationality?" hint="Select all that apply" options={[{"value":"british","label":"British","hint":"including English, Scottish, Welsh and Northern Irish"},{"value":"irish","label":"Irish"}]} />renders
<div class="fune-field"><fieldset class="fune-fieldset" aria-describedby="nationality-hint"><legend class="fune-legend">What is your nationality?</legend><div class="fune-hint" id="nationality-hint">Select all that apply</div><div class="fune-checkboxes"><div class="fune-checkbox"><input class="fune-checkbox-input" id="nationality" type="checkbox" aria-describedby="nationality-item-hint" name="nationality" value="british"/><label class="fune-label fune-checkbox-label" for="nationality">British</label><div class="fune-hint fune-checkbox-hint" id="nationality-item-hint">including English, Scottish, Welsh and Northern Irish</div></div><div class="fune-checkbox"><input class="fune-checkbox-input" id="nationality-2" type="checkbox" name="nationality" value="irish"/><label class="fune-label fune-checkbox-label" for="nationality-2">Irish</label></div></div></fieldset></div> -
an error describes the fieldset, not each box
<CheckboxGroup id="n" legend="Nationality" error="Select your nationality" options={[{"value":"british","label":"British"},{"value":"irish","label":"Irish"}]} />renders
<div class="fune-field fune-field--error"><fieldset class="fune-fieldset" aria-describedby="n-error"><legend class="fune-legend">Nationality</legend><p class="fune-error-message" id="n-error"><span class="fune-visually-hidden">Error:</span> Select your nationality</p><div class="fune-checkboxes"><div class="fune-checkbox"><input class="fune-checkbox-input" id="n" type="checkbox" name="n" value="british"/><label class="fune-label fune-checkbox-label" for="n">British</label></div><div class="fune-checkbox"><input class="fune-checkbox-input" id="n-2" type="checkbox" name="n" value="irish"/><label class="fune-label fune-checkbox-label" for="n-2">Irish</label></div></div></fieldset></div> -
an exclusive None after an or divider
<CheckboxGroup id="countries" legend="Will you travel to any of these countries?" values={["none"]} options={[{"value":"france","label":"France"},{"value":"none","label":"No, none of these","divider":"or","exclusive":true}]} />renders
<div class="fune-field"><fieldset class="fune-fieldset"><legend class="fune-legend">Will you travel to any of these countries?</legend><div class="fune-checkboxes"><div class="fune-checkbox"><input class="fune-checkbox-input" id="countries" type="checkbox" name="countries" value="france"/><label class="fune-label fune-checkbox-label" for="countries">France</label></div><div class="fune-checkboxes-divider">or</div><div class="fune-checkbox"><input class="fune-checkbox-input" id="countries-2" type="checkbox" data-behaviour="exclusive" name="countries" checked="" value="none"/><label class="fune-label fune-checkbox-label" for="countries-2">No, none of these</label></div></div></fieldset></div> -
small, disabled options and the legend as page heading
<CheckboxGroup id="f" legend="Filter" isPageHeading small options={[{"value":"open","label":"Open"},{"value":"closed","label":"Closed","disabled":true}]} />renders
<div class="fune-field"><fieldset class="fune-fieldset"><legend class="fune-legend fune-legend--heading"><h1 class="fune-legend-heading">Filter</h1></legend><div class="fune-checkboxes fune-checkboxes--small"><div class="fune-checkbox"><input class="fune-checkbox-input" id="f" type="checkbox" name="f" value="open"/><label class="fune-label fune-checkbox-label" for="f">Open</label></div><div class="fune-checkbox"><input class="fune-checkbox-input" id="f-2" type="checkbox" disabled="" name="f" value="closed"/><label class="fune-label fune-checkbox-label" for="f-2">Closed</label></div></div></fieldset></div> -
disabled disables every box; a class name joins the wrapper's
<CheckboxGroup id="d" legend="Days" disabled className="wide" options={[{"value":"mon","label":"Monday"},{"value":"tue","label":"Tuesday","disabled":false}]} />renders
<div class="fune-field wide"><fieldset class="fune-fieldset"><legend class="fune-legend">Days</legend><div class="fune-checkboxes"><div class="fune-checkbox"><input class="fune-checkbox-input" id="d" type="checkbox" disabled="" name="d" value="mon"/><label class="fune-label fune-checkbox-label" for="d">Monday</label></div><div class="fune-checkbox"><input class="fune-checkbox-input" id="d-2" type="checkbox" disabled="" name="d" value="tue"/><label class="fune-label fune-checkbox-label" for="d-2">Tuesday</label></div></div></fieldset></div> -
labels and values are escaped
<CheckboxGroup id="e" legend="Q & A" options={[{"value":"a&b","label":"<A> & \"B\""}]} />renders
<div class="fune-field"><fieldset class="fune-fieldset"><legend class="fune-legend">Q & A</legend><div class="fune-checkboxes"><div class="fune-checkbox"><input class="fune-checkbox-input" id="e" type="checkbox" name="e" value="a&b"/><label class="fune-label fune-checkbox-label" for="e"><A> & "B"</label></div></div></fieldset></div> -
no options is refused
<CheckboxGroup id="x" legend="Pick" options={[]} />error: a checkbox group needs at least one option
Show the other 2 tests
-
two options with one value are refused
<CheckboxGroup id="x" legend="Pick" options={[{"value":"a","label":"A"},{"value":"a","label":"Also A"}]} />error: checkbox option values must be unique: "a" is there twice
-
an id with a space is refused
<CheckboxGroup id="my waste" legend="Waste" options={[{"value":"a","label":"A"}]} />error: a field id cannot contain spaces
More from the author
- **onChange** is called with every ticked value after each change, not with the event, and always in the options' order, whatever order they were ticked in. With **values** it is a controlled group; with **defaultValues** (or neither) the component keeps the list itself and still reports it. - **onBlur** is called, with nothing, when any box in the group loses focus, so a form can mark the question touched (`form.state`'s blur action). - **toggleValue(options, values, value, checked)** is that update. The result holds only the options' values, once each, in their order, so a stale value from an old option list drops out. Ticking an `exclusive` option clears the others and ticking another clears it, which is what GOV.UK's `data-behaviour="exclusive"` does in the browser; the input carries that attribute too. A value that is not an option is refused. - **Ids.** The first checkbox's id is the `id`, the rest `<id>-2`, `<id>-3`... as GOV.UK does, so an error summary linking to `#<id>` lands on the first box. Every box posts under **name** (the id when left out). An item hint is `<item id>-item-hint` and describes only its box. - **The group's hint and error** are `<id>-hint` and `<id>-error`, as on GOV.UK; the `<fieldset>` itself has no id (`react.form.fieldset` uses the id only to name them), so the first checkbox can have it. - **The error is the group's.** As on GOV.UK, the hint and error message describe the fieldset (announced once on entering the group), and no checkbox is marked `aria-invalid`: the mistake is in the answer as a whole. - **small** gives `fune-checkboxes--small`, for filters and dense pages. **disabled** disables every box; an option's own `disabled` disables it. - Option values must be unique (they are the React keys), and a group needs at least one option.
For one checkbox on its own ("I agree"), use `react.form.checkbox`. It is a client component (state and change listeners), so the built file starts with `"use client"`.
Classes: those of `react.form.fieldset`, plus `fune-checkboxes` (and `fune-checkboxes--small`), `fune-checkbox` (one box and its label), `fune-checkbox-input`, `fune-label fune-checkbox-label`, `fune-hint fune-checkbox-hint`, `fune-checkboxes-divider`.
Sources: GOV.UK Design System, "Checkboxes" (item ids, item hints, the "or" divider and the exclusive "none" option, small checkboxes, errors on the fieldset) https://design-system.service.gov.uk/components/checkboxes/ and "Fieldset" https://design-system.service.gov.uk/components/fieldset/.
## Notices
Portions derived from GOV.UK Frontend (https://github.com/alphagov/govuk-frontend), Copyright (c) 2017 Crown Copyright (Government Digital Service), under the MIT License; the full notice is in NOTICE.
1.0.1 adds its attribution notices (NOTICE). The code and the tests are unchanged.
Files
| Path | Bytes |
|---|---|
| NOTICE | 1,223 |
| README.md | 3,836 |
| impl/typescript/checkbox_group.tsx | 3,400 |
| impl/typescript/toggle_value.ts | 1,333 |
| vectors.json | 12,160 |