Files
livewire-material/resources/views/components/checkbox.blade.php
T
Andreas Reinhold / reiniandClaude Opus 5 648a4cfe0f
tests / lint (push) Successful in 1m5s
tests / feature (8.4) (push) Successful in 1m9s
tests / feature (8.5) (push) Successful in 1m9s
tests / browser (chrome, chromium) (push) Successful in 3m19s
tests / browser (safari, webkit) (push) Successful in 5m0s
tests / browser (firefox, firefox) (push) Successful in 4m34s
Show a plain form field's errors under its name
Fields read their errors only under the wire:model name, so a Fortify
login form (name="email", no wire:model) never showed "These
credentials do not match". Without wire:model they now read the name,
turning brackets into dots.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01V9NnLxnPp8vaaurb3Z1MFy
2026-09-13 10:41:37 +02:00

65 lines
3.0 KiB
PHP

{{-- A checkbox, M3's: an 18px box that fills with primary when ticked, in a 40px state layer.
The label and its hint sit beside it and are its accessible name — the whole row is the
`<label>`, so either can be pressed. `right` puts the box at the end of the row, for a setting
read left to right. `indeterminate` shows the mixed state of a "select all" whose items are
partly ticked: HTML has no attribute for it, so the input is marked `data-indeterminate` and
resources/js/field.js keeps the property in step, on load and after every morph. Errors are
read from the bag under the `wire:model` name. Every other attribute reaches the `<input>`
(resources/css/components/selection.css). --}}
@props([
'label' => null,
'hint' => null,
'right' => false,
'indeterminate' => false,
])
@php
$model = $attributes->whereStartsWith('wire:model')->first();
$id = $attributes->get('id') ?? 'check-'.substr(md5($model.'|'.$label.'|'.$attributes->get('value')), 0, 12);
// A plain form's field is named, not bound: its errors are under its name (`files[]` `files`, `a[b]` `a.b`).
$errorKey = $model ?? (filled($attributes->get('name')) ? str_replace(['[]', '[', ']'], ['', '.', ''], (string) $attributes->get('name')) : null);
$messages = $errorKey !== null && isset($errors) ? \Illuminate\Support\Arr::flatten($errors->get($errorKey)) : [];
@endphp
<div {{ $attributes->only(['class', 'wire:key'])->class(['min-w-0']) }}>
<label for="{{ $id }}" data-selection @if ($messages !== []) data-invalid @endif @class([
'flex gap-4',
'items-start' => filled($hint),
'items-center' => blank($hint),
'flex-row-reverse justify-between' => $right,
])>
<span data-checkbox @class(['mt-[3px]' => filled($hint)])>
<input
{{ $attributes->except(['class', 'id', 'wire:key']) }}
id="{{ $id }}"
type="checkbox"
@if ($indeterminate) data-indeterminate @endif
@if ($messages !== []) aria-invalid="true" aria-describedby="{{ $id }}-support" @endif
/>
<x-livewire-material::icon name="check" class="size-4" data-check />
<x-livewire-material::icon name="remove" class="size-4" data-mixed />
</span>
@if (filled($label) || filled($hint))
<span class="min-w-0">
@if (filled($label))
<span class="block type-body-lg text-on-surface" data-selection-label>{{ $label }}</span>
@endif
@if (filled($hint))
<span class="mt-0.5 block type-body-sm text-on-surface-variant">{{ $hint }}</span>
@endif
</span>
@endif
</label>
@if ($messages !== [])
<div id="{{ $id }}-support" class="mt-1 type-body-sm text-error" role="alert">
@foreach ($messages as $message)
<p>{{ $message }}</p>
@endforeach
</div>
@endif
</div>