From cc91e99a5d196b6c10cef5b14c868caae1e76af8 Mon Sep 17 00:00:00 2001 From: Andreas Reinhold / reini Date: Mon, 14 Sep 2026 06:24:02 +0200 Subject: [PATCH] Say how M3 wants a checkbox group laid out at expanded MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit M3 § Checkbox, Behaviour asks that from expanded (840px) related checkboxes be gathered into a contained region rather than left as one long column. That is a rule about the page around the control, not about the control, so it is written down rather than built: the component's header and its SKILL.md entry now say it, and the showcase lays a group out in an `expanded:grid-cols-2` card (plan step 24, audit docs/audits/m3-alignment/inputs.md § Missing). Co-Authored-By: Claude Fable 5.1 Claude-Session: https://claude.ai/code/session_01Qwx5USif3wFFmxtHg5U1g9 --- .../livewire-material-development/SKILL.md | 2 +- resources/views/components/checkbox.blade.php | 8 ++++++- .../views/showcase/sections/fields.blade.php | 17 ++++++++++++++ tests/Feature/Components/SelectionTest.php | 23 +++++++++++++++++++ 4 files changed, 48 insertions(+), 2 deletions(-) diff --git a/resources/boost/skills/livewire-material-development/SKILL.md b/resources/boost/skills/livewire-material-development/SKILL.md index 74511648..56e114af 100644 --- a/resources/boost/skills/livewire-material-development/SKILL.md +++ b/resources/boost/skills/livewire-material-development/SKILL.md @@ -565,7 +565,7 @@ M3 text fields. `variant`: `outlined` or `filled`; without it, `config('livewire M3 selection controls on native inputs; the whole row is the label. -- `` — `indeterminate` for a "select all" whose items are partly ticked (bind it to a server expression; it follows every render). +- `` — `indeterminate` for a "select all" whose items are partly ticked (bind it to a server expression; it follows every render). Grouping is yours: from `expanded` (840px) M3 wants a set of related checkboxes gathered into a contained region rather than one long column, so wrap the set in `
` (or a card or side sheet) under a heading that names what the group asks. - `` — options `['id', 'name', 'hint', 'disabled']` (`option-value`, `option-label`, `option-hint`); `value` checks an option without `wire:model`; `name` names an unbound group. M3 stacks radios and cautions against a row at any width, so reach for `inline` only for two or three short labels; it also wants five options or fewer and one of them chosen when the page loads. - `` — M3 switch (`role="switch"`); `icons` puts a check and a cross on the handle, `icons="selected"` only the check. Without `label`, pass `aria-label`. diff --git a/resources/views/components/checkbox.blade.php b/resources/views/components/checkbox.blade.php index 150d0a28..9aaea1f8 100644 --- a/resources/views/components/checkbox.blade.php +++ b/resources/views/components/checkbox.blade.php @@ -10,7 +10,13 @@ (resources/css/components/selection.css). Without a label — a "select all" in a table header, a row's tick — the row is only the 18px box, - so the box carries `touch-target` and catches presses over M3's 48px minimum. --}} + so the box carries `touch-target` and catches presses over M3's 48px minimum. + + Grouping is the caller's, not this component's: M3 asks that from `expanded` (840px) a set of + related checkboxes be gathered into a contained region rather than left as one long column + (docs/reference/m3/components-navigation-selection-inputs.md § Checkbox, Behaviour). Lay the + group out yourself — `
` around the checkboxes, or a + `` or side sheet holding them — and give the group a heading that names what it asks. --}} @props([ 'label' => null, diff --git a/resources/views/showcase/sections/fields.blade.php b/resources/views/showcase/sections/fields.blade.php index 8dba5072..0ae1bbed 100644 --- a/resources/views/showcase/sections/fields.blade.php +++ b/resources/views/showcase/sections/fields.blade.php @@ -92,6 +92,23 @@
BLADE, + 'A checkbox group at expanded' => <<<'BLADE' + {{-- M3: from expanded (840px), gather related checkboxes into a contained region instead of one long column. --}} + +
+ Tell me about + +
+ + + + + + +
+
+
+ BLADE, 'Radio buttons' => <<<'BLADE'
diff --git a/tests/Feature/Components/SelectionTest.php b/tests/Feature/Components/SelectionTest.php index d25d5d85..b7e083e7 100644 --- a/tests/Feature/Components/SelectionTest.php +++ b/tests/Feature/Components/SelectionTest.php @@ -37,6 +37,29 @@ it('gives a selection control without a label a 48px target', function () { ->and((string) $this->blade(''))->not->toContain('touch-target'); }); +it('leaves a checkbox group to the caller and says how M3 wants it laid out', function () { + $html = (string) $this->blade(<<<'BLADE' +
+ Tell me about +
+ + +
+
+ BLADE); + + expect($html) + ->toContain('class="grid gap-4 expanded:grid-cols-2"') + ->toContain('Downloads') + ->toContain('Comments') + ->and(substr_count($html, 'data-checkbox'))->toBe(2); + + // The rule is guidance, not markup, so the component's header has to carry it. + expect(file_get_contents(__DIR__.'/../../../resources/views/components/checkbox.blade.php')) + ->toContain('expanded') + ->toContain('contained region'); +}); + it('puts a checkbox at the end of its row on request', function () { expect((string) $this->blade(''))->toContain('flex-row-reverse justify-between'); });