**Minor.** A new datetime picker picks a date and a time together, from a calendar and a list of times or typed into its field, as one moment or as a range, and opens as a modal on a phone. An image carries hotspots, markers that each name what they point at, with an editor that places them by click, drag or keyboard; a video player loads a file, a stream, YouTube or Vimeo only once the reader agrees; and an image editor crops with handles, the arrow keys or numbers. The date and the time picker open the same dialog with `popover`. A calendar takes limits and unavailable days, presets for a range, a today button, week numbers and a locale of its own, and a Livewire property typed with `DateRange` or `DateTimeRange` binds a range. ApexCharts 8 is a supported version of the chart. A map takes its style or its tiles from the config, so every map of an application loads them from its own server. A badge cuts a long label at one width and shows it whole in a tooltip, a table head takes the help for its column, and a product card's stars take a note. A list of checkboxes picks a range with Shift held, and a data table with selectable rows does it by itself. A bulk selection around a list of the application's own and a data table in server mode offer every match beyond the page, and an action bar says how many are selected. An entry of a command palette opens a page of values in the same palette, a palette takes the shortcut of another while it is on the page, as the palette of a selection does over a page's search, and the overview of keyboard shortcuts lists the hotkeys of the page's palettes. A form that Livewire does not send goes out once with `submit-once`, and the sign-in button of Apple shows its logo in the color of the button's words. A radio or a checkbox drawn as a card holds a description and an image in its frame, a sign-in button signs in with a passkey, and `wirekit:theme` derives success, danger and warning from brand colors as it does the accent. A heading takes `help`, the question mark that explains a page or a section, and a navbar takes a `menu` slot for what only its menu shows. A `kbd` draws a shortcut's keys for the reader's platform, ⌘ S or Ctrl S, and a tooltip draws the shortcut of its control. A card header takes buttons at its end and a sentence under its heading, a stat can be a toggle that sets the filter it counts, a menu entry carries a count at its end, a table column can give way only in a wide window, two taps on the quantity of a till line ask for a quantity, a countdown can be stopped, a save over a button in a card counts that card, the question before leaving names what is unsaved and asks before an ordinary link too, a link without an address can show its words as plain text, a translatable input reads as one field, WireKit writes its numbers in an application's own format where it gives one, and a series of a chart names its own decimals. A node of a tree view hands its `value` to the selection event, and an editor names the engine it opens in. The chevron of a collapsible card stands in a circle and closes an open card when clicked. On a phone, checkboxes and radios stand as far apart as on a desk, their boxes stand on the middle of the first line of their labels, and the select of the theme controller draws the chevron every other select of the kit draws. Inside a Livewire component, what the reader did survives an update: a tree's tab stop and closed branches, a split's size, a table's sort and a kanban board's announcements. On a short or narrow window a panel stays beside its trigger: a picker's dialog, the navigation menu, the popover, the color picker, the filter builder and the notification center are capped to the room there instead of lifted over the trigger, and a panel placed beside its trigger turns below or above it where neither side has room. A card's border takes the color of an intent, an aligned row wraps into lines that each line up on their controls, and a calendar takes `disabled` and `readonly`. A table stacks its rows below a width of its own with `stack-below-container`, and a stacked figure aligned to the end keeps its name; a chart offers its data as a table under it with `table`; an alert a Livewire render adds is announced; and the backdrop behind a dialog dims the page less.

### Security

- **A length, a ratio or a duration given to a component reaches its style as one value.** The `ratio` of an [aspect ratio](https://docs.wirekit.app/components/aspect-ratio), an [image](https://docs.wirekit.app/components/image) and an [image compare](https://docs.wirekit.app/components/image-compare), the `height` of a [chart](https://docs.wirekit.app/components/chart), a [mixed chart](https://docs.wirekit.app/components/chart-mixed), a [sparkline](https://docs.wirekit.app/components/sparkline) and a [map](https://docs.wirekit.app/components/map), the `max-height` of a [conversation](https://docs.wirekit.app/components/conversation), an [editor](https://docs.wirekit.app/components/editor) and a [scroll area](https://docs.wirekit.app/components/scroll-area), the `offset`, `max-height` and `width` of a [sticky panel](https://docs.wirekit.app/components/sticky-panel), the `width` and `list-max-height` of a [scope switcher](https://docs.wirekit.app/components/scope-switcher), the `width` of a [dropdown](https://docs.wirekit.app/components/dropdown) panel and of the [reading](https://docs.wirekit.app/components/reading) minimap, the `sticky-header-max` of a [table](https://docs.wirekit.app/components/table), the `logo-aspect` of a [brand](https://docs.wirekit.app/components/brand) and a [testimonial](https://docs.wirekit.app/components/testimonial) and the brand's `mobile-logo-aspect`, the `overlay` of a [lightbox](https://docs.wirekit.app/components/lightbox), the `offset` of an [indicator](https://docs.wirekit.app/components/indicator), the `duration` of a [shimmer](https://docs.wirekit.app/components/shimmer) and the `heat-from` and `heat-to` of a [status matrix](https://docs.wirekit.app/components/status-matrix) went into a `style` attribute as given. Escaping leaves a `;` alone, so a value from a request could carry declarations of its own and restyle the element. Each takes one value now: a length, a ratio, a duration, a color, or a function such as `calc()`, `min()` or `var()`. Anything else is reported while debugging and falls back to the prop's default.

- **The sandbox validator caps the elements of an array prop.** One prop's arrays hold at most 1 000 elements over all their levels together, refused like an oversized string or a nesting too deep, with the limit in the violation. A schema that allowed an array prop would otherwise have checked and rendered every entry of an array of any length.

### Added

- **New [image hotspots](https://docs.wirekit.app/components/image-hotspots) for an image that names what it shows.** `<x-wirekit::image-hotspots>` lays markers over an image at positions in percent, each a button named after its target that shows the name beside it on hover and focus, and a press sends `wirekit:image-hotspots-select` with the target, so the page decides what opens. A phone file takes positions of its own, and on the phone a strip under the image lists the targets as links.

- **New [image hotspots editor](https://docs.wirekit.app/components/image-hotspots-editor) that places the points of an image with hotspots.** `<x-wirekit::image-hotspots-editor>` sets a point with a click on the image or with its Add button, moves one by dragging, with the arrow keys or through its X and Y fields in the list beside the image, and orders and deletes the points there. Its value is the list `image-hotspots` takes as `markers`, bound with `wire:model` or `x-model`, and a drag writes it once, when the point is let go. With a phone file every point takes a position of its own on it, and selecting a point sends `wirekit:image-hotspots-editor-select`, so the page can show its own fields for that point.

- **New [video](https://docs.wirekit.app/components/video) player for a video in the page.** `<x-wirekit::video>` plays a file, a stream (HLS) or a video on YouTube or Vimeo when the reader presses play, and nothing loads before that. A provider's player loads nothing from the provider until the reader agrees: a notice offers "Load the video" and sends `wirekit:video-consent`, which a consent manager can take and answer with `wirekit:consent`, and `consented` starts a player whose consent the page already holds. YouTube plays from its cookieless host and Vimeo without tracking. `tracks` adds captions, and `background` runs a file as a muted loop with a pause button, still under `prefers-reduced-motion` and Save-Data. A stream plays natively in Safari and through hls.js elsewhere, handed over with `registerHlsEngine()`.

- **New [image editor](https://docs.wirekit.app/components/image-editor) for a crop over an image.** `<x-wirekit::image-editor>` draws a crop over an image, moved and sized by dragging its frame or one of its eight handles, with the arrow keys or through four number fields, and held to a ratio such as `9/16` when one is given. The image stays as it is: the value is the crop, a rectangle in percent of the image, bound with `wire:model` or `x-model`, and `Pushery\WireKit\Support\ImageCrop` turns it into pixels for a resize and moves the markers of image hotspots into the crop.

- **An [accordion](https://docs.wirekit.app/components/accordion#starting-open) item and an [FAQ](https://docs.wirekit.app/components/faq) question can start open.** `open` renders the item open from the first paint, its header expanded and its panel shown before any script runs, so nothing moves when the page starts. In single mode the first item with `open` stays open.

- **Whether a [collapsible](https://docs.wirekit.app/components/collapsible), a [sidebar](https://docs.wirekit.app/components/sidebar) section or an [accordion](https://docs.wirekit.app/components/accordion#starting-open) item starts open can be set once, in the configuration.** `components.collapsible.open`, `components.sidebar.collapsible.open` and `components.accordion.item.open` set the start of every box whose call does not say, and all three ship as `false`. An accordion item takes its default in multiple mode only: in single mode, where one panel is open at a time, only an item with `open` starts open.

- **A [datetime picker](https://docs.wirekit.app/components/datetime-picker) picks a date and a time together, from a calendar and a list of times in a dialog.** The trigger looks like a field and shows the moment it holds, "Oct 27, 2026 at 10:30 AM". The value is written `YYYY-MM-DDTHH:MM`, takes a date object, binds with `wire:model` and submits with a form. A day picked without a time waits for one rather than becoming midnight; `default-time` gives it one, and `with-confirmation` keeps both until Select. `interval`, `min-time`, `max-time` and `time-format` shape the list of times, and a `max-time` before the `min-time` lists the night. With `time="input"` the time is typed instead, the hour, the minute and AM or PM as segments in the order of the application's locale, with the list as suggestions and a sentence under the field when a typed time is closed. `min`, `max` and `unavailable` close days, times and spans, a span such as `22:00-06:00` runs over midnight, and a date object among them closes a booked moment. The moment is written in the application's locale, or in the one `locale` names, alike by the server and by the script, and a date object or a moment written with its offset is read in the application's time zone. A moment in another language than the page's carries it in `lang`, on the trigger and in the list of times. The calendar in the dialog takes the calendar's own options, the `trigger` slot takes a button of the page's own, and the picker dispatches `wirekit:datetime-picker-open`, `wirekit:datetime-picker-close` and `wirekit:datetime-picker-clear`. Its dialog, and the dialogs of the date and the time picker with `popover`, carry the [theme marker](https://docs.wirekit.app/theming#theme-markers) `data-wk-picker-dialog`.

- **A [datetime picker](https://docs.wirekit.app/components/datetime-picker#range) with `range` picks two moments, a start and an end.** The calendar shows two months and picks the two days, and a row for each end below it takes its time, from a list or typed with `time="input"`. Select range stays closed until both ends have a day and a time and the end comes after the start, which a sentence under the times says, on one day too. The trigger writes "Oct 27, 2026 at 9:00 AM – Nov 1, 2026 at 5:00 PM", with the end's time alone on the start's day. The form receives `name[start]` and `name[end]`, and `wire:model` binds the two ends as paths of an array or of a `DateTimeRange`. `default-time` takes a time for each end, `min-range` and `max-range` limit the days, and `presets` lists ranges as on the calendar, a preset taking its whole days.

- **A [datetime picker](https://docs.wirekit.app/components/datetime-picker#typing-the-whole-moment) with `type="input"` takes the whole moment typed in its field,** the day, the month, the year, the hour, the minute and AM or PM as segments in the order and with the separators of the locale, with a button at the end that opens the dialog. A moment typed whole and open is taken at once, as a native field takes it, and the field and the dialog show each other's moment. A day its month does not have, a closed day and a closed time are not taken, and a sentence under the field says why. A pasted timestamp, or a moment written as the locale writes it, fills every segment, and a pasted date whose month or day does not exist is not taken either. With `range` the start and the end are typed in two fields, taken together once the end comes after the start and the range covers as many days as `min-range` and `max-range` allow. In a field too narrow for the whole moment the time goes on a line under the date.

- **On a phone the [datetime picker](https://docs.wirekit.app/components/datetime-picker#on-a-phone) opens its dialog as a modal,** centered over a backdrop inside the safe area, with the page behind it held still and inert. The days grow to the size of a touch target as far as the width allows, a range shows one month with its presets as a select above it, the list of times gives way to a select the phone opens as its own wheel, and a pick waits for Select. This holds below 640 pixels of width and below 480 of height, a phone held sideways, where a dialog taller than the screen scrolls in itself with Cancel and Select in sight; a tablet keeps the panel below the trigger. Above those sizes the panel stands below the trigger, or above it near the bottom of the window, and on a window too short for all of it takes the room on its side and scrolls in itself, with the trigger in view and Cancel and Select in sight; a control the focus reaches stands clear of those two in either form.

- **A [date picker](https://docs.wirekit.app/components/date-picker#popover) and a [time picker](https://docs.wirekit.app/components/time-picker#popover) take `popover`.** In place of the native field, the date picker opens a dialog with the calendar, two months for a range, with the calendar's limits and options, and the time picker opens a list of times on the application's clock, or with `time="input"` takes the time typed in segments with the list as suggestions. The value, the field names and `wire:model` stay the same, so switching it on changes nothing on the server, and without `popover` both render as before. With `popover`, `format` sets the time picker's clock, a `max` before the `min` lists the night as the native field reads it, and each picker dispatches its own open, close and clear events. On a phone, and on a screen less than 480 pixels tall, both open as a modal centered over a backdrop with the page held still, as the dialog of the datetime picker does, the date picker with days as large as a touch target and one month for a range, its presets as a select above it. Inside a [field](https://docs.wirekit.app/components/field), and next to a `<label for>` of the page's own pointed at the picker's `id`, that label names the trigger or the typed time, a press on it opens the dialog or starts the typing in the first segment, and the button that clears the value names it as well. The datetime picker does the same. With `readonly` both show their value and open nothing, as the datetime picker does. A range shows a validation message filed under one of its ends, `{name}.start` or `{name}.end`, as it shows one filed under its name, here and on the datetime picker.
- **A [calendar](https://docs.wirekit.app/components/calendar) takes `flush`, without its panel's frame,** for a calendar on a surface of its own, as the datetime picker places it in its dialog.
- **A [calendar](https://docs.wirekit.app/components/calendar#date-format) takes `locale`, for the dates of one calendar in another locale than the application's,** such as a schedule that belongs to another region than the page. Its weekdays, its months and the first day of a week that follows the locale take it; its texts stay in the application's language. In another language than the page's, what the calendar shows in that locale carries it in `lang`, and the full date a screen reader hears for a day stays in the page's language, as the words added to it do.
- **A [calendar](https://docs.wirekit.app/components/calendar#keyboard) moves a year with Shift and Page Up or Page Down,** as far as `min` and `max` allow, onto the day with the same number; and the date, time and datetime pickers open their dialog with Down Arrow on the trigger as well as with Enter and Space.

- **A [calendar](https://docs.wirekit.app/components/calendar#limits) takes `min`, `max` and `unavailable`, and in range mode `min-range` and `max-range`.** A day outside them stays in the grid and within reach of the arrow keys, dimmed and named as unavailable, and neither a click nor Enter picks it. The month buttons, Page Up and Page Down stop at a month that lies wholly outside the bounds, and without a value a calendar whose limits close today opens on the next day that can be picked. Once the start of a range is picked, every day that would make the range too short or too long is closed, and the preview shows only a range that can be made. `min` and `max` take a day, a date and time, a date object, `today` or `now`, each read as its day in the application's time zone, text that names no day is reported through [strict validation](https://docs.wirekit.app/strict-validation#dates-and-times), and a limit that a Livewire render changes reaches the grid without resetting it.

- **A Livewire property typed with `DateRange` binds a [calendar](https://docs.wirekit.app/components/calendar#binding-a-range) or a [date picker](https://docs.wirekit.app/components/date-picker#binding-a-range) with `range`, and stays a range.** `Pushery\WireKit\Values\DateRange` reads every value the two components take for a range, and a range a form is still filling in is one too: `hasStart()`, `hasEnd()` and `isComplete()` say which ends there are, and a missing end throws nothing. It is a period of Carbon, so `whereBetween()` takes its two ends with the whole of the last day, and a loop over it runs a day at a time. Validation reads the ends as `period.start` and `period.end`. `DateTimeRange` keeps a time of day on each end, to the minute.

- **A [calendar](https://docs.wirekit.app/components/calendar#presets) and a [date picker](https://docs.wirekit.app/components/date-picker#presets) with `range` take `presets`, ranges such as "Last 7 days" picked in one press.** The list stands beside the calendar, and on a narrow screen it is a select above it. `presets` alone offers today, yesterday, this week, the last 7 days, this month, the year to date and, with `min`, all time; a list of keys names others, from days, weeks, months, quarters and years back or ahead to `custom`, which marks a range no preset names. A range picked in the grid marks the preset it equals, and a preset outside the limits cannot be picked. The range keeps its preset: a form receives `name[preset]`, a date picker binds it as a third path beside the two ends, and a `DateRange` returns it from `preset()`, so a filter set to "Last 7 days" is still "Last 7 days" when it is read again tomorrow. `DateRange::fromPreset()` computes the days of a preset for today, and each preset is a static constructor as well, `DateRange::last7Days()`. With presets, the grid's mark of today and the today button count from the application's day as the presets do.

- **A [calendar](https://docs.wirekit.app/components/calendar#today-button) takes a today button, a column of week numbers, six weeks in every month, the month it opens on and three sizes.** `with-today` adds a button beside the arrow to the next month, named with today's date, that goes back to today's month and picks today there; a today the limits close is only gone to. `week-numbers` adds the ISO 8601 number of each week, counted on its Thursday, as the header of its row. `fixed-weeks` draws six rows in every month, so a calendar keeps its height from month to month. `open-to` names the month a calendar without a value opens on, as a day, `YYYY-MM` or a date object. `size` draws the days at `sm`, `md` or `lg`. `week-starts-on` takes any day from `0` to `6`, and `locale` for the first day of the application's locale, read from the locale data of PHP's `intl` extension; `null` in `config/wirekit.php` makes that the default for every calendar.

- **An [editor](https://docs.wirekit.app/components/editor#several-engines) names the engine it opens in with `engine`.** An application with several schemas registers one factory per name in `window.wirekitEditors`, and a field with `engine` opens in that factory and in no other, waiting for it when its script runs after a `wire:navigate` visit. With one name for every engine, a field could open in whichever factory had run last and lose on the next save what that schema does not know. Without the prop a field takes `window.wirekitEditor` as before.

- **`fit` stands a [table](https://docs.wirekit.app/components/table) as wide as its columns, at most as wide as the space.** Wider than that it behaves as without `fit`: the columns wrap, or with a frozen first column the table scrolls sideways in its own scroller with the shadows at its edges. A wrapper that sized itself by its content, such as `w-fit` or `inline-block`, left a responsive table no width at all, because the container its columns measure against takes no width from what it holds.

- **`--wk-scroll-inset-below-fab` lifts the corner buttons over a floating bar without a script on the page.** WireKit writes the band of the surfaces pinned to the bottom, the floating [action bar](https://docs.wirekit.app/components/action-bar) among them, without the buttons that stand on `--wk-fab-lift` themselves: `--wk-fab-lift: var(--wk-scroll-inset-below-fab, 0px)` raises a [floating action button](https://docs.wirekit.app/components/fab) and a [scroll-to-top](https://docs.wirekit.app/components/scroll-to-top) stacked over it while the bar stands. `--wk-scroll-inset-bottom` counts the buttons as well, so as their lift it raised them by their own height on every measurement. A measurement that changes the lift measures once more, and once a sliding button has come to rest, so the bottom band counts the buttons where the lift put them.

- **⌘↵ or Ctrl+Enter confirms an open [alert dialog](https://docs.wirekit.app/components/alert-dialog#confirming-from-the-keyboard) or [modal](https://docs.wirekit.app/components/modal#confirming-from-the-keyboard) with its primary control, from a field as well.** An alert dialog presses the control inside `alert-dialog.confirm`, a modal the control a page marks with `data-wk-dialog-primary`, which wins in an alert dialog too. Focus stays on Cancel, so a plain Enter still approves nothing, and a control that is disabled or held back by its confirmation phrase is not pressed. The chord is the control's click, so `wire:click` and a page's own listeners hear it as one. The [overview of keyboard shortcuts](https://docs.wirekit.app/components/shortcuts) lists it among the open dialog's shortcuts, and the control carries it in `aria-keyshortcuts`. `confirm-shortcut` turns it off for one dialog, `components.alert-dialog.confirm-shortcut` and `components.modal.confirm-shortcut` in the configuration for every one.

- **A [navigation menu](https://docs.wirekit.app/components/navigation-menu) item, an [FAQ](https://docs.wirekit.app/components/faq) question, an [accordion](https://docs.wirekit.app/components/accordion) item and a [swatch group](https://docs.wirekit.app/components/swatch-group) option name the language of their text.** Each takes its text as a string and uses it again, for an id, for the structured data or inside a sentence of the page, so a marked-up text did not fit. `trigger-lang`, `question-lang`, `title-lang` and an option's `lang` write the language on the element that shows the text and leave the id, the schema and the sentence as they were; in "Blau, unavailable" only the label takes it.

- **An [image](https://docs.wirekit.app/components/image), an [image gallery](https://docs.wirekit.app/components/image-gallery) and a [lightbox](https://docs.wirekit.app/components/lightbox) name the language of an alternative text and of a caption.** Where either differs from the page's language, `alt-lang` and `caption-lang` write it on the image and on its caption alone; a `lang` on the tag landed on the figure and reached both. A gallery takes `altLang` and `captionLang` per image, in the grid and in the lightbox, keeps a caption that is markup as markup in the grid, and the lightbox draws such a caption's text. The lightbox's announcement of the slide it moved to carries the language of the text it reads.

- **An [FAQ](https://docs.wirekit.app/components/faq) takes the `level` of its questions.** Its questions stood on level 3 wherever it stood, so right under the page's `h1` the outline missed a level, and under an `h3` they could not go to 4. `level`, 1 to 6, reaches every question as `variant` and `size` do.

- **The [breadcrumb builder](https://docs.wirekit.app/components/structured-data#a-breadcrumb-trail) takes a list of steps.** `Schema::breadcrumbList()` took a `name => url` map, which keeps each name once, at the place of the first and with the address of the last: a category and a product with the same name left the `BreadcrumbList` one step short of the visible trail, and pointed the category at the product. A list of `['name' => …, 'url' => …]` steps keeps both, under the rules the map follows: a step without a page is left out unless it is the last, and two steps in a row with the same address are one. The map works as before.

- **A [callout](https://docs.wirekit.app/components/callout#a-title-in-the-pages-outline) and an [alert](https://docs.wirekit.app/components/alert) take a `level` for their title.** Both drew the title as a heading in a `div`, so a screen reader moving from heading to heading never met it, and the headings in a callout's text counted from a level that was not there. With `level`, 1 to 6, the title is a heading of that level in the component's own size; without it, it stays the `div` it was.

- **A [table](https://docs.wirekit.app/components/table#giving-way-only-in-a-wide-window) column can give way to the table's width only from a window width up, and `table.stand-in` shows what stands in for it.** `hide-below-container-from` on `table.th` and `table.td` sets the window width from which `hide-below-container` applies, so a list may scroll in its own frame on a phone and still has to fit on a desk. In a neighboring cell, `table.stand-in` with the column's two values shows its slot exactly where the column gives way, and the value is on screen once at every width.

- **A [dropdown](https://docs.wirekit.app/components/dropdown#counters) item takes a `badge`, a count or a short word at its end.** It is drawn as a sidebar item draws its counter and read with the entry's name, "My drafts 3". An empty value draws nothing, so an entry can carry its count only while there is one, and beside a `shortcut` the count stands before the key hint.

- **A [badge](https://docs.wirekit.app/components/badge#cutting-a-long-label) with `truncate` stays on one line and cuts a long label at one width.** A badge that carries a stored name grew as wide as the name, past the edge of a phone or wide enough to make a table scroll sideways. With `truncate` it stops at `--size-wk-badge-max`, the label ends in an ellipsis, and the whole label shows in a tooltip while it is cut. With `tooltip` as well, one panel shows the whole label above the tooltip's text.

- **A [stat](https://docs.wirekit.app/components/stat#a-tile-that-sets-a-filter) can be a toggle button that sets the filter it counts.** With `pressed`, `true` or `false`, the whole tile is a `<button type="button">` with `aria-pressed` and stays one item of a stats grid. A pressed tile draws the accent frame of a chosen card in place of its neutral border, an edge twice as thick as the border, and the frame follows `aria-pressed` wherever it is set, so a binding of the page moves it as well. `wire:click`, `wire:key` and `data-*` reach the button, which is named by what the tile shows.

- **A range of [checkboxes](https://docs.wirekit.app/components/checkbox#picking-a-range-with-shift) picked with Shift held.** `x-wk-range-select` on the element that holds them, a table body for one, gives every checkbox from the one clicked last to the one clicked with Shift the state this click gives it, and clears the range when the click clears its box. Each box in the range is clicked in turn, so `wire:model` on an array and every other binding hear it as a click, the text between the rows is not selected, disabled boxes and switches keep their state, and Shift and Space do the same from the keyboard. In lists inside each other, such as a table body that carries it inside a [bulk selection](https://docs.wirekit.app/components/bulk-selection), each list picks in itself. A [data table](https://docs.wirekit.app/components/data-table) with `selectable` picks a range by itself.

- **A [radio](https://docs.wirekit.app/components/radio) or [checkbox](https://docs.wirekit.app/components/checkbox) card holds a description and a trailing part inside its frame.** With `variant="card"`, the `hint` stands under the name as the option's description, and the `trailing` slot takes a price, a logo or an image at the end of the row, both inside the card. Neither becomes part of the control's name: the control takes its name from the label and its description from the hint.

- **A [sign-in button](https://docs.wirekit.app/components/sign-in-button#a-passkey) for a passkey.** `service="passkey"` is a `<button>` from which the page's passkey script starts the sign-in, with the words for signing in, continuing or signing up, and the passkey icon of the FIDO Alliance beside them once it is named in `config/wirekit.php`.

- **[`wirekit:theme`](https://docs.wirekit.app/cli-reference#wirekittheme-preset) derives success, danger and warning from brand colors, as it derives the accent.** `--success=`, `--danger=` and `--warning=` take a color each and write the state's fill, hover, label and text color for light and dark, the text color into the state's border token as well. The label reads at 4.5:1 or more on the fill and the hover, and the text color on the page, the card and the tints an alert or a callout draws.

- **A [command palette](https://docs.wirekit.app/components/command-palette#a-palette-that-takes-the-shortcut) takes the shortcut of another while it is on the page.** With `takes-hotkey`, a palette that shares its `hotkey` with others on the page has the key to itself: the key opens and closes it, and the others stay quiet until it leaves the page, as the palette of a table's selection leaves with the selection. Two palettes on one key opened together. A [search field](https://docs.wirekit.app/components/command-palette/search-field) for one of the others stops stating the key while it is taken, in `aria-keyshortcuts` and at its end.

- **An [action bar](https://docs.wirekit.app/components/action-bar#announcing-the-count) says its count with `summary`.** Its live region said "Bulk actions available" when the bar appeared, and the count beside the actions, "3 selected" then "4 selected", reached no screen reader. The `summary` slot shows the count first in the bar and the region says it in place of that sentence, on each change the server renders. Without the slot the bar says what it said.

- **A [bulk selection](https://docs.wirekit.app/components/bulk-selection) selects every match of a server list, not only its page.** Around a table of the application's own, `bulk-selection.toggle` is the header checkbox, checked when every row of the page is and mixed when some are. Once the whole page is selected and `total` says there are more, a notice above the rows names both numbers, "The 50 rows on this page are selected. Select all 1,284 matches on all pages", and afterwards offers the page alone again. Every match is a boolean that `wire:model` binds both ways. While it holds, the rows of each page the reader turns to are selected as they render, and a render with another `filter` clears it and says why. A screen reader hears each change, and a click with Shift held picks a range of rows. A switch in a row, such as a [toggle](https://docs.wirekit.app/components/toggle) for a setting of its record, is no row, so selecting or clearing the page leaves it as it is.

- **A [data table](https://docs.wirekit.app/components/data-table#selecting-every-match) in server mode offers every match with `total`.** Once the reader has selected the whole page, the bar offers all matches; taken, its count says "1,284 selected, on all pages", and `selection-change` carries `allMatches`. Another `search` or `filter` clears it. A screen reader hears the offer, every match taken and the page alone again from the table's status region.

- **An entry of a [command palette](https://docs.wirekit.app/components/command-palette) opens a page of values in the same palette.** `opens` names a `command-palette.page`, such as "Set status…" with Active, Draft and Archived: the field empties and searches the page, without case and accents, the first nine values carry the digits 1 to 9, and a digit chooses one while the field is empty. Backspace in the empty field or the new Back button goes up a level, Escape closes the palette, and a screen reader hears each level with its count and each value's digit as its `aria-keyshortcuts`. A page with `remote` takes its values from the application's search, as the top level does: the query event names the page in `page`. [Command Palette with Pages](https://docs.wirekit.app/components/command-palette/pages) shows both kinds.

- **The [overview of keyboard shortcuts](https://docs.wirekit.app/components/shortcuts#the-overview) lists the hotkey of every command palette on the page.** It names each under the palette's `label`, under Everywhere, where the key opens the palette from, or with the new [`hotkey-area="page"`](https://docs.wirekit.app/components/command-palette#in-the-overview-of-keyboard-shortcuts) under On this page, for a palette that belongs to one page. The key of such a palette does nothing while a modal dialog is open over the page, like a shortcut of the page. The palette still handles its key alone, so the key acts once, and a key another palette has taken is listed under that one.

- **A [`kbd`](https://docs.wirekit.app/components/kbd#a-shortcut-for-the-readers-platform) draws the keys of a shortcut for the reader's platform, and a tooltip draws the shortcut of its control.** `shortcut="cmd+s"` draws ⌘ S on a Mac and Ctrl S elsewhere, the words among the keys in the reader's language (`Strg` in German), and a sequence such as `g d` with "then" between its steps, as the overview of keyboard shortcuts draws them. The overview names its keys in the reader's language as well. A [tooltip](https://docs.wirekit.app/components/tooltip#a-keyboard-shortcut) draws the shortcut its control binds with `x-wk-shortcut`, or the one its new `shortcut` prop names, after its text, and so does the tooltip of an [app rail](https://docs.wirekit.app/components/app-rail) module. A single-key shortcut is drawn only while single keys work. A `shortcut` the grammar does not read is reported through [strict validation](https://docs.wirekit.app/strict-validation), and the `kbd` draws its slot in its place. A shortcut that names `ctrl` beside `cmd` draws ⌃ beside ⌘ on a Mac, in the overview as well, since it needs both keys there.

- **An application's own number format, through `WireKit::formatNumbersUsing()`.** An application whose numbers follow an account's settings rather than the language of the request gives WireKit its own way of writing a number, and every number WireKit formats on the server goes through it, the counts of a [pagination](https://docs.wirekit.app/components/pagination) summary among them. A percentage and an amount in a currency keep the way the locale writes them and take the formatter's grouping and decimal marks. See [Localization](https://docs.wirekit.app/localization#numbers-in-your-applications-own-format).

- **A series of a chart names its own decimals.** `decimals` on a dataset takes the place of `valueDecimals` for that series, in the tooltip, in the list of a chart's linked points and on the y-axis that shows it, so a [mixed chart](https://docs.wirekit.app/components/chart-mixed#decimals-per-series) of returned units beside a return rate writes `12` and `4,53` on a German page, where one setting for the whole chart wrote `12,00`. A series without it keeps the chart's `valueDecimals`.

- **Amazon's button image in one file per pixel density.** A [sign-in button](https://docs.wirekit.app/components/sign-in-button#amazon) for Amazon showed its one image at the image's own size, blurred on a dense screen from the single file and twice as large from the double one. `logo` and `wirekit.sign_in.logos.amazon` take `['1x' => …, '2x' => …]`, written as `srcset`, so the button stays sharp at the size Amazon gives it, and a `2x` file alone shows at half its own size.

- **Apple's logo in the color of the button's words.** Apple asks for a white logo on its black button and a black one on its white button, and a [sign-in button](https://docs.wirekit.app/components/sign-in-button#the-logos) with `variant="auto"` takes the page's mode, so a single file was wrong in one of the two. The logo of Apple can be given as `['white' => …, 'black' => …]`: every look carries both and shows the one it asks for, `auto` the one the page's mode asks for, and in forced colors, where the button stands on the reader's own colors, each shows the one the reader's contrast theme asks for. A single file holds for every look as before, and a list that names no file, by density or by color, is reported.

- **An ordinary link to another page asks in the kit's dialog too, and the page can take over the question.** With `x-wk-unsaved.confirm`, a link of the same site without `wire:navigate` asked in the browser's own words, which name nothing and stand in the browser's language. It now asks in the [unsaved hint](https://docs.wirekit.app/components/unsaved-hint#asking-before-the-reader-leaves)'s dialog, as a `wire:navigate` link does, and Leave follows it without the browser asking as well; a click with a key held, a download, another window, another site and a fragment of the page stay the browser's. Stay or Escape gives the focus back to the link that asked. Leave lets that one visit pass: a link that answers with a download or with no content leaves the page as it was, and the next unload asks again. `wirekit:unsaved` on `window` says whenever the page gains its first unsaved field or loses its last, and `wirekit:unsaved-release` sent to `window` stops every question until the next page, for a page that asks in its own way.

- **The question before leaving names what is unsaved and where.** Under the question, the dialog of the [unsaved hint](https://docs.wirekit.app/components/unsaved-hint#asking-before-the-reader-leaves) lists up to five unsaved fields, each by its label, a group by the caption of its legend, and by its place (the tab, the card, the accordion item and the marked part around it), and a line with the number of the others. Each entry closes the dialog without leaving, opens the tab, the accordion item, the collapsible card and the `details` around its field, and gives the field the focus.

- **A save over a button in a card counts the card as saved, and a path counts everything under it.** Under `x-wk-unsaved.until-saved`, `wirekit:saved` with `trigger: true` counts the fields of the part of the page around the button whose click sent the request, or around the field with the focus where a key such as Enter sent it: its form, else the part marked `data-wk-unsaved-area`, else its card, else its scope. A screen of several cards, each saved by its own button, keeps the cards that were not saved unsaved. `paths: ['variants.3']` now counts `variants.3.sku` and every other field under that path, for a save of several parts that says which went through, and `wirekit:not-saved` reads both the same way. See [unsaved hint](https://docs.wirekit.app/components/unsaved-hint#counting-only-a-save).

- **A [countdown](https://docs.wirekit.app/components/countdown#stopping-the-clock) can be stopped.** `pausable` puts a button after the time that stops the clock where it stands and starts it again, named "Pause countdown" or "Resume countdown" in each language WireKit ships. `static` works the remaining time out once, as the page loads, and leaves it standing, for a page served from a cache. A countdown that stands beside other content and whose ticking the task does not need meets WCAG 2.2.2 with either. At the deadline both still turn to the expired text, once, and fire `wirekit-countdown-expired`, and the button of `pausable` goes with the clock, handing the focus to the next control after the countdown when it has it. A headless countdown reads `paused` and calls `togglePause()` for a control of its own, which leaves `paused` as it is past the deadline.

- **Two taps on the quantity of a till line ask the application for a quantity.** In a [cart line](https://docs.wirekit.app/components/cart-list#a-line-for-a-till) with `stepper="buttons"`, two taps on the quantity between − and +, or a double click, dispatch `wirekit:cart-quantity` with the line's key, so a till can open a keypad of its own for a count that would take many presses. One tap does nothing. The quantity is a target as large as the buttons beside it, and a double click marks none of its digits.

- **A [card header](https://docs.wirekit.app/components/card#buttons-in-the-header) takes buttons and a sentence under its heading.** `card.header` takes an `actions` slot for buttons at its end and `description` for a sentence under the heading, as a prop or a slot. The buttons stand beside the heading while the card has room and drop under it where it has not, measured in the card rather than in the window, as the actions of a page header do. A header without either renders as before. A card that is itself a link or a button is one control and takes no buttons in its head: there `actions` is reported and left out, and a heading that links gives the card its destination instead.

- **`wirekit:card-opened` says when a [collapsible card](https://docs.wirekit.app/components/card#opening-it-from-elsewhere) stands open.** It rises from the card once the part that folds has slid open to its full height, after any way of opening it, and in answer to `wirekit:card-open` when the card was open already, so a script that opens a card can bring an element inside into view and land where it means to.

- **`:error="false"` turns the error of a form field off.** The [field](https://docs.wirekit.app/components/field#turning-an-error-off) then shows no message and no invalid state and reads nothing from the shared `$errors` bag, for a page that already reports the failure somewhere else, such as a notice above the form for a rejected sign-in link. Every form control that reads the bag takes it, a `field` turns it off for the control inside it as well, and a `field.set` turns its group message off the same way while its controls still leave the group's entries alone. Without it nothing changes, and `error="false"` written without the colon means the same.

- **A [drawer](https://docs.wirekit.app/components/drawer#full-screen-on-a-phone) can fill the screen on a phone.** Every drawer left a strip of the page beside its panel, 48px on a 390px phone, and nothing changed that, since the panel renders outside the page. `full-below` names the breakpoint, `sm` to `2xl`, below which the panel takes the full width as a side drawer or the full height as a top or bottom one, and keeps its content out of the safe areas on all four edges. Above it the drawer keeps its size.

- **A [number input](https://docs.wirekit.app/components/number-input#props) takes the names of its − and + buttons.** `decreaseLabel` and `increaseLabel` name them where the label alone words them badly, and without them the buttons are named from the label as before. A [cart line](https://docs.wirekit.app/components/cart-list) uses them: the stepper of a line read "Decrease Quantity of Desk lamp", and in French "Diminuer Quantité de", and now reads "Decrease the quantity of Desk lamp", as the press buttons of a till line already did.

- **The name of a [cart line](https://docs.wirekit.app/components/cart-list#a-name-that-links-to-its-product) can link to its product.** `href` makes the name a link in either layout, with the name's look and a link's underline on hover, and the controls of the line still say the name. `nameLang` sets the language of a name that is not in the page's, on the name alone.

- **A [link without an `href`](https://docs.wirekit.app/components/link#words-that-are-a-link-only-for-some-readers) can draw its words as text.** A page that names an order or a customer links it for a reader who may open its page and should show the words alone to one who may not. Without an `href` the link rendered an `<a>` without one, which looks like a link and takes neither focus nor a click. With `plain-without-href` it renders a `<span>` instead, without the link's color, underline, pointer and focus ring, and keeps `size` and the attributes it is given, except those only a link reads, such as `target`, `rel`, `wire:navigate` and `wire:current`. With an `href`, and without the prop, a link renders as before.

- **An [image compare](https://docs.wirekit.app/components/image-compare#disabled) can be disabled.** It submits a position like a field and had no way to be locked. `disabled` locks it as it locks a native field: the handle leaves the tab order and takes no press and no key, it shows that it is locked, and a form submits no position. Inside a [disabled group](https://docs.wirekit.app/components/field#a-disabled-group) the slider is locked the same way and now looks it, and a press that still reaches the handle moves nothing.

- **A [field set](https://docs.wirekit.app/components/field#a-required-group) takes `required`.** A group of radios or checkboxes that needs an answer had no way to say so: the attribute landed on the `<fieldset>`, where it means nothing, and the legend showed no asterisk. The legend now shows the asterisk a required field shows after its label, hidden from assistive technology, and its caption ends in "(required)" in the page's language, which a screen reader reads on entering the group, a group of checkboxes included. The browser's own check stays off, as on a required field.

- **A [textarea](https://docs.wirekit.app/components/textarea#in-a-plain-form) takes its text from `value`, as an input does.** In a form without Livewire, `:value="old('bio', $user->bio)"` brings back what the reader typed after a request that failed validation. The attribute used to land on the `<textarea>`, where it does nothing, so the field stood empty and the text was gone. Text written between the tags still fills the field, and wins when both are there.

- **A form that sends itself once.** A form that Livewire does not send went again on a second press before its answer arrived, and where the server takes a request only once, such as a code for one sign-in or a mail whose link the next mail replaces, the second request undid the first. A [form](https://docs.wirekit.app/components/form#sending-a-form-once) with `submit-once` lets the first submission go and holds every further one back until the page changes, without disabling anything: the form and the button that sent it carry `aria-busy="true"`, and the focus stays on the button. It takes a submission again when the browser shows the page from its back-forward cache, and after `submit-once-release` milliseconds for an answer that leaves the page as it is, ten seconds unless the form names its own. A plain `<form>` asks the same with `data-wk-submit-once`, and a submission another script has taken over, as `wire:submit` does, is left alone.

- **A [table](https://docs.wirekit.app/components/table#help-for-a-column) head takes `help`, the question mark that explains its column.** It is the one a field shows beside its label, with the text in a tooltip on hover and on keyboard focus, and it follows the head's `align`. In a sortable head it stands beside the sort button, so a click on it opens the help and sorts nothing, and the head stays named by its words. `help-id` writes the text as a hidden description for the fields of the column to list in their `aria-describedby`.

- **A [heading](https://docs.wirekit.app/components/heading#help-for-a-page-or-a-section) takes `help`, the question mark that explains a page or a section.** It is the one a field shows beside its label, and it stands beside the heading element rather than in it, so the heading stays named by its words. A click on it dispatches `wirekit:field-help` with the heading's `id`, and classes given to the heading go on the row that holds both.

- **A [navbar](https://docs.wirekit.app/components/navbar#what-only-the-menu-shows) takes a `menu` slot for what only its menu shows.** On a phone the menu holds it after the entries: the links to sign in, say, which a narrow bar has no room for beside the menu button. Above the breakpoint it is hidden, and its counterpart in `actions` takes `hidden md:flex`, so each is rendered once. Under `force-mobile` the menu shows it at every width, and a bar with `mobile="scroll"`, which has no menu, renders nothing of it.

- **A [file upload](https://docs.wirekit.app/components/file-upload#uploading-each-file-on-its-own) can send each file of a selection in a request of its own.** With `multiple` and `wire:model`, Livewire sends a selection in one request, so a limit on the size of a request, in PHP, the web server or a proxy in front of it, failed the whole selection when the files together passed it, the small ones included. Add `upload-separately` and each file goes up alone: one over a limit fails alone, its row says so, and the others stay on the property. The upload events still describe the whole selection, and `upload-separately` in the config turns it on for every upload.

- **A link to an [accordion](https://docs.wirekit.app/components/accordion#linking-to-an-item) item or an [FAQ](https://docs.wirekit.app/components/faq) question opens it.** An item's `id` stands on the item itself, so `/help#shipping` lands on the question, and the accordion opens it when the page loads or the address changes. A link to an element inside a closed item opens that item and brings the element into view.

- **`quantity-name` names the quantity of a [cart line](https://docs.wirekit.app/components/cart-list#quantity) for a form.** A cart that works without script sends its quantities with a form, and the field of a line was named after its id, `number-input-1`, `number-input-2`, a name that followed the order on the page and matched no line. With `quantity-name="lines[42][quantity]"` the form sends the quantity under that name; without it the field carries no name and a form sends nothing for it.

- **`help-field` names the field the help of a [field set](https://docs.wirekit.app/components/field) explains.** A click on the question mark beside the legend reports it as `name` in its event, where the set's own `name` is not that field.

- **A node of a [tree view](https://docs.wirekit.app/components/tree-view#handling-selection) takes `value`, and `tree-node-select` carries it beside the label.** The event named a node by its text alone, so two nodes that read the same could not be told apart, and a label that names the state of its record changed with that state. A Livewire page opens the record by its key from `$event.detail.value`, which is `null` for a node without one.

- **A [product card](https://docs.wirekit.app/components/product-card#ratings)'s stars take a note,** the `ratingNote` slot right after the number of reviews, in the row of the stars: where a shop says whether and how it checks that its reviews come from buyers, or a link to where it says so, which a statement on the product page alone does not replace. It renders only where the card shows stars, and a link in it takes its own click above the card's link.

- **A [swatch](https://docs.wirekit.app/components/swatch#a-name-instead-of-a-color) draws a value its name says best as a pill.** `shape="pill"` draws the name as the swatch's text, for a size such as XXL, as tall as a swatch of its `size` and at least as wide. An unavailable pill strikes its name through and reads "unavailable" with it, and a `color` or an `image` given with a pill is a dot before the name. A [swatch group](https://docs.wirekit.app/components/swatch-group#sizes-and-other-names-as-pills) takes `shape="pill"` for an axis such as sizes: each pill is drawn for the eye, and the option's name, with its language, is the one a reader hears.

- **A [product card](https://docs.wirekit.app/components/product-card#colors-and-other-values) takes the values of an axis over its price.** The `options` slot holds them, such as the colors the product comes in, each a link to its variant, and a link to the rest; its links take their own click apart from the card's link. The row takes the free space above the price, and the price follows it down, so the prices in a row of cards stand on one line whether a card has values or not.

- **A [map](https://docs.wirekit.app/components/map#your-own-tile-server) takes its style or its tiles from the config when it sets none.** `components.map.maplibre.style-url` is the style a MapLibre map loads, `components.map.leaflet.style-url` the tiles a Leaflet map draws, and `components.map.leaflet.attribution` the credit shown beside those tiles, so one setting keeps every map of an application on its own tile server. A map that sets its own `style-url` keeps it and shows only its own `attribution`. All three default to `null`: a MapLibre map then loads MapLibre's demo style, with its tiles and its fonts, from `demotiles.maplibre.org`, which receives each visitor's IP address, and a Leaflet map draws no tiles, as before.

- **A [calendar](https://docs.wirekit.app/components/calendar#disabled-and-read-only) takes `disabled` and `readonly`,** as the date and datetime pickers do. `disabled` locks every control and takes the calendar's fields out of the form. `readonly` lets the reader page through the months and move between the days, picks nothing, and still sends the value. Neither stops an empty submit with `required`.

- **A [card](https://docs.wirekit.app/components/card) takes `intent`, which draws its border in the color of an intent.** `info`, `success`, `warning` and `danger` take the border a [callout](https://docs.wirekit.app/components/callout) draws for the same intent, in place of the border of the card's surface; `neutral` and no intent keep it. An intent the card does not know is reported.

- **A [row](https://docs.wirekit.app/components/row#more-fields-than-one-line-holds) with `align-fields` and `wrap` wraps its fields into lines, each lined up on its own controls.** The fields take as many columns as fit at `min`, 14rem unless set, and every line of fields shares its tracks for labels, controls and messages, whatever the labels and hints on it carry. Below 48rem the row stacks, as every aligned row does.

- **A [field](https://docs.wirekit.app/components/field#content-after-the-field) takes an `after` slot for what follows it in its cell,** a button that adds a value under a select for example. In a row with `align-fields` the content takes a track of its own below the messages, so the controls and messages of the row stay on their lines; a row without such a field keeps its height.

- **A [dropdown](https://docs.wirekit.app/components/dropdown) item, checkbox item and radio item and the [command palette](https://docs.wirekit.app/components/command-palette)'s trigger take a `shortcut` as a list of keys,** such as `['Ctrl', 'K']`, as a [menubar](https://docs.wirekit.app/components/menubar) item and a [command palette](https://docs.wirekit.app/components/command-palette) item do, and draws them with a space between them. A list ended the page before.

- **`wirekit:doctor:props` names a list item written as a bare element.** A `<dt>` or `<dd>` written straight into a [data list](https://docs.wirekit.app/components/data-list), or an `<li>` straight into a [timeline](https://docs.wirekit.app/components/timeline), is reported with its line and the item to write, since such an element renders without the layout and the look of the item. See the [CLI reference](https://docs.wirekit.app/cli-reference#wirekitdoctorprops).

- **`actions` on [`table.td`](https://docs.wirekit.app/components/table#figures-aligned-to-the-end) says which cell of a stacked table holds the row's actions.** Where `stack-below` lays the rows out as cards, that cell stands as the card's footer without a name. Unset, it is a cell with `align="right"` and no label of its own, as before; `:actions="false"` keeps a column of figures aligned to the end as lines named by their column, and `actions` makes any cell the footer.

- **`stack-below-container` on [`table`](https://docs.wirekit.app/components/table#stacking-by-the-width-of-the-table) stacks the rows below a width of the table rather than of the window.** Beside a sidebar or in one column of a wide page the window is the wrong thing to measure: a table in a narrow column scrolled sideways while the window was wider than the breakpoint of `stack-below`. The new prop takes the container scale a column's `hide-below-container` reads, `sm` to `5xl`, and the rows stand as cards, each cell named by its column, as soon as the table has less room than its step, at any window width. It needs the table's frame, so a table with `:responsive="false"` reports it.

- **`table` on a [chart](https://docs.wirekit.app/components/chart#2-offer-the-data-as-a-table) renders its data as a table under it.** A chart draws its numbers where a screen reader does not reach them, and its name is a summary, so the values were nowhere as text unless each page built the table by hand. The table writes one row per label and one column per dataset, each value as the tooltip writes it, with `value-decimals`, `value-prefix` and `value-suffix`, and names a missing value. `table="disclosure"`, or the attribute on its own, puts it behind a summary every reader can open; `table="screen-reader"` keeps it out of sight. A Livewire update reaches it with the data, and [`chart-mixed`](https://docs.wirekit.app/components/chart-mixed) takes the prop as well.

### Changed

- **ApexCharts 8 is a supported version of the [chart](https://docs.wirekit.app/components/chart#requirements), and `wirekit:verify` no longer warns about it.** The chart suite runs against 8.3.1 in a real browser, as it ran against 5, 6 and 7. A build that runs `wirekit:verify --fail-on=warning` no longer fails on the ApexCharts version when 8 is installed.

- **A [calendar](https://docs.wirekit.app/components/calendar#visual-states) marks today with a dot under its number instead of a ring, and draws the month and year selects of `selectable-header` as pills.** The ring competed with the fill of a chosen day; the dot stays visible on it, in the accent's foreground color. The selects keep the control border, on the muted surface.

- **An [alert dialog](https://docs.wirekit.app/components/alert-dialog#closing-the-alert-dialog) with `close-on-confirm` needs a control that confirms, and strict validation says so.** The option closed the dialog only through `alert-dialog.confirm`, so a dialog whose action was a plain button stayed up after the action, with `aria-modal`, over a page it kept out of reach, and nothing said why. A control marked `data-wk-dialog-primary` confirms as well now and closes the dialog the same way, and a dialog with neither is reported, as an exception in tests and on the console and a log line in a request.

- **`wirekit:csp-audit` fails on `Js::from()` and `@js()` in a directive attribute, so it will fail builds it used to pass.** Laravel's encoder is the one for a `<script>` block. In an attribute it writes a non-empty array or object as `JSON.parse('…')`, which Alpine's CSP evaluator cannot run, so the expression parses and then dies without a message, and the audit listed it only as a pointer with the exit code at zero. It is now a finding of its own with its own exit condition, and the fix is one line: `{{ \Pushery\WireKit\Support\AlpinePayload::from($value) }}` writes every shape as a literal the evaluator reads, a number or a string as well as an array. The [CLI reference](https://docs.wirekit.app/cli-reference#wirekitcsp-audit) lists the condition, and the examples for a toast flashed to the session and for the inbox blueprint use the attribute encoder.

- **The tooltip of an [app rail](https://docs.wirekit.app/components/app-rail#counters) module draws two or more waiting items as a list, with a bullet before each.** A sentence that wraps goes on under its own words, so where one item ends and the next begins stays clear. One sentence, the line of how many more and the module's name take no bullet.

- **The chevron of a [collapsible card](https://docs.wirekit.app/components/card#a-card-that-folds) stands in a circle with a border**, so a closed card reads as one that holds more than its head. The circle is the new `chevron` class block, so a personalization can restyle it, and the arrow takes its color from it. A rule an application sets on `.wk-card-chevron` still reaches the arrow.

- **A [select](https://docs.wirekit.app/components/select#pitfalls) reports `multiple` and a list as its value.** With `multiple` the browser drew a list box clipped to the height of a field, under a chevron that opens nothing, and nothing said so. Strict validation now names the [multi-select](https://docs.wirekit.app/components/multi-select) for several values, and the attribute stays where it was, so a page that styled the list box keeps it. A list as `value`, which `old('country')` gives after a request that sent `country[]`, answered the page with "Array to string conversion". It is reported the same way, and where strict validation only logs, the select renders with nothing selected.

- **An icon name on a menu, palette, navigation or floating-button entry is checked in every installation.** A name no icon preset knows, on a [dropdown](https://docs.wirekit.app/components/dropdown) item, a [context menu](https://docs.wirekit.app/components/context-menu) or [menubar](https://docs.wirekit.app/components/menubar) entry, a [command palette](https://docs.wirekit.app/components/command-palette) item, a [sidebar](https://docs.wirekit.app/components/sidebar) or [app rail](https://docs.wirekit.app/components/app-rail) entry or a [floating action button](https://docs.wirekit.app/components/fab), fails a console command or a test also without an icon package, as it does on an [icon](https://docs.wirekit.app/components/icon). A request still draws the page and logs the name.

- **The backdrop behind a [modal](https://docs.wirekit.app/components/modal), a drawer, an alert dialog, a tour and the command palette dims the page less.** At half black in the light theme and seven tenths in the dark one, the page beside a dialog all but vanished, and the reader lost the page they came from. [`--color-wk-overlay`](https://docs.wirekit.app/theming/design-tokens#overlay-tokens) now defaults to `oklch(0% 0 0 / 0.35)` and `/ 0.5` in the dark theme; a theme that wants the old strength sets it back. The [lightbox](https://docs.wirekit.app/components/lightbox) keeps its darker backdrop under the new `--color-wk-overlay-media`, since a photo is looked at rather than read beside the page and its white caption keeps its contrast there.

- **The self-contained bundles carry Alpine 3.17.5.** `wirekit-alpine.js` and `wirekit-alpine.csp.js` bring their own Alpine, and 3.17.5 no longer applies `x-cloak` again to an element a morph leaves rendered, so a Livewire update cannot hide what was already shown. The plugin bundles, which use the application's Alpine, are unchanged apart from the collapse plugin's version.

### Fixed

- **A locale PHP's formatters refuse no longer takes the page down.** Under an application locale or a `locale` such as `POSIX`, `C`, `xx` or `de_DE@euro`, a [calendar](https://docs.wirekit.app/components/calendar), a [datetime picker](https://docs.wirekit.app/components/datetime-picker) and a [price](https://docs.wirekit.app/components/price), with every component that shows one, answered with an error page, in a request as well. They now write in the [nearest locale the formatters take](https://docs.wirekit.app/localization#a-locale-phps-formatters-refuse), down to the application's `fallback_locale`, and a locale they take stays as it was set. A component that formats in the browser was handed `en-US.UTF-8` under `en_US.UTF-8`, which the browser's `Intl` refuses, and now reads `en-US`.

- **An `x-model` on a WireKit component binds the page's property whatever its name.** The binding was read in the component's own Alpine scope first, so a property of the page named like one of the component's, `selected` on a [combobox](https://docs.wirekit.app/components/combobox), `password` on a [password input](https://docs.wirekit.app/components/password-input) or `value` on a [number input](https://docs.wirekit.app/components/number-input), bound the component to itself, without an error, and the page never received a value. It is now read in the page's Alpine component, with its modifiers, on a component's root as on a field inside it.

- **A [color picker](https://docs.wirekit.app/components/color-picker) with `popover` shows a color an Alpine page writes into it.** It kept showing the color it started with, or the last one picked in it, when an `x-model` of the page changed the value.

- **With `optimistic`, an `x-ref` on a [textarea](https://docs.wirekit.app/components/textarea), select, checkbox, toggle or time picker reaches the `$refs` of the Alpine component around it.** The field carried the component's own `x-ref` first, and the caller's was dropped. It is filed on the caller's Alpine component now, as on an input and a date picker.

- **Icons and marks in a [code block](https://docs.wirekit.app/components/code-block), a color picker and a [status matrix](https://docs.wirekit.app/components/status-matrix) take their intent's text color.** They took the fill color of the intent, which only has to suit the label on it: with a light brand green as `--color-wk-success`, the copied check of a code block stood at 2:1 on white. They read at 4.5:1 or more on the page now, as text in that intent does.

- **`wirekit:make recipe:<name>` writes the page its recipe shows first.** Most scaffolds composed other components than the first example of their page: the [documentation reader](https://docs.wirekit.app/blueprints/recipes/documentation-reader) and the [long-form article](https://docs.wirekit.app/blueprints/recipes/long-form-article) wrote a page without the reading shell their pages are built on, and the landing page a brand bar its page does not use. Each scaffold now builds that example, the landing page in the seven sections its page names as the smallest complete one.

- **A [price](https://docs.wirekit.app/components/price) in a currency given by its symbol writes its amount in the page's own format.** Given `€` or another text where a code of three letters belongs, a price wrote the amount as it is written without the intl extension, `1,234.50 €` on a German page, which a German reader takes for another number. It now writes the amount in the page's own pattern with that text where the symbol stands, so `€` reads as `EUR` does, and strict validation reports the value. An empty `currency` reads as none, so the default currency of the configuration counts instead of `XXX`, the code for no currency, and a list given as `currency` no longer answers with an error page. A [product card](https://docs.wirekit.app/components/product-card), a [pricing table](https://docs.wirekit.app/components/pricing-table), a [cart list](https://docs.wirekit.app/components/cart-list) and a [cart summary](https://docs.wirekit.app/components/cart-summary) draw their amounts through it.

- **A [radial progress](https://docs.wirekit.app/components/radial-progress) with an infinite `max` reads it as out of 100, as a progress bar does.** The ring stood empty, and screen readers were told a maximum of `INF` and `0%` beside a value of 40.

- **Two bounds written the wrong way round read as the range between them, as a calendar already reads two days.** A [slider](https://docs.wirekit.app/components/slider), a [range slider](https://docs.wirekit.app/components/range-slider), a [number input](https://docs.wirekit.app/components/number-input), a [cart line](https://docs.wirekit.app/components/cart-list), a [date picker](https://docs.wirekit.app/components/date-picker)'s own field and the moments of a [datetime picker](https://docs.wirekit.app/components/datetime-picker) took a `min` above their `max` as written: a field with no valid value, which a form never sends, a slider with no travel, a cart line with both buttons disabled. They now put the two in order. A [time picker](https://docs.wirekit.app/components/time-picker) keeps a window across midnight, such as `17:00` to `09:00`, which HTML defines.

- **A [date picker](https://docs.wirekit.app/components/date-picker) without `popover` takes `today`, `now` and a date and time as the bounds of its own field, as its calendar does.** It wrote them into its date field as given, and a browser passes over a bound that is no `YYYY-MM-DD`, so the field had no bound at all where the calendar of the same picker closed the days outside it.

- **A [rating](https://docs.wirekit.app/components/rating), a [strength meter](https://docs.wirekit.app/components/strength-meter), a [skeleton](https://docs.wirekit.app/components/skeleton) with its text and table forms, and an [OTP input](https://docs.wirekit.app/components/otp-input) draw at most a hundred stars, bars, lines, rows, columns or boxes.** Each drew one per unit of its `max`, `lines`, `rows`, `cols` or `length`, so a count of a hundred thousand from a broken record ran the request out of memory, an error no handler catches. A larger count now draws a hundred, and strict validation reports it. A count far below zero no longer ends the page of a skeleton or a strength meter either.

- **A field named with a space, such as `first name`, is described by the hint and the error it shows.** A name may hold a space, and a field without its own `id` took the name as its id: `aria-describedby="first name-hint"` named `first` and `name-hint`, ids no element carries, so a screen reader read neither the hint nor the error. An id given with a space did the same, in every [input](https://docs.wirekit.app/components/input) and picker. Each run of whitespace in an id now becomes a hyphen; the field's `name` stays as given.

- **A [tab](https://docs.wirekit.app/components/tabs) keyed with a space, such as `new york`, and its panel name each other.** The key went into both ids as given, so the panel's `aria-labelledby` named `…-tab-new` and `york`, ids no element carries, and a screen reader read the panel without a name; the tab's `aria-controls` split the same way. An `id` given to the tabs with a space did the same for every tab. A row of the [scope switcher](https://docs.wirekit.app/components/scope-switcher) carried its key in its id the same way. Each run of whitespace in these ids now becomes a hyphen, and the key stays as given.

- **An image address that is empty, white space or `false` is no image.** Given one, an [avatar](https://docs.wirekit.app/components/avatar), a [brand](https://docs.wirekit.app/components/brand), a [product card](https://docs.wirekit.app/components/product-card), a [testimonial](https://docs.wirekit.app/components/testimonial) and the other components that show a person's picture, a logo or a thumbnail drew an image that cannot load, which shows the sign of a broken image, where they have a state without one: the initials, the name alone, a card without a picture. Each now shows that state. An [image](https://docs.wirekit.app/components/image) with no address draws nothing, an [image gallery](https://docs.wirekit.app/components/image-gallery) shows an entry's zoom in its place or leaves the entry out, an [image compare](https://docs.wirekit.app/components/image-compare) reports a missing image through strict validation, and the attendees of an [event calendar](https://docs.wirekit.app/components/event-calendar) show their initials.

- **A link address that is empty or white space is no link.** A [button](https://docs.wirekit.app/components/button), a [text link](https://docs.wirekit.app/components/link), a [card](https://docs.wirekit.app/components/card) and the other components that become a link with an address drew one to the page they stand on when the address was white space, and the entries of a [navbar](https://docs.wirekit.app/components/navbar), a [sidebar](https://docs.wirekit.app/components/sidebar), the bottom navigation, the app rail and the navigation menu did the same for an empty address and for `false`: a screen reader read a link, and a press loaded the page again. Each now draws as it draws without an address, the entries with their own `#`, and the name of a [cart item](https://docs.wirekit.app/components/cart-list) given `false` is no link.

- **A link address of `0` is a link.** A [button](https://docs.wirekit.app/components/button), a [text link](https://docs.wirekit.app/components/link), a [card](https://docs.wirekit.app/components/card), a [product card](https://docs.wirekit.app/components/product-card) and the entries of a dropdown, a menubar, a context menu, the navigation menu, the command palette and the floating action button asked whether their address was true, and `0` is not: given `href="0"`, they drew a button or an element without a target. Each now draws the link, as the steps of a stepper and the entries of a navbar or a sidebar already did.

- **A date that is no date reads as none.** Given `false`, a [countdown](https://docs.wirekit.app/components/countdown), a [review](https://docs.wirekit.app/components/review), an [event calendar](https://docs.wirekit.app/components/event-calendar), a [message](https://docs.wirekit.app/components/message) and a [date separator](https://docs.wirekit.app/components/date-separator) drew 1 January 1970, and given the zero date `0000-00-00` that older MySQL schemas write for no date, 30 November of the year -1, which reads as 2 December of the year 2. Both now read as no date, and so does a date of white space, which strict validation reported as one it could not read.

- **A date that cannot be read is reported on a date picker, a time picker and the events of an event calendar.** A `min` or `max` such as `2026-13-45` or a word set no bound on a [date picker](https://docs.wirekit.app/components/date-picker) and a [time picker](https://docs.wirekit.app/components/time-picker), without a report, and the time picker wrote it into its field as given. An [event calendar](https://docs.wirekit.app/components/event-calendar)'s event with such a `start` stood on no day, and one with such an `end` lasted no time. Each is now reported through [strict validation](https://docs.wirekit.app/strict-validation#dates-and-times), as the date of a countdown or a review already was, and counts as none: the field has no bound, the event is left out, and an event whose end counts as none takes the length of one without an `end`. An event whose start is no date, `null`, `false`, an empty text or the zero date, is left out without a report; `null` and `false` put it on the first moment of 1970 in UTC. The value of a date or time field is not checked, since after a failed validation it holds what the reader sent.

- **An [event calendar](https://docs.wirekit.app/components/event-calendar) places an event or a day marker whose date is written in another form than ISO 8601.** A date the server reads, such as `31.12.2026` or a Unix timestamp, reached the browser as written, where Chrome reads `31.12.2026` as no date and every browser counts a number in milliseconds: the event and the marker stood on no day, or in January 1970. Each now reaches the browser in ISO 8601, a time without a zone as the wall-clock time it names, and so does a date and time written with a space, as a column without a cast holds it, in the form ECMAScript defines for every browser.

- **A time written as text reaches a time field in the form the field reads.** A [time picker](https://docs.wirekit.app/components/time-picker) and an [input](https://docs.wirekit.app/components/input) with `type="time"` wrote `9:30` into their field as given, and a field takes two digits for the hour, so the value stood empty and `min="9:00"` bounded nothing. A time with seconds from a `time` column, such as `08:00:15` given as `min` on a field that counts minutes, is the base the step counts from, so no whole minute was a step and the form refused to send. Each is now written as the field reads it, `09:30`, with its seconds only where `step` counts them, as a date object already was, and a `datetime-local` field takes `2026-03-15 9:30` as well. The list of a time picker with `popover` reads no time from the zero date `0000-00-00 00:00:00`, which names no date.

- **A [keyboard key](https://docs.wirekit.app/components/kbd) with no key to show draws nothing.** A `shortcut` of white space, and in a request one strict validation reports, drew an empty key cap where its slot was empty as well, and a [menubar](https://docs.wirekit.app/components/menubar) item with a blank `shortcut` drew one in its row. A slot still stands in for a shortcut that names no key.

- **The caption of a [table](https://docs.wirekit.app/components/table#caption) that scrolls sideways breaks within what shows of the table.** A caption was as wide as its table, so under a table wider than its scroll area, such as a comparison on a phone, its sentences broke at the width of the whole table and the scroll area cut them mid-word. A caption is at most as wide as the space the table stands in now; under a table that fits, nothing changes.

- **An [event calendar](https://docs.wirekit.app/components/event-calendar) with a `locale` in another language than the page marks what it shows in that language.** Its heading, its weekdays, its hours and its times stood in the locale with no `lang`, so a screen reader read them in the page's voice, and the accessible name of an event or a day set a date in the locale between words of the page, such as "All day", so one name held two languages. What the calendar shows in its locale carries it in `lang` now, a time that can read "All day" only while it is a time, and every name a screen reader hears, with the plural form of its sentence, is written in the page's language.

- **A [kanban](https://docs.wirekit.app/components/kanban) board inside a Livewire component stays draggable and reachable from the keyboard after an update that leaves its cards as they are.** The board gives each card the attributes that dragging, the Tab key and a screen reader read, and an update that changed no card took them off again, so a pointer could no longer drag a card and Tab no longer reached one until a card moved. The confirm control of an [alert dialog](https://docs.wirekit.app/components/alert-dialog) that waits for its confirmation phrase stays announced as unavailable, with its reason, through an update while the dialog is open, and a control that a page puts in the editor slot of an [inline edit](https://docs.wirekit.app/components/inline-edit) keeps its name and description through an update while it is open.

- **Every size an [attachment](https://docs.wirekit.app/components/attachment) shows reads in the page's language and in the application's own number format.** A size in bytes and a size from ten up were written as plain digits, past the locale and past `WireKit::formatNumbersUsing()`, beside the sizes below ten, which went through both. A card could read `2,4 MB` through the application's format beside `512 B` and `24 MB` without it, and `1022 KB` stood ungrouped where the locale groups it.

- **A number written with no set decimals keeps its own without the intl extension.** Without `intl`, a figure that asks for no number of decimals was rounded to a whole number, so a [usage meter](https://docs.wirekit.app/components/usage-meter) read `8 / 10 GB` for 7.5 GB where the locale's way writes `7.5 / 10 GB`. It now keeps up to three decimals with no zeros at the end, as it does with `intl`.

- **A [file upload](https://docs.wirekit.app/components/file-upload#multiple-files) with `multiple` and `wire:model` holds on its property exactly the files its list shows.** Livewire 4 adds every selection of a `multiple` field to the files the property already holds, and removing a file hands the field the files that stay. After a removal the property still held the removed file and the others twice, and a second selection joined the first while the list showed only the second, so a save stored files the reader had taken out or replaced. A new selection now replaces the one before it on the property as it does in the list. With `upload-separately` the files go up one after another, and the first that arrives replaces what the property held. A file whose upload is canceled leaves the list as it left the property, and one that failed stays in it and says so. A selection none of whose files arrives empties the property, without a request of its own, so the message the failure left stays and the selection before is not stored.

- **The marks and the value bubble of a [slider](https://docs.wirekit.app/components/slider#accessibility) follow a right-to-left page.** Under `dir="rtl"` the browser draws the lowest value of the range on the right, while the marks and the bubble stood from the left, so the label of the lowest value stood over the highest one and the bubble pointed at the mirrored position. Both now stand from the start of the reading direction, as the thumb does.

- **The mark labels of a [slider](https://docs.wirekit.app/components/slider#labels-on-a-narrow-track) no longer run into each other on a narrow track.** Each label was placed from its position alone, so on a phone two longer neighbors, such as "Empathetic" and "Enthusiastic" on a scale of five, ran together. Labels that would touch now move apart, each only so far that its tick stays under it, and where that does not make room the slider shows every second label, or every third, always with the first and the last. What the slider announces does not change.

- **[Tabs](https://docs.wirekit.app/components/tabs) inside a Livewire component survive an update that reorders, adds or drops a tab.** Each panel was opened in one of two branches and closed after them, so Livewire's block markers stood unpaired and the update threw "Cannot read properties of null (reading 'before')". Every panel is one element now, with and without `findable`.

- **Inside a Livewire component, the suffix of an [input](https://docs.wirekit.app/components/input) and the brand of an [app rail](https://docs.wirekit.app/components/app-rail) are updated as a block when they come or go.** A comment in the code of the tag before each of them made Livewire read the block as part of the tag, so it marked the block at its end only, and an update patched the suffix or the brand by its position among the nodes around it.

- **The hints of a [collapsible card](https://docs.wirekit.app/components/card#a-card-that-folds) drop under its heading where the head has no room for both,** as the buttons of a card header do. The heading, the hints and the chevron stood on one line that never wrapped, so a heading with a word that does not break, such as a product code, and a badge in the hints made the card wider than its column on a phone, or the heading ran into the hints. The chevron keeps to the end of the head.

- **A read-only or disabled [editor](https://docs.wirekit.app/components/editor#read-only) shows its document once the engine takes over.** Neither has a form field, and since 2.66.0 the engine read the document only from that field, so on a page that loads an engine it replaced the first paint with an empty document: a moderation queue showed blank posts, and a form locked for review a blank body. The document given as `value` now reaches the engine without a form field, and the form still submits nothing for either.

- **A branch of a [tree view](https://docs.wirekit.app/components/tree-view) inside a Livewire component stays announced as closed after an update.** A branch rendered open and closed by the reader got its open state back from the server on the next update, so a screen reader heard "expanded" over a hidden group. The row now binds `aria-expanded` to the branch's state, which the update keeps.

- **A [tree view](https://docs.wirekit.app/components/tree-view), a [resizable](https://docs.wirekit.app/components/resizable) split and a [status matrix](https://docs.wirekit.app/components/status-matrix) inside a Livewire component keep what the reader did across an update.** An update put the server's markup back over what their scripts had written: a tree without a selected node lost its tab stop, so Tab passed it by, the handle of a split lost its role, its place in the tab order and its values, and the split jumped back to its default size, and a status matrix sent its tab stop back to the first cell. The tab stop stays where the reader left it, and the handle and the split stay as the reader set them.

- **A move on a [kanban](https://docs.wirekit.app/components/kanban) board inside a Livewire component is announced after the first one as well.** The live region the keyboard path speaks into was made by the script, and the update that saves a move took it off; the next sentence landed in a region made together with it, which a screen reader does not announce. A sortable column renders the region itself now.

- **A [dropdown](https://docs.wirekit.app/components/dropdown) inside a Livewire component keeps the link from its trigger to its menu after an update.** The update took the menu's id off, so the trigger's `aria-controls` named an element that was not on the page until the next full load. The menu takes its id back as soon as an update removes it.

- **The [chevron of a dropdown trigger](https://docs.wirekit.app/components/dropdown#trigger-indicator) turns on its own control alone.** It turned whenever any element around it reported itself expanded, so in a row of a tree or a table that a reader had opened, the chevron of a closed menu pointed up. It now follows the nearest element that reports a state, the button it stands in.

- **A long label no longer widens its tab of a [bottom nav](https://docs.wirekit.app/components/bottom-nav).** With a mouse, a label with a long word, as German has many, made its tab as wide as the word and pushed the bar past its frame, so the label was never cut and never showed whole on hover. Each tab now takes its share of the bar and cuts its label; on a touch screen the 44px floor of a tab stays.

- **A long label of a [data list](https://docs.wirekit.app/components/data-list#detail) in `detail` breaks inside its column and leaves the value its room.** The label's column was as wide as its text unbroken, so a label with no space in it, such as a file name, ran past the list on a phone and left the value a few pixels, broken letter by letter. The column now holds its content up to 10rem, or up to 40% of the row where that is wider, and a longer label breaks inside it. In `summary` the value's column has the same limit, so a long code beside a label breaks in its column instead of pushing the label out. Labels and amounts within the limit stand as before.

- **A [price](https://docs.wirekit.app/components/price#fitting-a-narrow-column) wider than its column breaks its line, and "from" stays with its amount.** The line never broke, so in a narrow column, such as a table cell on a phone, a price ran past the column and widened it. It now breaks between its parts, and the word "from" and the amount stand together: the struck price on the first line, "from €179.10" whole on the next. A screen reader reads the price as before.

- **A row in the slot of a [cart summary](https://docs.wirekit.app/components/cart-summary#your-own-rows) stands in its columns.** A `data-list.item` there took the default layout rather than the summary's, since the slot renders before the summary's own list: a box of its own in one cell, its label at a third of that cell, so a longer label broke over several lines and two rows could stand side by side. It now stands like the rows the component draws, the label on the left and the amount flush right under the others. A row that names its own `layout` keeps it.

- **The description of a [product card](https://docs.wirekit.app/components/product-card) without a link shows whole on hover.** It is cut after two lines; a card with a link leads to the whole text on its page, and one without showed the rest nowhere. Such a card carries the description as its title now.

- **A long label of a compact [file upload](https://docs.wirekit.app/components/file-upload) shows whole on hover.** The compact control cuts its label so the row it sits in keeps its width, and nothing showed the rest of it. The cut label carries its whole text as its title now; a screen reader always heard it whole, as the name of the field.

- **The edge shadow of a [table](https://docs.wirekit.app/components/table) that scrolls sideways is as strong at its top row as anywhere else.** It runs the full height of the frame, and it was a radial gradient dense only at the middle of that edge, so on a list taller than the screen the rows a reader sees first showed almost none of it and a cut-off column gave no sign that the table continued. Every scroll shadow is now a linear gradient across its strip, equally dense along its whole edge: the sideways pair of the table, the [data table](https://docs.wirekit.app/components/data-table) and the [segmented control](https://docs.wirekit.app/components/segmented-control), and the top and bottom pair of the [sticky panel](https://docs.wirekit.app/components/sticky-panel), the [scope switcher](https://docs.wirekit.app/components/scope-switcher) and the [sidebar](https://docs.wirekit.app/components/sidebar), mirrored right to left as before.

- **The first unsaved change of a [status matrix](https://docs.wirekit.app/components/status-matrix), the first selected row of a [data table](https://docs.wirekit.app/components/data-table) and the empty state of a [command palette](https://docs.wirekit.app/components/command-palette) are announced reliably.** Each was a live region that showed together with its text: the matrix's count behind its own toggle, the table's count in the bar that shows with a selection, and the palette's "no results" behind the toggle that shows it. A screen reader announces text that appears in a region it already knows and a region that appears with its text unreliably, so the first change could go unheard. The three regions are in the page from the first render now, and only their text changes. `command-palette.empty` carries no role of its own, since the palette reads it out from its status region. A role passed on it still lands, and the palette then leaves the announcement to that role: `role="none"` keeps an application that announces the empty state itself from being heard twice.

- **The [reading time](https://docs.wirekit.app/components/reading#reading-meta) follows an article that a Livewire update renders.** The update took the per-paragraph annotations out of the article and none came back, and the estimate stayed at the words the page loaded with. It counts the article again in the next frame now, puts the annotations back, and leaves its own annotations out of the count.

- **A [reading minimap](https://docs.wirekit.app/components/reading#reading-minimap) in `rendered` mode keeps its picture through a Livewire update.** An update that left the article as it was took the drawn minimap out, and it stayed empty until the article changed. The hover preview keeps its frame and its place through an update as well.

- **A [table](https://docs.wirekit.app/components/table#client-side-sorting-alpine) sorted with `alpine-sort` inside a Livewire component stays sorted through an update.** The update put the rows back in the order the server rendered, while the header went on announcing the sort and showing its arrow. The table sorts again before the next paint now, by the values the update brought, and a sort that already holds moves no row.

- **A panel opened below its trigger stays beside it on a short window.** The [navigation menu](https://docs.wirekit.app/components/navigation-menu), the [popover](https://docs.wirekit.app/components/popover) with a top or bottom placement, and with it the [scope switcher](https://docs.wirekit.app/components/scope-switcher), the [color picker](https://docs.wirekit.app/components/color-picker), the [filter builder](https://docs.wirekit.app/components/filter-builder) and the [notification center](https://docs.wirekit.app/components/notification-center) moved a panel taller than the room below its trigger up until it fit the window, and so over the trigger: at 400% zoom a mega menu covered the trigger that keeps the focus while it is open, and the color picker's panel the swatch that shows its value. The panel now stays on the side of its trigger with more room, capped to that room and scrolling inside, and a wide panel still moves sideways to stay on a narrow screen. A [context menu](https://docs.wirekit.app/components/context-menu) still moves into the window over the point it opened at.

- **A [data table](https://docs.wirekit.app/components/data-table#after-a-bulk-action) follows a selection its component clears.** The selection lived in the browser alone, so a bulk action that emptied the bound list left the bar showing the old selection, and the next change sent its ids again. With `selected`, and `all-matches` for every match, the table opens with the component's selection and takes it from a response that changed it, while a click made after the request left stays the reader's.

- **The header checkbox of a [data table](https://docs.wirekit.app/components/data-table#server-mode-large-datasets) in server mode selects and clears its page, and leaves the other pages alone.** It replaced the selection with the rows on screen, so selecting page two dropped what the reader had selected on page one, and clearing it cleared every page. Its mixed state now describes the page, where a selection on another page alone showed it mixed.

- **A panel placed beside its trigger that fits on neither side opens below or above it.** A [hover card](https://docs.wirekit.app/components/hover-card), a [multi-select](https://docs.wirekit.app/components/multi-select) or a [dropdown](https://docs.wirekit.app/components/dropdown) placed `left` or `right`, a [tour](https://docs.wirekit.app/components/tour) step beside its target and the submenus of the dropdown, the [menubar](https://docs.wirekit.app/components/menubar) and the [context menu](https://docs.wirekit.app/components/context-menu) flipped to the opposite side only, and on a narrow screen they stood partly outside the window: a hover card is 288px wide, so beside a trigger on a 375px phone it rarely fit. Where a side has room, nothing changes.

- **A submenu taller than the window scrolls in itself.** The submenus of the [dropdown](https://docs.wirekit.app/components/dropdown), the [menubar](https://docs.wirekit.app/components/menubar) and the [context menu](https://docs.wirekit.app/components/context-menu) had no limit to their height, so on a page zoomed to 400% or a phone held sideways a long one ran past the bottom of the window, where neither a scroll nor the focus reached its last entries. They are capped to the window and scroll, as their menus already did. So is a step of a [tour](https://docs.wirekit.app/components/tour), whose Back and Next stood past the edge of a short window while its focus held the reader there, and which is no wider than a 320px window either.

- **An overlay refuses a `placement` it cannot place.** A [tooltip](https://docs.wirekit.app/components/tooltip), a [popover](https://docs.wirekit.app/components/popover), a [hover card](https://docs.wirekit.app/components/hover-card), a [dropdown](https://docs.wirekit.app/components/dropdown), a [tour](https://docs.wirekit.app/components/tour) step and the submenus took any word, and one outside the twelve placements, such as `botom`, put the panel on the corner of its trigger with nothing said. In debug the word is refused with the one it most resembles, and in production the component uses its default and logs the word, as the [combobox](https://docs.wirekit.app/components/combobox) and the [multi-select](https://docs.wirekit.app/components/multi-select) already did.

- **A prop that takes one of a few values reports any other.** The `size` of a [combobox](https://docs.wirekit.app/components/combobox), a [checkbox](https://docs.wirekit.app/components/checkbox), a [date picker](https://docs.wirekit.app/components/date-picker) and twelve more form controls, the `position` of a [toast region](https://docs.wirekit.app/components/toast) and a [scroll-to-top button](https://docs.wirekit.app/components/scroll-to-top), the `variant` of an [accordion](https://docs.wirekit.app/components/accordion), a [navbar](https://docs.wirekit.app/components/navbar) and a [sidebar](https://docs.wirekit.app/components/sidebar), the `orientation` of a [stepper](https://docs.wirekit.app/components/stepper), and fifty-three more props took any word and rendered their default for one they did not know, while an [input](https://docs.wirekit.app/components/input) and the other components reported the same word. So did a prop that takes a switch or one word: `truncate="tooltp"` on a [text](https://docs.wirekit.app/components/text) cut the line without its tooltip, as `true` does. Each now goes through [strict validation](https://docs.wirekit.app/strict-validation) as every prop with a fixed set of values does: with debug on, a Pest test or an `artisan` command throws on an unknown value, and a request logs it and renders what it rendered before. A bound `null` or an empty string is still the default, without a word. A prop whose default is none, such as an [avatar](https://docs.wirekit.app/components/avatar)'s `status`, stays none for an unknown value rather than taking the first of the list. A [stats](https://docs.wirekit.app/components/stat) grid given its `cols` as a number, `:cols="3"`, now lays out three columns, where it fit its stats to the width before. A [chart](https://docs.wirekit.app/components/chart) whose stream mode was another word than `strict` or `stream` let a streamed series grow without a bound; the word is reported and the series is capped, as `strict` does.

- **A prop that takes a number reports a text that holds none.** On most such props a text read as the default without a word: a `delayShow` of `soon` on a [tooltip](https://docs.wirekit.app/components/tooltip), a `maxTags` of `ten` on a [tags input](https://docs.wirekit.app/components/tags-input), a `weekStartsOn` of `monday` on a [calendar](https://docs.wirekit.app/components/calendar), a `max` of `1OO` or a `step` of `0,5`, while a prop with a fixed set of values reported an unknown one. Each now goes through [strict validation](https://docs.wirekit.app/strict-validation#numbers): with debug on, a Pest test or an `artisan` command throws, and a request logs it and renders as before, with the default or, for the few props that take the number a text starts with, such as the `searchDebounce` of a [data table](https://docs.wirekit.app/components/data-table), with that number. An empty text and a number written as text pass as before. The value of a field is not checked, since after a failed validation it holds what the reader sent, such as the `minValue` and `maxValue` of a [range slider](https://docs.wirekit.app/components/range-slider).

- **A prop that takes a list reads a text as an empty list instead of ending the page.** `options="Red,Green"` written without its colon arrives as a text, and so does a JSON column read without its `array` cast. A [select](https://docs.wirekit.app/components/select), a [combobox](https://docs.wirekit.app/components/combobox), [tabs](https://docs.wirekit.app/components/tabs), a [stepper](https://docs.wirekit.app/components/stepper) and nine more components ended the page with a type error at the first loop over it, and the other list props read the text as nothing without a word. Each now goes through [strict validation](https://docs.wirekit.app/strict-validation#lists): with debug on, a Pest test or an `artisan` command throws, and a request logs it and renders the component with an empty list. An empty text is an empty list without a report. A prop that takes a text as well reads it as before: the name of a [message](https://docs.wirekit.app/components/message)'s author, the comma-separated value of a [multi-select](https://docs.wirekit.app/components/multi-select) or a [tags input](https://docs.wirekit.app/components/tags-input), and a single country written as text on a [phone field](https://docs.wirekit.app/components/phone). The arguments of a [chart](https://docs.wirekit.app/components/chart) keep the types its class declares: a text in its `labels`, `datasets` or `options` still ends the page with a type error that names the argument.

- **A prop that takes a text reads a list as none instead of ending the page.** A `label`, a `hint`, a `title` or another text prop given a list, a collection or an object without a text of its own ended the page with a type error in most components, in a request too: `__('checkout.address')` returns a list when the key names a group of lines rather than one. Each now goes through [strict validation](https://docs.wirekit.app/strict-validation#texts): with debug on, a Pest test or an `artisan` command throws, and a request logs it and renders the component without the prop. An object that writes itself as text, such as an `HtmlString` or a date, is read as before, and so is a list given to the author of a [message](https://docs.wirekit.app/components/message) or to the badge label of an [app rail](https://docs.wirekit.app/components/app-rail) item.

- **A label given as markup, an `HtmlString`, names its element by its text.** Written into `aria-label`, `placeholder`, `title` or `aria-valuetext`, its markup stood in the attribute: a screen reader read the tags out, and a double quote in it ended the attribute early, so the rest of the tag landed on the page as text. Every component writes the text of such a prop there, and where a script shows it, the panels a [dropdown](https://docs.wirekit.app/components/dropdown), a [menubar](https://docs.wirekit.app/components/menubar), an [alert dialog](https://docs.wirekit.app/components/alert-dialog) or a [drawer](https://docs.wirekit.app/components/drawer) places at the end of the page and the search field of a [command palette](https://docs.wirekit.app/components/command-palette) included. An id or a menu's name derived from the label takes its text as well, while the markup stays where the component shows the prop on the page. The same holds for the props that carry a text under another name: the `alt` of an [avatar](https://docs.wirekit.app/components/avatar) or a [flag](https://docs.wirekit.app/components/flag), the `before-alt` and `after-alt` of an [image compare](https://docs.wirekit.app/components/image-compare), the `name` of an [assistant message](https://docs.wirekit.app/components/assistant-message), a [profile](https://docs.wirekit.app/components/profile), an [attachment](https://docs.wirekit.app/components/attachment) or an item of a [cart list](https://docs.wirekit.app/components/cart-list), the `filename` of a [code block](https://docs.wirekit.app/components/code-block), the `trigger` of a [navigation menu](https://docs.wirekit.app/components/navigation-menu) item or a [collapsible](https://docs.wirekit.app/components/collapsible), the `question` of an [unsaved hint](https://docs.wirekit.app/components/unsaved-hint), and the `tooltip` that names a [toggle button](https://docs.wirekit.app/components/toggle-button) without a visible label. So do the names a component writes in one of its forms only: the clear button of an [input](https://docs.wirekit.app/components/input) and of the [date](https://docs.wirekit.app/components/date-picker), [time](https://docs.wirekit.app/components/time-picker) and [date and time](https://docs.wirekit.app/components/datetime-picker) pickers, the end field of a date range, the name of a [stat](https://docs.wirekit.app/components/stat) with an `intent`, the remove button of a dismissible [badge](https://docs.wirekit.app/components/badge), and the placeholder of a [translatable input](https://docs.wirekit.app/components/translatable-input) with several lines. The unit of a cart item shows its markup, and the placeholder in the trigger of a date picker's popover its text, as the trigger of a date and time picker does.

- **A [field](https://docs.wirekit.app/components/field)'s `help` given as markup shows the markup in its tooltip, not its tags.** An `HtmlString` as the help of any field showed its tags as text in the tooltip, and so did one as the heading of [shortcuts](https://docs.wirekit.app/components/shortcuts). The placeholder of a [date and time picker](https://docs.wirekit.app/components/datetime-picker), the name of the menu of an [overflow nav](https://docs.wirekit.app/components/overflow-nav), the words of a [sign-in button](https://docs.wirekit.app/components/sign-in-button) and the name a [tooltip](https://docs.wirekit.app/components/tooltip) gives its trigger read the text of such a value instead of its tags.

- **A value shared with every view no longer fills a prop or a slot the caller left out.** An application that shares its page title through `View::share` saw it as the heading of every [alert](https://docs.wirekit.app/components/alert) and [empty state](https://docs.wirekit.app/components/empty-state) written without one, and a value shared under the name of another prop, such as `label`, `size` or `href`, reached every component that declares it. A value shared under the name of a slot did the same: a status shared from the session stood under every [filter builder](https://docs.wirekit.app/components/filter-builder), and a text shared as `meta` ended the page of every [page header](https://docs.wirekit.app/components/page-header) written without that slot. A prop the caller leaves out takes its default, a slot reads as not given, and every other view still reads the shared value. The components still read the shared error bag.

- **A composer the application registers for every view changes no prop or slot of a component.** A composer for `*` that writes a `title` into every view replaced the title of every [alert](https://docs.wirekit.app/components/alert) and [empty state](https://docs.wirekit.app/components/empty-state), the one a caller wrote on the tag included, since it runs after the component has read its tag. A WireKit view renders the props and slots its caller wrote and its defaults without them, and every other view still gets what the composer gives it. That holds as well for a composer another package or the application registers while the application boots, and for one the application registers in the `register()` method of a service provider. A composer registered after the application booted, in a middleware for instance, still runs after this.

- **A component inside another takes its parent's settings, not those of an unrelated ancestor.** Whenever their own parent was written without the setting, the questions of a [FAQ](https://docs.wirekit.app/components/faq) took the `size` and the heading `level` of a [card](https://docs.wirekit.app/components/card) around it, the items of a [navbar](https://docs.wirekit.app/components/navbar) inside a compact [toolbar](https://docs.wirekit.app/components/toolbar) were compact, and a [table](https://docs.wirekit.app/components/table) inside a [page header](https://docs.wirekit.app/components/page-header) written with `stack-below` stacked its rows. The items, tabs, steps and cells of an accordion, a FAQ, a tab list, a navbar, a sidebar, an app rail, a bottom navigation, a data list, a wizard and a table take such a setting from their own family now, past any other component between.

- **A [table](https://docs.wirekit.app/components/table) inside a cell of another keeps its own stripes, hover, density, sticky head and frozen column.** The parts of a table read `striped`, `hoverable`, `compact`, `sticky-header` and `sticky-column` from a table around them at any depth, so a plain table in a cell of a striped, compact table was striped and compact, its head stuck in the outer table's scroller, and its first column froze at the outer table's edge. Each part reads them from its own table now, as the frozen column of the stylesheet already did, and so does the padding the stylesheet gives the plain cells of a table.

- **A [carousel](https://docs.wirekit.app/components/carousel) in a slide of a carousel of the other orientation keeps its own layout.** A vertical carousel in a horizontal one took the gutter the horizontal one keeps for its arrows, and the slides of a horizontal carousel in a vertical one took the full width and height of a vertical carousel's slides, so one showing several slides at a time showed one. The stylesheet reads the orientation from each carousel's own root now, as it already read `per-view`.

- **A [carousel](https://docs.wirekit.app/components/carousel) counts, shows and steps through its own slides only, with a carousel in one of them.** The slides of the carousel inside counted among the outer carousel's: it drew a dot for each of them, could take one of them for the slide in view, and End went to the last of them.

- **A [table](https://docs.wirekit.app/components/table) sorted with `alpine-sort` moves only its own rows.** With a table in one of its cells, sorting moved the head and the rows of that table into its own body, and a head of that table naming the same column decided which cell a row was sorted by. The sort reads its own body, rows and head now.

- **A menu, a tooltip, a popover or a dialog opened in a [light or a dark island](https://docs.wirekit.app/theming#a-light-island-in-a-dark-page) takes the island's mode.** The panel is placed at the end of the page, outside the island, so it took the page's mode: the menu of a button in a light island on a dark page opened dark. A panel takes the class of the nearest island it was opened from, keeps it through a Livewire update, and reads it again each time it opens or closes. A panel whose own markup names a mode keeps its own.

- **A panel opened in a section that sets `lang` or `dir` names the same language and direction.** A menu, a popover or a dialog in a section with `lang="de"` on an English page stood outside that section at the end of the page, so a screen reader read its entries as English, and in a section with `dir="rtl"` its text ran left to right. Like the mode of an island, the panel takes both from the nearest element around it that sets them, keeps them through a Livewire update and reads them again each time it opens or closes; what its own markup names, or another script writes, stays.

- **An overlay opened inside another keeps the outer one open.** A combobox, a dropdown or a picker in the panel of a [popover](https://docs.wirekit.app/components/popover) stands beside that panel, since every panel is placed at the end of the page, and a press on one of its options closed the popover. The same held for the panel of a [navigation menu](https://docs.wirekit.app/components/navigation-menu) and the menu of a [menubar](https://docs.wirekit.app/components/menubar), and a [hover card](https://docs.wirekit.app/components/hover-card) closed a moment after the focus moved into the menu of a dropdown in it. A popover opened in the panel of another closed the outer one, and its own trigger with it. Each now counts a panel opened from inside its own as inside, and an overlay of the same kind opened inside it is no longer taken for a sibling.

- **A key an element inside a menu already answered leaves the menu as it was.** In a [dropdown](https://docs.wirekit.app/components/dropdown) or a [context menu](https://docs.wirekit.app/components/context-menu), the Escape that dismissed the tooltip of a cut label in an item closed the menu as well and moved the focus to its trigger, and an arrow key or a letter that an element inside had already taken still moved the focus between the items. A key that something inside the menu answered is spent now, as it is in a dialog, and the next Escape closes the menu. With the focus in the menu of a dropdown inside a [hover card](https://docs.wirekit.app/components/hover-card), Escape closes that menu and leaves the card, which closes on the next one.

- **The arrow keys of [tabs](https://docs.wirekit.app/components/tabs) stay in their own row with a tabs in a panel.** Tabs nested in one of the panels put their tabs under the same element as the outer row, and the arrow keys, Home and End walked both: from the last outer tab the focus went on into the inner ones instead of back to the first, and End landed on the last inner tab. They walk their own row now, as the tabs pattern asks.

- **A [pagination](https://docs.wirekit.app/components/pagination) given something other than a paginator says so.** A number, `true` or a list ended the page with a type error that named neither the component nor the prop, and a collection, as `all()` returns where `paginate()` was meant, rendered no pages without a word. Each is reported through strict validation now and renders nothing, as no paginator does.

- **A number beyond the integer range ends no page on PHP 8.5.** Given to the `surface` of a [badge](https://docs.wirekit.app/components/badge), a [button](https://docs.wirekit.app/components/button) or a [card](https://docs.wirekit.app/components/card), the `variant` of a card or an [empty state](https://docs.wirekit.app/components/empty-state), the `intent`, `tone` or `size` of a [feature](https://docs.wirekit.app/components/feature), the `layout` or `asideWidth` of a [hero](https://docs.wirekit.app/components/hero), the `size` of an [icon](https://docs.wirekit.app/components/icon), the `kind` of an [activity row](https://docs.wirekit.app/components/activity-row), the `preset` of a [reveal](https://docs.wirekit.app/components/reveal), the `intent` of a [spinner](https://docs.wirekit.app/components/spinner) or the `value` of a [rating](https://docs.wirekit.app/components/rating), a number such as `1e21` ended the page with a warning about casting it to an integer. It is read as any other value that does not fit now, and strict validation reports the props that take a word. The same held where one branch casts a prop: the `progress` of an uploading [attachment](https://docs.wirekit.app/components/attachment), the `searchDebounce` of a [data table](https://docs.wirekit.app/components/data-table) or a [filter builder](https://docs.wirekit.app/components/filter-builder) with a search field, the `max` of the deprecated [`progress.circle`](https://docs.wirekit.app/components/progress), the `size` and `margin` of a [QR code](https://docs.wirekit.app/components/qr-code), the `detailsColspan` of a [table](https://docs.wirekit.app/components/table) row, the `step` of a [time picker](https://docs.wirekit.app/components/time-picker) with `popover`, the `months` of a [date picker](https://docs.wirekit.app/components/date-picker) with `popover`, and the `maxlength` of an [input](https://docs.wirekit.app/components/input) or a [textarea](https://docs.wirekit.app/components/textarea) with `counter`. Below PHP 8.5 the number turned into an unrelated one there, such as a search field waiting `8446744073709551616ms` for `-1e19`. It reads as zero progress, no wait, the default maximum, size and quiet zone, no span, no step, the default months and no limit now.

- **A [calendar](https://docs.wirekit.app/components/calendar) draws the layout for the months it shows.** Given a `months` that holds no whole number, `1e21` or `1.5`, it drew one month in the layout for several, since its view read the value as given and its script as one month. The view reads it as the script does now, one to four months, and a [date picker](https://docs.wirekit.app/components/date-picker) and a [datetime picker](https://docs.wirekit.app/components/datetime-picker) hand their calendar that number.

- **An `id` with a space keeps the references built on it.** Given one, such as an id written from a row's name, an [inline edit](https://docs.wirekit.app/components/inline-edit) named it in its label's `for` while its field wrote the space as a hyphen, so the field had no name from its label and its hint was not read. A [data table](https://docs.wirekit.app/components/data-table)'s caption and the panels of a [sidebar](https://docs.wirekit.app/components/sidebar)'s collapsible sections and groups were named by references that no element carried, since a list of ids splits on a space. Each writes the space as a hyphen now, as the other components do.

- **A delay of 2^31 milliseconds or more waits as long as a timer can, not no time at all.** Browsers read the delay of `setTimeout` and `setInterval` as a 32-bit integer and run a timer whose delay does not fit at once. Given such a number, `PHP_INT_MAX` among them, the `duration` of a [toast region](https://docs.wirekit.app/components/toast), the `delayShow` and `delayHide` of a [tooltip](https://docs.wirekit.app/components/tooltip) or a [hover card](https://docs.wirekit.app/components/hover-card), the `interval` of a [carousel](https://docs.wirekit.app/components/carousel), the `duration` of a [clipboard button](https://docs.wirekit.app/components/clipboard-button), the `showAfter` of a [page progress](https://docs.wirekit.app/components/page-progress), the `simulateSpeed` of a [stream](https://docs.wirekit.app/components/stream), the `searchDebounce` of a [combobox](https://docs.wirekit.app/components/combobox), a [multi-select](https://docs.wirekit.app/components/multi-select), a [data table](https://docs.wirekit.app/components/data-table) or a [filter builder](https://docs.wirekit.app/components/filter-builder), the `submitOnceRelease` of a [form](https://docs.wirekit.app/components/form) and the `saveTimeout` of an [inline edit](https://docs.wirekit.app/components/inline-edit) waited none: a toast meant to stay closed at once, and a form's guard against a second submit held for nothing. Such a delay is held to the longest a timer waits now, and a carousel given an `interval` of zero or below turns at its default instead of as fast as the browser lets it.

- **An [icon](https://docs.wirekit.app/components/icon) in running text is followed by no space, and a missing icon takes the display a class gives it.** A named icon ended its output with a line break after the SVG, and the placeholder of a missing icon after its span, which a page shows as a space between the icon and the period or comma that follows. The placeholder also wrote its display inline, so a `block` or `hidden` class on the tag never reached it.

- **A radio item of a [dropdown](https://docs.wirekit.app/components/dropdown) takes only the name of an Alpine property as its `model`.** The value was written into four Alpine expressions as it came, so a model holding anything else, such as a value taken from data, ran as code in the browser. A name or a path such as `filters.sort` binds as before; anything else is reported through strict validation and the item renders without a model.

- **A date that names a day that does not exist is reported, not moved into the next month.** A [countdown](https://docs.wirekit.app/components/countdown), an [event calendar](https://docs.wirekit.app/components/event-calendar), a [message](https://docs.wirekit.app/components/message), a [review](https://docs.wirekit.app/components/review) and a [date separator](https://docs.wirekit.app/components/date-separator) read `2026-02-30` as 2 March without a word. Such a date is reported through strict validation now and read as no date, as a text that names none is.

- **A [calendar](https://docs.wirekit.app/components/calendar), a [date picker](https://docs.wirekit.app/components/date-picker), a [datetime picker](https://docs.wirekit.app/components/datetime-picker) and a [time picker](https://docs.wirekit.app/components/time-picker) report a prop written wrong that they dropped without a word.** An `openTo` that names no day or month (no day or moment on a datetime picker), a `minRange` or `maxRange` that holds no number, a `defaultTime` that names no time and a `format` other than `12h` or `24h` are reported through strict validation now, as `min`, `max` and `minTime` are. In a request each still draws as if it were left out.

- **An [OTP input](https://docs.wirekit.app/components/otp-input) with parentheses, brackets, braces, a slash or a bar in its `alphabet` keeps its pattern.** Browsers compile a field's `pattern` with the `v` flag, under which these characters are syntax inside a character class, so the pattern did not compile and the browser ignored it, with an error in the console. They are escaped now, as the backslash, the closing bracket, the caret and the hyphen were.

- **A component without the part it needs says which part that is.** A [popover](https://docs.wirekit.app/components/popover), a [hover card](https://docs.wirekit.app/components/hover-card) and a [context menu](https://docs.wirekit.app/components/context-menu) without their `trigger` slot, and an [image compare](https://docs.wirekit.app/components/image-compare) without its images, ended the page with an undefined variable; each names the slot or the props it needs now. An [icon](https://docs.wirekit.app/components/icon) without a name is reported through strict validation and draws the placeholder a missing icon draws, where it ended the page with a type error.

- **A switch reports a text that says neither on nor off.** A prop such as the `dismissible` of a [modal](https://docs.wirekit.app/components/modal) read `true`, `false`, `on`, `off`, `yes`, `no`, `1` and `0`, and any other text as on without a word, so `dismissible="flase"` left the dialog dismissible. Each switch now goes through [strict validation](https://docs.wirekit.app/strict-validation#switches): with debug on, a Pest test or an `artisan` command throws, and a request logs it and renders as before, with the switch on. An empty text is off, and the prop's own name, `disabled="disabled"` as HTML writes it, is on, both without a report. The `wrap` of a [row](https://docs.wirekit.app/components/row) reports a word other than `responsive`, as the other props that take a switch or one word do.

- **An entry of [status tiles](https://docs.wirekit.app/components/status-tiles) without an `intent` draws a neutral tile.** It ended the page with a warning about the missing key, while the component meant neutral for it.

- **A range shows a validation message filed under one of its ends.** A [date picker](https://docs.wirekit.app/components/date-picker) with `range` sends `{name}[start]` and `{name}[end]`, and a rule on one end files its message as `{name}.start` or `{name}.end`. The picker read the error bag only by `{name}`, so after a failed validation it showed nothing and was not marked invalid. It now shows that message and carries `aria-invalid`, as it does for a message filed under its name. A [range slider](https://docs.wirekit.app/components/range-slider) does the same for a rule on one handle, `{name}.min` or `{name}.max`.

- **A form control without a `name` is no longer sent under a name WireKit made up.** An [input](https://docs.wirekit.app/components/input), a [toggle](https://docs.wirekit.app/components/toggle), a [select](https://docs.wirekit.app/components/select), a [tags input](https://docs.wirekit.app/components/tags-input), a [multi-select](https://docs.wirekit.app/components/multi-select) and twelve more took their `id` as their name, the last two with `[]` after it, and without an `id` from the page that was one WireKit counted out: an unnamed search field in a GET form put `input-1=…` into the address. Such a control now sends nothing, as the input page said it did. An `id` the page gives still names the field, and the radios of a single-choice [swatch group](https://docs.wirekit.app/components/swatch-group) keep a shared name, which is what makes them one choice. An [OTP input](https://docs.wirekit.app/components/otp-input) without a `name` still writes its code to the field `wire:model` binds.

- **A `readonly` on a [toggle](https://docs.wirekit.app/components/toggle), a [checkbox](https://docs.wirekit.app/components/checkbox), a [radio](https://docs.wirekit.app/components/radio), a [slider](https://docs.wirekit.app/components/slider) or a [color picker](https://docs.wirekit.app/components/color-picker) is reported while debugging.** HTML ignores `readonly` on a checkbox, a radio, a range and a color field, so these controls stayed operable, and the strictness gate counted them among the components that take it and said nothing. They now report it as doing nothing, and [`StrictnessGate::controlAttributesWithoutAControl()`](https://docs.wirekit.app/strict-validation#asking-the-gate-instead-of-reading-its-log) gives a test the same answer.

- **A [color picker](https://docs.wirekit.app/components/color-picker) with `popover` hands `autofocus` to its trigger.** The attribute landed on the element around the trigger, which cannot take the focus, so the page opened with nothing focused.

- **An [inline edit](https://docs.wirekit.app/components/inline-edit#bringing-your-own-control) no longer stops the form around it from submitting.** Its editor stays on the page while the value is shown, and a form checks every field it owns, shown or not. With `required` and an empty value, or as a number off its step (a price of 12.99 against the default step of 1), the hidden field failed that check, and the form's submit button did nothing, with no message on screen. The field of a closed editor is disabled now, which leaves it out of the check, and an open editor is checked as before. The page shows the same binding for a control in the `editor` slot.

- **What acts on a field reaches it on three more components.** A `min`, `max` or `step` on an [inline edit](https://docs.wirekit.app/components/inline-edit) with a number now reaches the number it opens. It landed on the element around the component, so the number had no bounds and stepped by one, and its arrows rounded a price to whole numbers. A `step` or `list` on a [date picker](https://docs.wirekit.app/components/date-picker#date-range) with `range` reaches both dates, as it reaches a single date. A `pattern` on a [translatable input](https://docs.wirekit.app/components/translatable-input) reaches every language's one-line field, as `maxlength` already did.

- **A `disabled` or `autofocus` written as `"false"` turns nothing on.** HTML reads both by their presence, so `disabled="false"` on a [field set](https://docs.wirekit.app/components/field) disabled every field in it, on a [copy button](https://docs.wirekit.app/components/clipboard-button), the close button of a modal or a drawer and seven more it disabled the button, and `autofocus="false"` focused a [button](https://docs.wirekit.app/components/button), a [tab](https://docs.wirekit.app/components/tabs) or a menu item as the page loaded. A value that reads as false now leaves the flag off, as it already did on the form controls, and a bare flag or `"true"` turns it on as before.

- **An `aria-describedby` on a [translatable input](https://docs.wirekit.app/components/translatable-input) describes every language's field.** It landed on the element around the languages, which nobody focuses, so no field read it. Each language's field now reads it after the message of the whole value, as every other form control does.

- **A `tabindex` on a [file upload](https://docs.wirekit.app/components/file-upload), a [multi-select](https://docs.wirekit.app/components/multi-select), a [tags input](https://docs.wirekit.app/components/tags-input), a [one-time code](https://docs.wirekit.app/components/otp-input) or a [translatable input](https://docs.wirekit.app/components/translatable-input) reaches its fields.** It landed on the element around them, so `tabindex="-1"` took none of their tab stops out, as on a honeypot field or a field in a folded section, and made the wrapper focusable instead.

- **`x-on:blur`, `x-on:focus` and `wire:blur` on a form component made of several parts [run as the reader leaves or enters the control](https://docs.wirekit.app/components/form#focus-and-blur-on-a-control-of-several-parts).** A tags input, a multi-select, a one-time code, a file upload, a date range, a color picker in a popover, a range slider, a rating, a segmented control, a swatch group, an editor, an inline edit and a translatable input take focus on their parts and never on the element the attributes land on, and neither event bubbles, so such a listener never ran. Each now fires both there, once on the way in and once on the way out, as a field does, and a move between its own parts or into a panel it opened elsewhere on the page fires nothing. A tags input and a multi-select fired the `blur` already and now fire the `focus` as well.

- **A color typed into a [color picker](https://docs.wirekit.app/components/color-picker#popover-mode) reaches the form as it was typed.** The plane and the hue slider hold saturation, brightness and hue in whole steps, and a typed, picked or starting color was read into them and sent back as the nearest color they reach: `#B87334` arrived as `#b87333`. The color now stands as it was read until the reader moves the plane or the hue slider.

- **A [filter builder](https://docs.wirekit.app/components/filter-builder) panel, a dropdown or any element with `x-show` and a transition, opened again while it closes, [reports no unhandled rejection](https://docs.wirekit.app/getting-started/integration#a-panel-opened-again-while-it-closes).** Alpine rejects the hide that the show cancels with a marker it treats as expected, but handles the rejection one frame later, so an opening inside that frame left it unhandled: the console read "Uncaught (in promise)", and an error monitor or a browser test that listens for unhandled rejections counted an error. WireKit's bundles give every hide a handler as it starts, and any other error in a hide still reaches the console.

- **A [filter builder](https://docs.wirekit.app/components/filter-builder#livewire-integration) bound with `wire:model.live` keeps a panel open when the answer to the last filter arrives.** A reader who applied a filter and opened the panel again before the server answered saw it close under them, and what they had entered was gone: the answer renders the builder again with the filters it holds, and that render reset the builder. The answer now changes nothing a reader has open. A set of filters the server changes still reaches the chips, and an edit that is open stays on its filter, or ends when the server removed it.

- **A [calendar](https://docs.wirekit.app/components/calendar), a [color picker](https://docs.wirekit.app/components/color-picker), a [date picker](https://docs.wirekit.app/components/date-picker) range, an [image comparison](https://docs.wirekit.app/components/image-compare), a [number input](https://docs.wirekit.app/components/number-input), a [phone field](https://docs.wirekit.app/components/phone), a [slider](https://docs.wirekit.app/components/slider), a [range slider](https://docs.wirekit.app/components/range-slider), a [tags input](https://docs.wirekit.app/components/tags-input), an editable [status matrix](https://docs.wirekit.app/components/status-matrix), a [toggle button](https://docs.wirekit.app/components/toggle-button) and a [branch switcher](https://docs.wirekit.app/components/branch-switcher) bound with `wire:model.live` keep what the reader did after a change when the answer to it arrives.** Each of them took the value it shows from the expression that starts it, so the answer, which renders the value its request carried, started the component again: digits typed since, a tag added since or a second click went back, a drag ended, the sentence about a corrected number disappeared, an open color panel closed, and a calendar returned to the month of its date. Through the binding the older value even reached the property. Each one now follows a value the server sets without starting again, and leaves alone an answer that only returns what it sent, as Livewire does with the property.

- **A [range slider](https://docs.wirekit.app/components/range-slider#livewire-integration) bound with `wire:model.live` keeps a second step taken while the first is on its way.** Each move fired `input` on both of its hidden fields, so on the first move the end that had not moved was written again as text where the server had sent a number. Every key of the range had changed, and Livewire sent the range as one object and kept that object itself as what the request carried. A step taken before the answer changed it as well, the answer then read as the server taking the step back, and the property kept the first step while the handle showed the second. Now `input` fires only on an end that moved, and on an end whose thumb does not show the stored value: both ends of a slider without `min-value` and `max-value`, whose first move replaces the stored range, and an end the scale held inside it.

- **The tooltip of a cut [text](https://docs.wirekit.app/components/text#truncation-with-a-tooltip) shows it in its own language.** With `truncate="tooltip"` the tooltip repeats a cut text whole, and it stands outside the text, so a name in another language, such as a product name marked with its own `lang`, appeared there in the language of the page, with the glyphs and quotation marks of that language. The tooltip now takes the language of the closest element that names one. Screen readers were not affected: they read the text from the element itself, which carried its language already.

- **An attribute bound to `null` leaves a component's own name, role and id in place, and so does a name, a description or a live region bound to `false`.** Blade writes nothing for either, so `:aria-label="$label"` with no label wrote no name, but the components counted it as given and left their own out: a [navbar](https://docs.wirekit.app/components/navbar) lost "Main navigation", the dialog of a [modal](https://docs.wirekit.app/components/modal) its name, a [combobox](https://docs.wirekit.app/components/combobox) its role, a [phone](https://docs.wirekit.app/components/phone) field `autocomplete="tel"` and a [data table](https://docs.wirekit.app/components/data-table) its id, and a [number input](https://docs.wirekit.app/components/number-input) marked its steppers disabled for a `null` `disabled`. Such an attribute now counts as not written, in every component.
- **An empty name leaves a component its own.** `:label="$section->title"` over a record without a title hands a component an empty text, and a component that names itself wrote it as its name: a [theme controller](https://docs.wirekit.app/components/theme-controller), a button that shows a symbol only, lost "Dark mode", a [bottom navigation](https://docs.wirekit.app/components/bottom-nav) "Main" and a [rating](https://docs.wirekit.app/components/rating) "Rating", and a [cart summary](https://docs.wirekit.app/components/cart-summary) wrote an empty heading. An empty `label`, `aria-label` or `placeholder` now hands over to the next name a component knows, down to its own, and so does the empty label of a part, such as the words of a [filter builder](https://docs.wirekit.app/components/filter-builder)'s add button, which had left the button without a name, and an `aria-label`, `aria-labelledby` or `aria-describedby` given as an empty text counts as not written, in every component, so the dialog of a [modal](https://docs.wirekit.app/components/modal) with a header is named by its header.
- **A [countdown](https://docs.wirekit.app/components/countdown) written into a sentence keeps the paragraph whole.** It rooted in a `<div>`, and a `<div>` inside a paragraph ends the paragraph in the parser: the time and the rest of the sentence fell out of it, and an empty paragraph followed. Everything a countdown renders is text-level, so it roots in a `<span>` now, which looks the same. A headless slot that holds block content takes `as="div"`.
- **A [ticker](https://docs.wirekit.app/components/ticker)'s delta and the number of reviews on a [product card](https://docs.wirekit.app/components/product-card) read in the page's language.** The delta was written as PHP writes a number, with a point in every language, so a German dashboard read `+8.4%` beside its translated words, and the name of the delta said the same; an absolute delta and the number of reviews stood ungrouped. Both go through the number format of the page now: `+8,4 %` and `1.234 Bewertungen` in German. A delta that is no number is shown as it comes.
- **A badge without text draws nothing.** `:badge="false"`, a badge of spaces and a `badge` slot that holds nothing, or only the markers Livewire writes around a condition, drew an empty pill on a [dropdown item](https://docs.wirekit.app/components/dropdown), a [sidebar item](https://docs.wirekit.app/components/sidebar), an [app rail item](https://docs.wirekit.app/components/app-rail), a [bottom nav item](https://docs.wirekit.app/components/bottom-nav), a [tab](https://docs.wirekit.app/components/tabs), an [indicator](https://docs.wirekit.app/components/indicator), a [product card](https://docs.wirekit.app/components/product-card) and an [activity row](https://docs.wirekit.app/components/activity-row). They draw nothing now, and `0` stays a count. The name of a bottom nav entry reads its count as the pill shows it, `1,234` rather than `1234`.
- **A count in the badge of a [tab](https://docs.wirekit.app/components/tabs) given through `items` is grouped as the page writes numbers.** A tab of its own wrote `1,234`, and one from `items` wrote `1234`; both write `1,234` in English and `1.234` in German now.
- **Page Up and Page Down in a [calendar](https://docs.wirekit.app/components/calendar#keyboard) keep the day.** They moved the focus to the first of the month they went to, where the date picker dialog of the WAI-ARIA practices, which the calendar follows, keeps the day's number, or takes the last day of a shorter month.
- **An expired [countdown](https://docs.wirekit.app/components/countdown) stops its clock.** Past the deadline it went on updating itself every second, or less often when it showed no seconds, for as long as the page stayed open, with nothing left to change: it shows its expired text, and `remaining` holds at zero. The tick stops at the deadline now, and a tab that comes back does not start it again.
- **Words in a [replay button](https://docs.wirekit.app/components/replay-button)'s slot name the button.** Its label named it whatever the slot showed, so a button that read "Play the animation again" answered to "Replay", and in another language every slot with words did: voice control could not reach it by what it showed. The label now names the button where the slot shows an icon alone, or where the label holds the words the slot shows.
- **An [image gallery](https://docs.wirekit.app/components/image-gallery)'s zoom buttons hold no figure.** A button takes text-level content only, and each thumbnail rendered a `<figure>` inside one, which an HTML validator reports on every image. The [image](https://docs.wirekit.app/components/image) takes `as="span"` for that place, rendering as a block with its caption as a line of its own, and the gallery uses it. The [collapsible](https://docs.wirekit.app/components/collapsible) page's slot example no longer puts a `<div>` and a `<p>` in its button.

- **A text prop given `false` or an empty string reads as none.** A condition at the call site such as `:help="$isNew && __('Optional')"` writes `false` when it fails, and a [review](https://docs.wirekit.app/components/review) drew an empty heading, the [label](https://docs.wirekit.app/components/label) of a form field a help button with nothing to say, a [sticky panel](https://docs.wirekit.app/components/sticky-panel) a landmark with an empty name, a [field set](https://docs.wirekit.app/components/field) and a sidebar group `0` as their legend and name, and a [drawer](https://docs.wirekit.app/components/drawer) an empty question before it discards. A boolean given to a label, a help, a title, a description, a caption, a placeholder or a language now reads as none, as `null` does; `0` stays a text. An empty string, or one of spaces, as a record with an empty column writes it, reads as none in the same way, so a [strength meter](https://docs.wirekit.app/components/strength-meter) with an empty label keeps its name. An empty `placeholder` still means no placeholder, as it does in HTML.

- **A word a component writes for itself, given `false` or an empty string, gives way to its own.** Given `false`, a [badge](https://docs.wirekit.app/components/badge)'s `dismissLabel` left its dismiss button without a name, a [radial progress](https://docs.wirekit.app/components/radial-progress)'s `valueText` wrote an empty `aria-valuetext`, a [pricing table](https://docs.wirekit.app/components/pricing-table) named its interval switch with nothing, and the `beforeLabel` and `afterLabel` of an [image compare](https://docs.wirekit.app/components/image-compare), a [notification center](https://docs.wirekit.app/components/notification-center) and the `addLabel` of a [filter builder](https://docs.wirekit.app/components/filter-builder) drew empty labels, links and buttons. An empty string reads as none in the same way: a tier of a [pricing table](https://docs.wirekit.app/components/pricing-table) with an empty `priceLabel` no longer loses its price, and a [data table](https://docs.wirekit.app/components/data-table) with an empty `emptyText` says its own sentence when nothing matches.
- **An [alert dialog](https://docs.wirekit.app/components/alert-dialog) without a description no longer points `aria-describedby` at nothing.** The reference went out whenever `describedby` was not set, and only `alert-dialog.description` carries the id it names, so a dialog without one, such as the example of the keyboard confirmation on its own page, pointed at an element that never renders unless `describedby="false"` was written. Unset, the dialog now points at its description when it holds one; `false` and `true` work as before.
- **A [price](https://docs.wirekit.app/components/price) in another language than the page marks its amounts with `lang`.** With a `locale` whose language is not the page's, the amount, the struck price, the delta and the unit price carry it, so a screen reader reads `1.234,50 €` by German rules rather than as another number by English ones. The word "from" and the name "Previous price" stay in the page's language. A [product card](https://docs.wirekit.app/components/product-card), a [cart line](https://docs.wirekit.app/components/cart-list), a [cart summary](https://docs.wirekit.app/components/cart-summary) and a tier of a [pricing table](https://docs.wirekit.app/components/pricing-table) show their prices this way, and an empty `locale` reads as the application's.
- **An icon that cannot be drawn no longer takes the page down from a menu or a navigation entry.** In a request, an unknown icon alias or one whose icon set is not installed leaves its [icon](https://docs.wirekit.app/components/icon) out and keeps the page, and a console or a test still fails on it. A [dropdown](https://docs.wirekit.app/components/dropdown) item and submenu, a [sidebar](https://docs.wirekit.app/components/sidebar) item and collapsible group, an [app rail](https://docs.wirekit.app/components/app-rail) item, a [menubar](https://docs.wirekit.app/components/menubar) submenu, a [context menu](https://docs.wirekit.app/components/context-menu) item and submenu, a [command palette](https://docs.wirekit.app/components/command-palette) item and its search field and a [floating action button](https://docs.wirekit.app/components/fab) drew the icon without that guard and answered with an error page instead.

- **Components in running text no longer put a space in front of the punctuation after them.** A [badge](https://docs.wirekit.app/components/badge), a [highlight](https://docs.wirekit.app/components/highlight), a [hover card](https://docs.wirekit.app/components/hover-card) on a name, a [status dot](https://docs.wirekit.app/components/status-dot), a [flag](https://docs.wirekit.app/components/flag), a [swatch](https://docs.wirekit.app/components/swatch), the [label](https://docs.wirekit.app/components/label) of a form field, a [button](https://docs.wirekit.app/components/button) and the components drawn as one wrote a line break after their closing tag, which the browser draws as a space, so a sentence written as "By Ann, today" read "By Ann , today". So did [text](https://docs.wirekit.app/components/text), a [heading](https://docs.wirekit.app/components/heading) and a [tooltip](https://docs.wirekit.app/components/tooltip) written as a span. Each now ends with its own closing tag, and a line break inside the element stays as it was.

- **A [badge](https://docs.wirekit.app/components/badge) or a [toggle button](https://docs.wirekit.app/components/toggle-button) with a tooltip stays inside its paragraph.** The tooltip around it rooted in a block element, and the browser's parser closes a paragraph in front of one: the badge stood on a line of its own, and the rest of the sentence fell outside the paragraph. Both now root their tooltip in a span, as a [status dot](https://docs.wirekit.app/components/status-dot) does, and so do the layer of an optimistic toggle button and the wrapper of a [scroll to top](https://docs.wirekit.app/components/scroll-to-top) button that the page shows and hides.

- **A [field set](https://docs.wirekit.app/components/field#a-group-error) with text fields in it shows its message once.** A text field, a select or a picker named for the set's key, as `emails[]` is in a set named `emails`, repeated the set's message under itself and kept it when the set's error was turned off, and the rejected entry of one field, such as `emails.1`, showed under that field and again as the message of the whole group. Such a control now leaves the group's message to the set, which the `<fieldset>` points at, and shows the entries below the key that are its own, which the set no longer takes for the group's.

- **A [field set](https://docs.wirekit.app/components/field#a-group-error) named the way a form names its controls shows its message once.** Laravel files the error of `address[country]` under `address.country`, and a set named `address[country]` read nothing from the error bag: each radio or checkbox inside showed the message under itself, once per option, and nothing described the `<fieldset>`. A `field.set` now reads its name in the spelling of the bag, as every control does, so `address[country]`, `roles[]` and `address.country` each name their group.

- **A named slot that a condition leaves empty draws nothing.** Livewire writes two HTML comments around every `@if`, so a slot whose content sits inside one arrives holding those comments when the condition is false. Components drew such a slot as soon as it was written: a [sticky panel](https://docs.wirekit.app/components/sticky-panel), a [kanban](https://docs.wirekit.app/components/kanban) column and a [command palette](https://docs.wirekit.app/components/command-palette) showed an empty bar with its border and padding, a [footer](https://docs.wirekit.app/components/footer) a rule above an empty row, a [callout](https://docs.wirekit.app/components/callout) a margin over nothing, and a [select](https://docs.wirekit.app/components/select) or a [combobox](https://docs.wirekit.app/components/combobox) with no options turned itself off and showed an empty message for an `empty` slot that held nothing. They now draw a slot only when it holds more than comments, as the label and icon slots already did, and a [swap](https://docs.wirekit.app/components/swap) shows its default slot when its `off` slot holds nothing. The same holds where such a slot stands in for another part: a [tooltip](https://docs.wirekit.app/components/tooltip) whose `content` slot holds nothing shows its `text` rather than an empty panel, so the control it sits on keeps its description, a [product card](https://docs.wirekit.app/components/product-card) keeps its `image` beside an empty `media` slot, and a [sidebar](https://docs.wirekit.app/components/sidebar) with a header and an empty footer, or the reverse, draws no empty band.

- **A [call to action](https://docs.wirekit.app/components/cta), a [hero](https://docs.wirekit.app/components/hero), a [timeline](https://docs.wirekit.app/components/timeline) item, a [tour](https://docs.wirekit.app/components/tour) step and a [brand bar](https://docs.wirekit.app/components/brand-bar) take their text slots as props as well.** `title="…"` on one of them became the element's tooltip and the heading was missing, as on a callout before, and `description`, `eyebrow` and `tagline` written as attributes were lost. Each now takes the text as a prop of the same name, and the slot wins when both are given.

- **An `aria-label` on a [translatable input](https://docs.wirekit.app/components/translatable-input) names it.** It stood on the element around the languages, which has no role, so a screen reader read no name: the set of languages went unnamed, and a single language's field had no name at all. With more languages it now names the set while each field keeps its language's name, and with one language it names the field. An `aria-labelledby` goes the same way.

- **The help of a [translatable input](https://docs.wirekit.app/components/translatable-input) names the value it explains.** With more than one language its question mark reported no field in its event, so a listener could not tell which value's help was asked for. It reports the value's name now, or the property it is bound to, or its id.

- **An `aria-label` given to a [skeleton](https://docs.wirekit.app/components/skeleton), the [editor's](https://docs.wirekit.app/components/editor) toolbar, a [tab list](https://docs.wirekit.app/components/tabs) or a [button group](https://docs.wirekit.app/components/button-group) names it.** These wrote a name of their own, "Loading", "Editor commands" or the one their `label` gave, and printed the given one beside it on the same element, where the browser keeps the first and drops the second. A role, a tabindex or a state written on a component that writes its own landed on one element twice in the same way. Each element now carries an attribute once: a given name wins, and so does the role of a container; the role of a menu item or a tab, its tabindex, and a state the component keeps stay the component's.

- **The − and + buttons of a [number input](https://docs.wirekit.app/components/number-input) follow a lock that comes after the page loaded.** They looked at the field's lock only when its value changed, so a field that started `disabled` and was freed later kept both buttons disabled until the reader typed a digit, and a field locked later, by itself or by a fieldset around it, kept buttons that looked in use and did nothing. They now follow the field's `disabled` and `readonly` and every fieldset around it.

- **A [date picker](https://docs.wirekit.app/components/date-picker) with `range` hands `form`, `readonly`, `autocomplete` and `autofocus` to its dates.** They landed on the row around the two fields, where they do nothing: a range in a form elsewhere on the page was not sent, and a readonly range stayed editable. Both date fields carry them now, as the single date's field always did, and `autofocus` goes to the start date.

- **[`wirekit:doctor:a11y`](https://docs.wirekit.app/cli-reference#wirekitdoctora11y) checks an icon-only button whose attributes hold a `>`.** A value such as `:attributes="new ComponentAttributeBag(['row' => $id])"` ended the button's tag for the scan at the arrow, so a button with only an icon and no `aria-label` went unreported. A button group is no longer read as a button either.

- **A [swatch](https://docs.wirekit.app/components/swatch) in the label of a [checkbox](https://docs.wirekit.app/components/checkbox) or a radio stands on the middle of the box.** A swatch beside a name made the first line of the label taller than its text, and the box, which stands on the middle of the first line of text, stood above the swatch's middle. In the label a swatch now takes the height of the line and reaches equally above and below it.

- **The color of a [swatch](https://docs.wirekit.app/components/swatch#a-color-behind-the-picture) stands alone where its picture does not load.** Given with an `image`, the `color` lies behind the picture: it shows through the picture's transparent parts and while the picture loads, and where the picture does not load it stands alone, where the picture's `<img>` drew the browser's mark for a broken picture over it. The picture is the background of the swatch's fill now. The swatch page said a picture stood in place of a color, and it and the [swatch group](https://docs.wirekit.app/components/swatch-group) page say where the color goes.

- **A y-axis label formatter a page sets for every [chart](https://docs.wirekit.app/components/chart) through `window.Apex` stays in charge under ApexCharts 8.** ApexCharts 8 lays a chart's own axis over the global one, so the label formatter the kit gives each axis hid the page's, on the axis and in the values of the tooltip. The kit sets none where the page set one, as it already did for the legend and the title of the tooltip.

- **[`wirekit:class-by-area`](https://docs.wirekit.app/cli-reference#wirekitclass-by-area) traces a container variant that follows another variant.** A class such as `xl:@max-5xl/wk-table:hidden` was listed as compiled CSS that no source emits, because only a class that opened with the `@` was read as a container variant.

- **[`wirekit:class-by-area`](https://docs.wirekit.app/cli-reference#wirekitclass-by-area) reads the classes a component hands through the attributes of a slot.** A class list given to a slot's own attributes was not read, so its classes were listed as compiled CSS that no source emits.

- **A deploy no longer logs that text falls back to system fonts.** The warning about a font that was never published came from every boot of the application, so a deploy wrote it from `package:discover`, which runs before `wirekit:publish-fonts` in the same Composer run and renders no page. It also said the text fell back to system fonts, which the package route prevents: [fonts](https://docs.wirekit.app/components/fonts) serves such a family through PHP. The line is written now when a page renders `<x-wirekit::fonts />`, once per family and hour, in the words of the comment it writes into the page: the family is served through PHP, and `php artisan wirekit:publish-fonts` makes it a static file.

- **The stylesheet of a font served through the package route keeps its URL from page to page.** A family that was never published loads through PHP, and the URL [fonts](https://docs.wirekit.app/components/fonts) wrote for it carried the time of the request instead of the time the bundled file last changed. It changed every second, so the browser fetched the stylesheet again on every page, though the route lets it stay in the cache for a year. The URL now changes when an update brings a new file.

- **One [Tailwind source per component](https://docs.wirekit.app/getting-started/integration#scanning-only-the-components-you-use) builds a narrower stylesheet in a Laravel application.** Tailwind reads the whole folder around a `@source` that lies in a directory git ignores, and `vendor/` is one, so a single declared source read every source beside it and the stylesheet carried the utilities of the whole catalog. Each source is now a folder of its own under the same path, `…/resources/tailwind/card.txt`, so the lines already declared narrow the build as they are. `wirekit:doctor` now also reads the views that packages register and names a component that only a package renders: run it after the upgrade, because such a component needs a line of its own once the declaration narrows.

- **A [spine-aware](https://docs.wirekit.app/components/spine-aware) block keeps its padding with [one Tailwind source per component](https://docs.wirekit.app/getting-started/integration#scanning-only-the-components-you-use).** It takes its inline padding from `WireKit::spinePadding()`, which builds the class in PHP, and the source of `spine-aware` carried none of the four tier classes, so an application that declared it built no padding for it and its content met the edge of the page. The source carries all four, the full template scan generates them whatever other components spell, and `php artisan wirekit:doctor` names `spine-aware.txt` for a view that calls the helper while no declared source carries its classes.

- **A [navigation menu](https://docs.wirekit.app/components/navigation-menu) in a [navbar](https://docs.wirekit.app/components/navbar) names its landmark apart from the bar's.** Both named their landmark `Main navigation` when the page gave them no name, so a screen reader listed two navigation landmarks of one name in a row, and an accessibility checker reported them as not unique. A menu named by default inside a navigation landmark of the same name now takes the name `Main menu`, translated like the other, and keeps it when Livewire renders the page again. A name the page gives either one stays as it is given.

- **A [tooltip](https://docs.wirekit.app/components/tooltip) ends where the control in its slot ends.** Its trigger is a block, so a button in it stood on a line of text, and the line reached a few pixels below the button: the collapse toggle of a [sidebar](https://docs.wirekit.app/components/sidebar) stood that much above the edge it was lined up with, and an icon button in a row stood above the row's middle. A control now stands at the top of the trigger's line.

- **The title of a [modal](https://docs.wirekit.app/components/modal#auto-close-button) stands on the middle of its close button.** The header lines its children up at the top, so a one-line title stood about 4px above the middle of the button and read as sitting high. Its first line now moves down by half the difference to the button, and a title of several lines keeps the button in the top corner, on the middle of its first line.

- **The one-character hotkey of a [command palette](https://docs.wirekit.app/components/command-palette#custom-hotkey) waits while single-key shortcuts are off.** A palette on `/` opened through the reader's switch in the [overview of keyboard shortcuts](https://docs.wirekit.app/components/shortcuts#single-keys) and through `data-wk-single-keys="off"` on a screen, which every other single key obeys (WCAG 2.1.4). A hotkey with `cmd`, `ctrl` or `alt` is not a single key and keeps working.

- **[Charts](https://docs.wirekit.app/components/chart) group the thousands of their values.** An ApexCharts chart wrote `278984,46` in its tooltip, in the cells of a treemap and on its y-axis, beside a page that wrote `278.984,46`. The values are grouped the locale's way now, also where the chart sets no decimals of its own, `value-grouping="false"` writes them ungrouped, and a chart takes the marks of the application's own number format where it gave one.

- **A cut name in a compact [cart line](https://docs.wirekit.app/components/cart-list#a-line-for-a-till) shows its whole wording in a tooltip.** The name showed it only in the browser's `title`, which a touch screen and the keyboard never show, and a cut variant showed it nowhere. Both now show it in the kit's tooltip while they are cut, on hover, on keyboard focus and on a tap.

- **On a touch screen the controls of a [cart line](https://docs.wirekit.app/components/cart-list#a-line-for-a-till)'s press stepper take the touch size as their own.** With `stepper="buttons"`, − and + drew a 44px hit area around their square. At `size="sm"` it reached into the quantity between them, and in the compact layout at `size="sm"` or `"md"` the hit area of the remove control reached 2px into the + beside it, so a tap on the edge of + went to the remove control. −, the quantity, + and the remove control beside them now stand at least 44px tall and wide on a touch screen, and none of them reaches its neighbor. At the default `size="lg"` the stepper keeps its size, and the remove control of a compact line grows from 40 to 44px on a touch screen.

- **`wk-fab-clearance` keeps the end of a long page clear of a [button back to the top](https://docs.wirekit.app/components/scroll-to-top#over-a-floating-action-button) over the floating action button.** The room it reserves counted the [floating action button](https://docs.wirekit.app/components/fab#keeping-content-out-from-under-it) alone, so at the end of a long page on a phone the button back to the top with `above-fab` covered the button at the end of the last row. While such a button is on the page, the room grows by its size and the gap it keeps, and it counts `--wk-fab-lift` as well.

- **A field bound with `wire:model.blur` or `wire:model.change` counts as unsaved.** The [unsaved hint](https://docs.wirekit.app/components/unsaved-hint#what-counts-as-unsaved) left such a field out, as if it sent its value by itself, so the page could be left with the change in it and no question. Livewire 4 sends a binding by itself only with `.live` or `.lazy`. Without `.live`, `.blur` and `.change` decide when the page writes the value, and the value waits for the next request.

- **The words beside the label of an unsaved field never move the field or run past the label.** In a narrow column they wrapped onto a line of their own with the label's last word and pushed the field below the fields beside it, where that word stood alone on its line they ran past the label's edge, and beside a switch they pushed the buttons next to it aside. Each label is now measured where it stands: the words while the field stays where it is and the label holds them, else a dot in the color of the unsaved line with the words as the label's title, else nothing. A label that does not stand above its field, around a switch or a single checkbox, shows no words. See [unsaved hint](https://docs.wirekit.app/components/unsaved-hint#the-words-beside-the-label).

- **An unsaved field says so to a screen reader on the field itself.** The words beside its label stayed out of its name, and the [unsaved hint](https://docs.wirekit.app/components/unsaved-hint#the-words-beside-the-label) only said that something was unsaved. While a field is unsaved, its description now names the same words, after the description it already had, and leaves it once the field counts as saved. A radio button, a checkbox of a list and an invalid field are not described, as they take no words.

- **An unsaved field in a drawer or a modal says so.** A scope with `x-wk-unsaved` inside a dialog tracked none of its fields, since the dialog is placed at the end of the page, outside the element of the Livewire component it belongs to: a changed field was never framed, the [unsaved hint](https://docs.wirekit.app/components/unsaved-hint) stayed hidden, and `.confirm` did not ask before the page was left. A scope around a dialog did not count the fields in it either. Both count the dialog's fields now, as they stand where the dialog is written, and so do `data-wk-unsaved-off`, a `wire:submit` of a form in a dialog and a `wirekit:saved` with `trigger`.

- **The button that takes a chip out is a 24px target.** The remove button of a pill in a [multi-select](https://docs.wirekit.app/components/multi-select), of a tag in a [tags input](https://docs.wirekit.app/components/tags-input) and of a chip in a [filter builder](https://docs.wirekit.app/components/filter-builder) measured 18 x 18 px, too small for a finger beside the next chip (WCAG 2.2 SC 2.5.8). Each is now a 24px square with its glyph in the middle, and the chip keeps its height.

- **The browser's own clear button of a search field shows the pointer.** On an [input](https://docs.wirekit.app/components/input) of type `search` without `clearable`, the cross the browser draws is a control, and the pointer now says so over it.

- **The close button of a dismissible [badge](https://docs.wirekit.app/components/badge#trailing-icon--dismissible) is a 24px target.** It was as large as its 12px glyph, half the 24 × 24 px of WCAG 2.5.8, and a row of removable filter chips is where a finger misses it. It now takes the 24px around the glyph and gives them back through its margins, so a badge of every size keeps its height and its width, and the glyph stands where it stood.

- **A [translatable input](https://docs.wirekit.app/components/translatable-input) reads as one field and stands on a field's height.** Its legend was bolder than the labels beside it and 4px above the first field, where a field puts its label 6px above, so the primary language's field stood about 2px higher than an input in the same row. The legend is now drawn as a field's label, at a label's distance, and a message about the whole value stands under the fields, as under any field. [`field.set`](https://docs.wirekit.app/components/field) takes the same as `as-field`, for any set that stands for one field.

- **A [translatable input](https://docs.wirekit.app/components/translatable-input) without `locales` has a field to type in.** An empty list of languages, the default, drew the label and no field, so the form sent nothing for the value and nothing said why. Without a language the input edits the value in the application's language, as one ordinary field, and a list whose every code is refused is reported.

- **A translatable input with a single language is an ordinary field.** It drew a group with the language's code in a box before the field, a lone "DE" in every form of a shop with one language. With one language in `locales` it now draws its field as an input or a textarea does, with the label in sight and the same binding, messages and help, and shows the codes from the second language on.

- **A key listener and the attributes of a text field reach every field of a translatable input, and Enter on a chip only opens the chip's language.** `x-on:keydown.enter` and the other key listeners of the page landed on the component's root, where they also heard Enter on a chip and ran the field's action, and `autocomplete="off"` or `maxlength` did nothing there. A `form` that joins the field to a form elsewhere on the page stayed there too, so that form received none of the languages. They are now handed to each language's field, as an input takes them; a listener on the window or the document stays on the component and runs once.

- **A translatable input marks an unsaved language at its code, and takes a sentence for one language.** Inside `x-wk-unsaved`, a language's field took the unsaved line, but its label is visually hidden, so the words beside a label had no place. The code, which stands where the label would, now takes a dot in the unsaved color, and the field's description names the words. `hints` gives one language a sentence of its own under its field, `:hints="['en' => 'Translated by machine']"`, and the field is described by it.

- **The counts of a [pagination](https://docs.wirekit.app/components/pagination) summary are grouped the locale's way**, "of 10.514 results" in German rather than "of 10514".

- **A link to an element inside a closed [collapsible card](https://docs.wirekit.app/components/card#opening-it-from-elsewhere) brings the element into view once the card stands open.** It scrolled on the next tick, while the part that folds was still sliding open and the page around it as short as with the card closed, so an element far down a long card stayed out of view.

- **A click on the chevron of an open [collapsible card](https://docs.wirekit.app/components/card#a-card-that-folds) closes it.** The turned arrow was painted above the head's click area and took the click itself, so only the space beside and below it closed the card. A collapsible card that holds nothing but a footer draws one line under its head instead of two, and inside `data-wk-touch` the button in its head is 44px tall, as the triggers of accordions and collapsibles are.

- **On a phone, [checkboxes](https://docs.wirekit.app/components/checkbox) and [radios](https://docs.wirekit.app/components/radio) stand as far apart as on a desk.** Since v2.66.0 their label grew to 44px under the coarse pointer of a touch screen, so the options of a [field set](https://docs.wirekit.app/components/field), the legend above them and a checkbox between a sentence and a button stood visibly further apart on a phone than under a mouse. The label keeps its height now and answers a finger over an area above and below its text that moves nothing: at least 24px tall, and between two options of a field set reaching halfway to the next one, so a tap between them lands on the nearer one. Inside `data-wk-touch` the label is a 44px row, as before.

- **The box of a [checkbox](https://docs.wirekit.app/components/checkbox) and the circle of a [radio](https://docs.wirekit.app/components/radio) stand on the middle of the first line of their label, at every size.** Both were aligned to the top of the label, so a small box stood above the middle of its text, and a [swatch](https://docs.wirekit.app/components/swatch) and a name in the slot stood below the box. A label that wraps keeps its first line beside the box. A small checkbox or radio is now as tall as its line, 2px lower than before; the medium and large sizes keep their height.

- **The [theme controller](https://docs.wirekit.app/components/theme-controller) with `variant="select"` draws the chevron of the [select](https://docs.wirekit.app/components/select).** Its arrow was the browser's, and a browser places that by its own rule: close to the box's edge in Chrome whatever the padding says, and a different glyph in each engine. The box now draws the select component's chevron, centered and as far from the edge as on every other select, and keeps the value clear of it.

- **An empty `error` on a [form field](https://docs.wirekit.app/components/field#error-state) reads the `$errors` bag as if no `error` were given.** With an entry in the bag, a field given `error=""` was marked invalid and showed no message, and its description pointed at an error paragraph that never rendered. It now shows the bag's message with the invalid state, or neither.

- **A [form field](https://docs.wirekit.app/components/field#error-state) bound with `wire:model` and no `name` shows its validation error.** Every field read the `$errors` bag under its `name` alone, so after a failed `$this->validate()` a field bound only with `wire:model` showed no message and no invalid state. Livewire files the message under the bound property, and a field without a `name` now reads it there: `wire:model="form.email"` under `form.email`, with any modifier. A `name` still wins, and a checkbox bound to the key of its `field.set` leaves the message to the group.

- **A [field](https://docs.wirekit.app/components/field#error-state) around a form control that shows the same error no longer repeats it.** With `name` on both, the shape of the field page's own examples, a failed validation rendered the message under the control and again under the field, and both paragraphs carried the same id. The field now leaves its message out when the control inside already shows it, so the message appears once, attached to the control, and the field's hint gives way to it as it does to the field's own message. Around markup of the application's own, or a control that shows no message, the field shows it as before.

- **The hint of a [field](https://docs.wirekit.app/components/field#basic-usage) describes the form control inside it.** The field rendered its hint below the control, and nothing pointed `aria-describedby` at it, so a screen reader never read it with the control. With a hint on the control as well, both paragraphs carried the same id. Every form control in a field now links the field's hint after its own description. While the field has an error, the error takes the hint's place and no hint is linked. When the control's own hint carries `{name}-hint` already, the field's takes `{name}-field-hint`, and a field without a `name` names its hint after the control. Markup of the application's own still references `{name}-hint` by hand.

- **The label of a [field](https://docs.wirekit.app/components/field#accessibility) names every form control inside it.** A [segmented control](https://docs.wirekit.app/components/segmented-control) or a [swatch group](https://docs.wirekit.app/components/swatch-group) in a field had no accessible name at all, and an interactive [rating](https://docs.wirekit.app/components/rating) or a [one-time code](https://docs.wirekit.app/components/otp-input) kept the name it gives itself, "Rating" or "One-time code": the label pointed at nothing, or at a hidden input. They now take the field's label as they take a label of their own. The groups are named by it, and the label of a one-time code points at its first box. With two fields of the same name on a page, the label of the second field named the control of the first for a number input, a password input, a phone, a time picker, a one-time code and a rating. Each label now names its own control.

- **A closed [accordion](https://docs.wirekit.app/components/accordion#accessibility) item is no landmark.** A closed item the browser's find in page can open kept `role="region"` and the name of its trigger. Its panel keeps its box while closed, so axe counted it in Chromium among the page's landmarks: a region with nothing to read, and the twin of any other region of the same name, which axe reports as `landmark-unique`. The panel now takes the role and its name when it opens and gives both up when it closes, through a Livewire update as well. The answers of a [FAQ](https://docs.wirekit.app/components/faq) follow, since they are accordion items.

- **A required [one-time code](https://docs.wirekit.app/components/otp-input), [range slider](https://docs.wirekit.app/components/range-slider) or [tags input](https://docs.wirekit.app/components/tags-input) says so where the reader lands.** Each wrote `aria-required` on the group around its parts, where ARIA does not allow it and axe reports a critical `aria-allowed-attr`, and the elements that take the focus did not say it at all. The attribute now sits on every box of the code, on both thumbs of the range and on the input a tag is typed into.

- **The `required` of a [field](https://docs.wirekit.app/components/field#required-fields) reaches the form control inside it.** The field marks its label with an asterisk that is hidden from assistive technology, and with `required` on the field alone no control said the field was required, so a screen reader never announced it. The field page's own example had that shape. A form control in a required field now carries `aria-required="true"`. It never takes the native attribute from the field, so the browser checks an empty field only when the control is given `required` itself, as before.

- **The `help` of a [field](https://docs.wirekit.app/components/field#props) describes the form control inside it, as a control's own help does.** The field showed its help in a tooltip beside the label, and its hidden copy, which a screen reader reads as the control's description, was only offered under `{name}-help`. A form control in a field with a label now links it after the field's hint. Beside a help of the control's own that carries the same id, the field's takes `{name}-field-help`, and a field without a `name` names it after the control.

- **`readonly` makes a [one-time code](https://docs.wirekit.app/components/otp-input), a [tags input](https://docs.wirekit.app/components/tags-input), a [multi-select](https://docs.wirekit.app/components/multi-select) and an [inline edit](https://docs.wirekit.app/components/inline-edit) read-only.** The attribute landed on a wrapper element, where it is no valid attribute and stopped nothing, so each of them stayed editable. A read-only code keeps every box in the tab order and refuses keys and pastes. A read-only tags input or multi-select keeps its values on the page and in the form, shows no remove buttons, and adds or removes nothing; the multi-select's list still opens to show the options. A read-only inline edit shows its value without a pencil and opens no editor. An `autocomplete` written on an inline edit now reaches its field as well.

- **A [disabled group](https://docs.wirekit.app/components/field#a-disabled-group) locks a [combobox](https://docs.wirekit.app/components/combobox) and an open [color picker](https://docs.wirekit.app/components/color-picker) panel.** Both draw their list or panel at the end of the document, outside the fieldset, so a fieldset disabled while one was open left it working: a click on an option of the open list still chose it, and the plane, sliders and swatches of the open panel still changed the color. A combobox without search, whose field is no native control, also stayed in the tab order and opened on a click or a key. While the fieldset is disabled, an option of an open list now picks nothing, a combobox without search leaves the tab order and says it is disabled, and an open color picker panel closes.

- **The required star of a [translatable input](https://docs.wirekit.app/components/translatable-input) stands where a field's label draws it.** Its legend held the star in the row after its text, half a gap further from the words than the star of a field beside it. It now stands right after the text, and the legend says "(required)" to a screen reader, through the new `required` of the field set.

- **A [keyboard shortcut](https://docs.wirekit.app/components/shortcuts#pitfalls) on a button inside a disabled fieldset leaves the key alone.** The shortcut registry read the button's own `disabled`, which stays false inside a disabled fieldset, so ⌘↵ in a dialog whose form a request had locked took the key and pressed a button that could not act, and the overview on `?` listed the shortcut. Such a button now counts as disabled, as the browser counts it: its shortcut neither fires nor is listed until the fieldset is enabled again.

- **A click on a [disabled option](https://docs.wirekit.app/components/combobox#disabled-options) of an optimistic combobox chooses nothing.** With `optimistic`, a click on an option went straight to the optimistic layer, so a disabled option was chosen and its value sent to the server, while the arrow keys and Enter passed it by. A click now chooses what Enter would: nothing on a disabled option, and the option's value otherwise, a falsy one included.

- **An [optimistic](https://docs.wirekit.app/extending/optimistic-ui) checkbox or switch that cannot reach its Livewire component shows the value it holds.** Outside a Livewire component, or with a `bind` that names no property, the layer refuses the press and warns in debug that the control will not change, but the box stayed as the browser had flipped it. It goes back to its value now. A text field keeps what was typed into it.

- **The reference of every component with `optimistic` explains the prop and names the file it needs.** In every component that takes [`optimistic`](https://docs.wirekit.app/extending/optimistic-ui), the comment that explains it stood above `optimisticArgs`, so the reference the MCP server answers `get_component` with gave its text to `optimisticArgs` and none to `optimistic`. Each prop carries its own text now, and the one of `optimistic` says that the page loads `wirekit-optimistic.js` beside its bundle, without which no control calls its method.

- **Names and labels built from a slot or a markup label read as written, `Tom's & Jerry` included.** A [tooltip](https://docs.wirekit.app/components/tooltip) with a `content` slot named its trigger, a [table](https://docs.wirekit.app/components/table) that stacks its rows named its columns, a [command palette](https://docs.wirekit.app/components/command-palette) item titled its line and an [app rail](https://docs.wirekit.app/components/app-rail) module with a counter wrote its tooltip with Blade's escaping still in the text, so a screen reader, or the reader of a stacked table on a phone, met `Tom&#039;s &amp; Jerry`. The same reached the buttons that an [input](https://docs.wirekit.app/components/input), a [combobox](https://docs.wirekit.app/components/combobox), a [password input](https://docs.wirekit.app/components/password-input) and a [kanban](https://docs.wirekit.app/components/kanban) column name after a label given as an `HtmlString`, and the parts a [field](https://docs.wirekit.app/components/field) with such a label names. The first count of a [textarea](https://docs.wirekit.app/components/textarea) counter counted the references, 28 for 16 characters, until the page's scripts started, and a [floating action button](https://docs.wirekit.app/components/fab) whose label holds its words lost that label as its name when the words held an apostrophe or an ampersand.

- **A form control given a list where it takes one value renders without it.** `old('email')` returns a list when a request sent `email[]`, and a rule such as `string` sends the reader back to the form with it. An [input](https://docs.wirekit.app/components/input), a [password input](https://docs.wirekit.app/components/password-input), a [number input](https://docs.wirekit.app/components/number-input), a [one-time code input](https://docs.wirekit.app/components/otp-input), a [phone field](https://docs.wirekit.app/components/phone), a [combobox](https://docs.wirekit.app/components/combobox), a [segmented control](https://docs.wirekit.app/components/segmented-control), a [date picker](https://docs.wirekit.app/components/date-picker), a [time picker](https://docs.wirekit.app/components/time-picker), a [color picker](https://docs.wirekit.app/components/color-picker), an [inline edit](https://docs.wirekit.app/components/inline-edit), a [radio](https://docs.wirekit.app/components/radio), a [checkbox](https://docs.wirekit.app/components/checkbox) and a [toggle](https://docs.wirekit.app/components/toggle) threw a PHP error on it, and so did a [multi-select](https://docs.wirekit.app/components/multi-select), a [tags input](https://docs.wirekit.app/components/tags-input) and a [calendar](https://docs.wirekit.app/components/calendar) given a list inside their list, so the page that should show the validation error answered with a server error. Each now reports the list through [strict validation](https://docs.wirekit.app/strict-validation) and, where strict validation only logs, renders without it.

- **The numbers a slider, a range slider, a progress bar, a character counter and a badge write read in the page's language.** A German page read "Bereich: 0.2 bis 0.7" under a [range slider](https://docs.wirekit.app/components/range-slider), "0.3" in a [slider](https://docs.wirekit.app/components/slider)'s bubble and "0.5" under its mark, "12.5 / 100" beside a [progress](https://docs.wirekit.app/components/progress) bar and "3 / 12500" under a [textarea](https://docs.wirekit.app/components/textarea) with a counter, beside figures the same page wrote as "12.500". A slider's values and marks now take the page's decimal mark, `0,3`, and are never grouped, so a scale of years still reads `2026`. A count is grouped as the [pagination](https://docs.wirekit.app/components/pagination) groups one, `12.500` in German and `12,500` in English: the readout of a progress bar, the character counter, and the badge of a [sidebar](https://docs.wirekit.app/components/sidebar) item, an [app rail](https://docs.wirekit.app/components/app-rail) module, a [dropdown](https://docs.wirekit.app/components/dropdown) item, a [tab](https://docs.wirekit.app/components/tabs), a [bottom navigation](https://docs.wirekit.app/components/bottom-nav) item, an [indicator](https://docs.wirekit.app/components/indicator), an [activity row](https://docs.wirekit.app/components/activity-row) and a [product card](https://docs.wirekit.app/components/product-card), the counts of a [kanban](https://docs.wirekit.app/components/kanban) column, a [stage card](https://docs.wirekit.app/components/stage-card) and a [reaction](https://docs.wirekit.app/components/reaction), an optimistic one included, and the count of new messages on the jump-to-latest button of a [conversation](https://docs.wirekit.app/components/conversation). A badge that is no plain whole number, such as `99+`, `New` or `007`, stays as written, and an application that writes its numbers its own way gets its own marks in all of them.

- **A form with a [phone](https://docs.wirekit.app/components/phone) field sends the number a reader typed when the page runs no script.** Without JavaScript the form sent the number the page was loaded with, so a new or edited number never arrived, and nothing reported it. Until its script starts, the field now sends the number as typed and the country it stands on under its name, as `name[number]` and `name[country]`; with the script it sends E.164 alone, as before, and a `wire:model` still binds that value only. `DialingCodes::fromField()` reads either shape and returns E.164, so one line in front of the validation covers both, see [Without JavaScript](https://docs.wirekit.app/components/phone#without-javascript).

- **A form sent from a page that runs no script keeps the selection of a [multi-select](https://docs.wirekit.app/components/multi-select) and the tags of a [tags input](https://docs.wirekit.app/components/tags-input).** Their fields were written by the script, so such a form carried neither, and a server saving it stored both empty. The values the page was loaded with are now sent as well when no script runs; with one, the fields are the same as before.

- **A one-time code typed into an [OTP input](https://docs.wirekit.app/components/otp-input) arrives when the page runs no script.** Only the script joins the boxes into the code, so such a form sent an empty field and a verification step without JavaScript could never pass. Until the script starts, the boxes are now sent as `name[]`, one entry per box, and `implode('', (array) $request->input('code'))` reads the code from either shape; with the script the form sends the code alone, as before, see [Form Submission](https://docs.wirekit.app/components/otp-input#form-submission).

- **A form with a required [combobox](https://docs.wirekit.app/components/combobox), [multi-select](https://docs.wirekit.app/components/multi-select), [tags input](https://docs.wirekit.app/components/tags-input), [OTP input](https://docs.wirekit.app/components/otp-input), [rating](https://docs.wirekit.app/components/rating), [calendar](https://docs.wirekit.app/components/calendar) or [editor](https://docs.wirekit.app/components/editor) can be sent from a page that runs no script.** These controls check `required` through a hidden stand-in that only the script fills, so without one the browser stopped every submit of the form, even when the field had a value, at a field nobody can see. The stand-in now takes part in the check only once the script runs; the server checks `required` either way, and with the script an empty field stops the submit as before.

- **A [combobox](https://docs.wirekit.app/components/combobox#with-preselected-value) with search shows its choice before its script starts.** Its search field stayed empty until the script ran, so a page loaded on a choice showed the placeholder over it: a filter opened from a link read "All people" above a table filtered to one person. With [`free-input`](https://docs.wirekit.app/components/combobox#free-input) the field carries the name, so a form sent before the start, or from a page that runs no script, sent nothing for it. The field holds the chosen option's text, or with `free-input` the value, from the first render.

- **A label of a [bottom nav](https://docs.wirekit.app/components/bottom-nav#items) and the name of a [message](https://docs.wirekit.app/components/message#author-role-badge)'s author show whole when they are cut.** A long word in a tab of a phone's bar, or a long name beside the author's role and the time, ended in an ellipsis with nothing to read it whole by. The tab's label shows whole in a tooltip while it is cut, on hover, on the link's keyboard focus and on a long press, and the author's name takes a `title`, as the head of a message group does.

- **A [slider](https://docs.wirekit.app/components/slider), a [password input](https://docs.wirekit.app/components/password-input) and a [filter builder](https://docs.wirekit.app/components/filter-builder) follow a form reset.** The browser resets a native field without telling the script, so a slider's bubble and its announced value kept the value the reader had left, and a password input's strength meter kept rating the password that was gone. A filter builder kept the filters the reader had set while the rest of the form went back. All three now return to what they started with, as the other form components already did.

- **The groups of a [combobox](https://docs.wirekit.app/components/combobox) list stand on an element that may carry them.** Each group took the `group` role on a list item, which ARIA in HTML does not allow, so an accessibility check reported `aria-allowed-role` for every combobox with grouped options and for every combobox with `server`, whose list is grouped too. The role and the group's name now sit on the list inside the item, and the options still belong to their group.

- **A person drawn without a picture gets the same initials in every component.** The attendees of an [event calendar](https://docs.wirekit.app/components/event-calendar) took the first character of the first two words, so "Ada Byron Lovelace" read "AB" there and "AL" in a [message](https://docs.wirekit.app/components/message), and a name with an emoji or a character such as 𠮷 showed half of that character, drawn as a replacement character. A message, a [team member](https://docs.wirekit.app/components/team-section) and a [testimonial](https://docs.wirekit.app/components/testimonial) took a word's first character as well, so "(Ada) Lovelace" read "(L". Every component now takes the first letter or digit of the first and the last word, as the options of a [combobox](https://docs.wirekit.app/components/combobox) already did, and the calendar reads the same rule in the browser. For those names the [color an avatar derives from the initials](https://docs.wirekit.app/components/avatar#deterministic-color-from-initials) changes with them.

- **An [avatar](https://docs.wirekit.app/components/avatar)'s initials keep the accent of a name written decomposed.** A name whose accent is a mark of its own after the letter, as a file name from macOS writes it, lost the mark: "Émile Zola" showed "EZ". The marks that combine with a letter stay with it, on the server and in the browser alike, and a vowel sign stays with the consonant it belongs to.

- **A caller's `x-on:click` on a component that listens to clicks itself runs beside the component's own.** On a [context menu](https://docs.wirekit.app/components/context-menu) item, a [menubar](https://docs.wirekit.app/components/menubar) item, a [dropdown](https://docs.wirekit.app/components/dropdown) trigger, the close control of a [modal](https://docs.wirekit.app/components/modal), the trigger and the close control of a [drawer](https://docs.wirekit.app/components/drawer), the confirm and cancel controls of an [alert dialog](https://docs.wirekit.app/components/alert-dialog), the trigger of a [command palette](https://docs.wirekit.app/components/command-palette) or of the [keyboard shortcuts](https://docs.wirekit.app/components/shortcuts) overview and the toggle of a [sidebar](https://docs.wirekit.app/components/sidebar), a listener written with `x-on:click` stood beside the component's own of the same name, and the browser kept only one of them: a menu item written that way did nothing, or the menu stayed open. The same held for `x-on:keydown` on a dropdown panel, `x-on:mouseenter` and `x-on:mouseleave` on a [navigation menu](https://docs.wirekit.app/components/navigation-menu) item, the pointer, key and focus listeners of a [resizable](https://docs.wirekit.app/components/resizable) handle, and `x-on:click.prevent` on an item of an interactive [bottom navigation](https://docs.wirekit.app/components/bottom-nav). Both run now, the component's first.

- **A [usage meter](https://docs.wirekit.app/components/usage-meter) and a [radial progress](https://docs.wirekit.app/components/radial-progress) write a percentage as the page's language does.** A German page read `(13%)` beside a usage meter's figures and heard `13%` from a radial progress, where WireKit writes `13 %` elsewhere, as for the change of a price. The deprecated circular [progress](https://docs.wirekit.app/components/progress#radial-circular-progress) writes the value in its middle the same way.

- **A count WireKit writes takes its plural form under a regional locale spelled with a hyphen.** Under `de-AT`, `pt-BR`, `fr-CA` or `en-GB` every count read in its first form, "3 Stern" for a [rating](https://docs.wirekit.app/components/rating)'s third star or "von 57 Treffer" in a [pagination](https://docs.wirekit.app/components/pagination) summary, and a count that changes in the browser kept that one form for every number. The form follows the locale's language now, as it did under `de_AT`. [Localization](https://docs.wirekit.app/localization) says what the hyphen means for an application's own plural sentences.

- **A page in a language WireKit ships no catalog for writes its English counts in their English form.** Under Polish, Russian, Czech or Arabic the English sentences WireKit falls back to read "5 item" or "1 items", and a count that changes in the browser read "21 item" under Russian. An English sentence takes its form by English now, and a sentence an application translates keeps its own language's rule. [Localization](https://docs.wirekit.app/localization) describes the fallback.

- **A Portuguese count that reaches zero in the browser reads as the server writes it.** A [countdown](https://docs.wirekit.app/components/countdown), a [scope switcher](https://docs.wirekit.app/components/scope-switcher)'s result count or a [textarea](https://docs.wirekit.app/components/textarea)'s character counter read "0 segundo" or "0 resultado" once the number changed in the browser, where the page itself wrote the plural.

- **A [reading minimap](https://docs.wirekit.app/components/reading#reading-minimap)'s labels keep an emoji or a flag whole.** A heading cut to fit its marker or its tooltip could end in half a flag, drawn as a replacement sign, or in the first part of a joined emoji, which showed another emoji. The cut falls between characters as a reader sees them now, and the same holds for a [command palette](https://docs.wirekit.app/components/command-palette)'s Backspace in the moment before its field has the focus.

- **A number the browser writes into a sentence follows the page's language.** A [number input](https://docs.wirekit.app/components/number-input) that corrected a value on leaving the field said "Auf 2.5 gesetzt" on a German page, and the selection of a [data table](https://docs.wirekit.app/components/data-table) read "12500 Zeilen ausgewählt" beside a pagination that wrote "10.514". The value takes the page's decimal mark, ungrouped as the field shows it, and a count on the page is grouped as WireKit groups one elsewhere, as is the count of changes of a [status matrix](https://docs.wirekit.app/components/status-matrix). A sentence only a screen reader hears keeps its digits, which every voice reads alike.

- **A search keeps a mark that makes another letter.** The search of a [combobox](https://docs.wirekit.app/components/combobox), a [multi-select](https://docs.wirekit.app/components/multi-select), a [data table](https://docs.wirekit.app/components/data-table) and a [scope switcher](https://docs.wirekit.app/components/scope-switcher) folds accents away so `munchen` finds `München`, and it folded a Japanese voicing mark or a Devanagari vowel sign away the same way, so a search for a word found another one. In those scripts the mark stays now; Latin, Greek, Cyrillic, Arabic and Hebrew accents fold as before.

- **A [review](https://docs.wirekit.app/components/review) renders a date that names its offset.** An ISO 8601 date with an offset or with `Z`, the form `toISOString()` and most APIs write, a date object with an offset and a Unix timestamp stopped the page with an exception, because the date was formatted in a zone PHP names by its offset. Such a date is written on the day of its own zone now.

- **A [message](https://docs.wirekit.app/components/message) renders a `timestamp` that is a plain PHP date.** A `DateTime` or a `DateTimeImmutable` stopped the page with an error, where a Carbon date rendered. A date object of any class renders now, and a Carbon date keeps the element ids it had.

- **A Unix timestamp is written in the application's time zone.** Handed to a [message](https://docs.wirekit.app/components/message), a [countdown](https://docs.wirekit.app/components/countdown), a [review](https://docs.wirekit.app/components/review) or an [event calendar](https://docs.wirekit.app/components/event-calendar) without a `timezone`, a timestamp was written in UTC, while the same instant as a string or from a model was written in the application's zone: in Berlin a message read two hours early, and after midnight a calendar opened on the previous day. A timestamp takes the zone a string without one is read in now. An application in UTC sees no change.

- **A number that rounds to zero is written without a minus.** The zero line of a [chart](https://docs.wirekit.app/components/chart) axis that steps in tenths or fifths read `-0`, or `-0,0` in the decimals of its series, and a figure written on the server that rounds to zero from below read `-0`, `-0 %` or `-0,00 €`, as the change of a [price](https://docs.wirekit.app/components/price) just below zero did, colored as a price drop. Such a value reads `0` now, and one that rounds away from zero keeps its minus.

- **A [color picker](https://docs.wirekit.app/components/color-picker)'s panel stays open while an input method's conversion is abandoned in its value field.** Writing Japanese, Chinese or Korean, a reader abandons a conversion with Escape, and the panel heard that Escape as its own and closed. The value field, the search of a [filter builder](https://docs.wirekit.app/components/filter-builder) and the value fields of its popover keep such a key to the input method now, as WireKit's other text fields do.

- **An id above `Number.MAX_SAFE_INTEGER` comes back from the browser exactly.** The selection of a [data table](https://docs.wirekit.app/components/data-table), a click on an [event calendar](https://docs.wirekit.app/components/event-calendar)'s event or a [map](https://docs.wirekit.app/components/map)'s marker and the events of a [notification center](https://docs.wirekit.app/components/notification-center) handed a 64-bit id, such as a snowflake id, back as another number, because a script reads a number in JSON as a double. Such an id travels as its digits now, and every smaller id stays a number.

- **A backed enum is a value, as a model attribute cast to one hands it over.** A [select](https://docs.wirekit.app/components/select), a [radio](https://docs.wirekit.app/components/radio), a [checkbox](https://docs.wirekit.app/components/checkbox), an [input](https://docs.wirekit.app/components/input), an [inline edit](https://docs.wirekit.app/components/inline-edit), a [multi-select](https://docs.wirekit.app/components/multi-select) and the `default` of [tabs](https://docs.wirekit.app/components/tabs) stopped the page with an error when an enum such as `$post->status` was the value. Each reads a backed enum as its value now, the way Blade writes one, and a pure enum as its name, and writes exactly what it writes for the same value as text.

- **A date or time field shows the date a model hands over.** An [input](https://docs.wirekit.app/components/input) with `type="date"` or `type="time"` wrote a date object, such as an attribute with a `date` cast or `old('due', $task->due_on)`, as `2026-03-15 00:00:00`, which the browser's field drops: the field stood empty, and a form saved without touching it sent no date. A date and time written as text, such as `2026-03-15 14:30:00` from a column without a cast or the ISO 8601 that Laravel writes into JSON, emptied every date and time field the same way and left a [calendar](https://docs.wirekit.app/components/calendar) without a single day. Each field now receives such a value in its own form, with text read in the application's time zone, and a calendar that cannot read its start value opens on the current month. A [time picker](https://docs.wirekit.app/components/time-picker) wrote the seconds of a date object, `09:30:45`, which a field that counts minutes refuses to send; a time keeps its seconds only where `step` counts them now.

- **An [event calendar](https://docs.wirekit.app/components/event-calendar) puts a day from a model on that day.** A day marker whose `date` came from a `date` cast stood on the day before in every time zone east of UTC, so a `blocked` holiday blocked the wrong day, and an all-day event from one stood on the day before for a reader west of the application. A plain PHP `DateTime` marker or event stood on no day at all. A marker's date and the ends of an all-day event are written as the day they name now, and the ends of a timed event as the instant they hold.

- **A [chart](https://docs.wirekit.app/components/chart) labels a date on its date axis as the time it names.** A day from a `date` cast stood on the day before on ApexCharts' axis, which is labeled in UTC, in every application east of UTC, and a plain PHP `DateTime` was no date at all. A date and time written without a time zone showed each reader another hour on that axis, and a date alone stood on the day before for readers west of UTC on an axis labeled in their own zone. The chart now writes each in the form the axis reads as the time it names, and the links of its points name the same day.

- **A date in a row of a [data table](https://docs.wirekit.app/components/data-table) shows as the date it is.** A date object in a row reached the table's cells as `1990-12-24T23:00:00.000000Z`, the day before for a date of an application east of UTC, and a plain PHP `DateTime` as `[object Object]`. It shows as PHP prints it now, in its own time zone, and sorts as the dates do.

- **A saved [filter](https://docs.wirekit.app/components/filter-builder) on a date field shows its day.** A rule whose value was a date object read `Created after 2026-12-24T23:00:00.000000Z` on its chip, the day before for a date of an application east of UTC, or `[object Object]` for a plain PHP `DateTime`, and the date field stayed empty when the rule was edited. The value of a rule on a `date` field is written as the day it names now.

- **A number that is not finite no longer ends the page.** A [chart](https://docs.wirekit.app/components/chart), a [sparkline](https://docs.wirekit.app/components/sparkline) or a [data table](https://docs.wirekit.app/components/data-table) whose data held `INF` or `NAN`, as a rate divided with `fdiv()` by a base of zero gives, stopped the page with `Inf and NaN cannot be JSON encoded`. Such a number is written as `null` now, as JavaScript's own `JSON.stringify()` writes it: a chart draws a gap, a cell shows nothing. An [editor](https://docs.wirekit.app/components/editor) given its document as an array writes one as `null` as well, as the browser writes it when the document is saved, where the render failed before.

- **A [tool call](https://docs.wirekit.app/components/tool-call) shows its arguments when one of them holds a byte that is not UTF-8 or a number that is not finite.** Arguments given as an array with a value from a Latin-1 source, `INF` or `NAN` showed no arguments block at all, without a word. The byte shows as U+FFFD now and the number as `null`, beside the other arguments, and arguments JSON cannot hold at all are named in the log in debug mode.

- **A numeric prop that holds `NAN` or `INF` no longer ends the page under PHP 8.5.** PHP 8.5 warns when such a number is cast to an integer or written as text, and Laravel turns the warning into an exception. Heading levels, counts, sizes, delays and the other numeric props of the components read their value as a number first now, so `NAN` and `INF` take the default a text takes. That holds for the numeric props that default to nothing as well, such as the `seconds` of a [tool call](https://docs.wirekit.app/components/tool-call), the `index` of a [wizard](https://docs.wirekit.app/components/wizard) step or a `date` given as a timestamp, and for the `offset` of a [popover](https://docs.wirekit.app/components/popover). A [stat](https://docs.wirekit.app/components/stat) and the count in a badge show such a value as PHP has always written it.

- **A prop given a fluent string from `str()` shows the text it holds.** `:label="str($field)->headline()"` is an ordinary way to write a prop, and Blade's `{{ }}` writes such a value as its text, but an [input](https://docs.wirekit.app/components/input)'s `success`, a [tool call](https://docs.wirekit.app/components/tool-call)'s `name`, a [kbd](https://docs.wirekit.app/components/kbd)'s `shortcut` and other text props left it out, an [editor](https://docs.wirekit.app/components/editor) wrote such a document into its field as a JSON string, which the next save kept, and an [activity row](https://docs.wirekit.app/components/activity-row)'s `kind` ended the page. Every component reads a fluent string as its text now. An `HtmlString` stays markup: a `success` message given as one is written as markup, as `hint` is, a [map](https://docs.wirekit.app/components/map)'s `attribution` reaches Leaflet as the HTML it holds, and where a prop is text for a script or for a name, such as a [countdown](https://docs.wirekit.app/components/countdown)'s `expired-text`, it is read as its text rather than written as `[object Object]`.

- **A [grid](https://docs.wirekit.app/components/grid) or a [feature grid](https://docs.wirekit.app/components/feature-grid) with a `cols` value it does not know falls back to one column in production.** Outside debug mode a value such as `13` or a typo ended the page with a `TypeError`, where an unknown value is meant to be logged and replaced by the fallback, and the fallback then came out as a bare class `1` rather than `grid-cols-1`.

- **A Collection handed to a control that holds one value is reported, as an array is.** A [combobox](https://docs.wirekit.app/components/combobox), a [select](https://docs.wirekit.app/components/select) or a [segmented control](https://docs.wirekit.app/components/segmented-control) given `$post->tags->pluck('id')` wrote its JSON text, `[5,8]`, as the value without a word, where an array was reported while developing and left out. Both arrive the same way now; a [multi-select](https://docs.wirekit.app/components/multi-select) still reads a Collection as its list.

- **A display in a component's `class` takes the place of the component's own.** `class="hidden md:inline-flex"` left a [button](https://docs.wirekit.app/components/button) on a phone's screen, `class="hidden"` left a [badge](https://docs.wirekit.app/components/badge) there, and `class="block"` kept a [stack](https://docs.wirekit.app/components/stack) a flex column: Tailwind writes the display utilities in the order of their names, so a component's own `inline-flex` came after `hidden` and won, as its own `flex` did after `block`. A display written without a breakpoint in front now replaces the component's own, so the element hides and comes back at the breakpoint the class names. A display under a breakpoint alone, as in `class="md:hidden"`, leaves the component's own in place. See [Customization](https://docs.wirekit.app/customization#hiding-or-placing-a-component-with-your-own-classes).

- **A position in a component's `class` takes the place of the component's own.** `class="absolute top-2 right-2"` left a [tooltip](https://docs.wirekit.app/components/tooltip) around a copy button in the flow, and a [dropdown](https://docs.wirekit.app/components/dropdown) or an [avatar](https://docs.wirekit.app/components/avatar) placed that way stayed where it stood, while `absolute` left a [button back to the top](https://docs.wirekit.app/components/scroll-to-top) fixed to the window: Tailwind writes the position utilities in the order of their names, so `absolute` and `fixed` came before a component's own `relative` and lost, and `absolute` before its own `fixed`. A position written without a breakpoint in front now replaces the component's own. See [Customization](https://docs.wirekit.app/customization#hiding-or-placing-a-component-with-your-own-classes).

- **A display or a position in a component's `class` reaches a component that writes its layout inline.** A [header](https://docs.wirekit.app/components/header), a [data list](https://docs.wirekit.app/components/data-list) and its items, a [mixed chart](https://docs.wirekit.app/components/chart-mixed), an inline [sparkline](https://docs.wirekit.app/components/sparkline), a [page progress](https://docs.wirekit.app/components/page-progress) bar and a [reading progress](https://docs.wirekit.app/components/reading#reading-progress) bar write their display or position into `style`, so their layout holds on a page whose stylesheet never scanned them, and a declaration there wins over every class: `class="hidden md:flex"` left a header on a phone, `class="md:hidden"` left a data list on a desktop, and `class="absolute"` left a progress bar fixed to the window. Where the class reaches for the display or the position, with a breakpoint in front or without, the inline declaration now gives way to it. See [Customization](https://docs.wirekit.app/customization#hiding-or-placing-a-component-with-your-own-classes).

- **A [flat card](https://docs.wirekit.app/components/card), a [transparent navbar](https://docs.wirekit.app/components/navbar) and the create action of a [scope switcher](https://docs.wirekit.app/components/scope-switcher) keep their own color over a [personalized block](https://docs.wirekit.app/customization#level-3-deep-personalization) in every spelling Tailwind accepts.** Each takes the competing color out of the block it builds on, because two utilities for one property are decided by their order in the stylesheet. A color with an opacity (`bg-white/80`, `text-black/60`), the custom-property form (`bg-(--brand)`) and an arbitrary text color (`text-[#333]`, `text-[var(--ink)]`) were not recognized and stayed, and `bg-white/80` won over the flat card's own background. A background image, size or position written as an arbitrary value (`bg-[image:…]`, `bg-[length:…]`) was taken out as if it were a color, and stays now. A [table](https://docs.wirekit.app/components/table) header given a font size or weight in `class` recognizes `text-[1.25rem]/7`, `text-[clamp(…)]` and `font-(--weight)` too, and `pbs-*` and `pbe-*` count as padding where a component takes a padding out.

- **A name given to a control reaches the control.** `aria-label` or `aria-labelledby` on the confirm or cancel control of an [alert dialog](https://docs.wirekit.app/components/alert-dialog), a [theme controller](https://docs.wirekit.app/components/theme-controller), the collapse toggle of a [sidebar](https://docs.wirekit.app/components/sidebar), a [menubar](https://docs.wirekit.app/components/menubar) menu, a [navigation menu](https://docs.wirekit.app/components/navigation-menu) item with a flyout or a [command palette](https://docs.wirekit.app/components/command-palette) trigger stood on the element around the control, which has no role and so takes no name: a screen reader read the control's own name, or none. The name goes to the button or the search field now, ahead of the control's own. A control a caller places in the slot of a confirm or cancel control is the caller's to name.

- **A [toast region](https://docs.wirekit.app/components/toast) named with `aria-label` or `aria-labelledby` is a landmark.** The name stood on an element without a role, where it names nothing; it now makes the region the named landmark that `label` makes it.

- **An `aria-labelledby` or `aria-describedby` on a [drawer](https://docs.wirekit.app/components/drawer) or an [alert dialog](https://docs.wirekit.app/components/alert-dialog) names and describes the dialog.** Both took only `aria-label` to the element with the dialog role; a reference or a description written on their tag stayed on the element around it, which has no role, and named and described nothing. They go to the dialog now, a reference ahead of the header or the title, and a description beside the dialog's own in one attribute. A [modal](https://docs.wirekit.app/components/modal#accessible-description) wrote its `describedby` and a description on its tag as two attributes of the same name, of which the browser kept the first; it writes one. The controls that hand a name given on their tag to their button or field, such as the confirm and cancel controls of an alert dialog, a [theme controller](https://docs.wirekit.app/components/theme-controller) and a [command palette](https://docs.wirekit.app/components/command-palette) trigger, do the same with `aria-describedby`.

- **Five tab stops draw the kit's focus ring.** The control a [modal](https://docs.wirekit.app/components/modal) or [drawer](https://docs.wirekit.app/components/drawer) close renders when its slot holds no control of its own, a [replay button](https://docs.wirekit.app/components/replay-button), the create action of a [scope switcher](https://docs.wirekit.app/components/scope-switcher) and the search field of a [command palette](https://docs.wirekit.app/components/command-palette) drew the browser's own ring or none, which follows neither `--ring-wk-width` nor `--color-wk-ring`. They draw the kit's ring now, and a [map](https://docs.wirekit.app/components/map) draws it as an outline inside its frame, where its tiles cannot cover it.

- **What starts hidden stays hidden on the first paint.** A head of a [table](https://docs.wirekit.app/components/table#client-side-sorting-alpine) sorted in the browser showed its arrows up, down and unsorted side by side until the script ran, and for good without it, and a [tree view](https://docs.wirekit.app/components/tree-view) showed the children of a collapsed node until the script folded them and moved the page. Both start hidden now.

- **A `wire:key` given to a submenu, an app rail item, a sidebar row or an action bar stands on the component's outermost element.** Livewire tells the entries of a loop apart by the key on the outermost element of each, which is why [a `wire:key` on a WireKit component](https://docs.wirekit.app/getting-started/integration#a-wirekey-on-a-wirekit-component) keys that element. On a dropdown, menubar or context menu submenu, on an app rail item with a tooltip and on a sidebar row in a sidebar that collapses, the key landed on an element inside it, so Livewire matched those entries by their position, and an entry that left the list or moved could leave its state, such as an open submenu, to the entry that took its place. `x-show` and `wire:show` hid that inner element and left the outer one in the layout, where [an `x-show` or `wire:show` on a WireKit component](https://docs.wirekit.app/getting-started/integration#an-x-show-or-wireshow-on-a-wirekit-component) shows and hides the whole component. All of them go on the outermost element now. An action bar keeps its announcement for screen readers beside the bar, so a key, `x-show` or `wire:show` given to it goes on an element around both.

- **A [modal](https://docs.wirekit.app/components/modal#width--layout) with a long body scrolls the body alone.** A visually hidden text below the body's fold, such as the "Loading" of a [spinner](https://docs.wirekit.app/components/spinner) or the hidden input of a [file upload](https://docs.wirekit.app/components/file-upload), was placed against the panel, because the body had no position of its own: the body neither clipped nor scrolled it, and the panel scrolled by its depth beside the body's own scrollbar. Every region of the kit that scrolls is now the positioned box for what it holds, so the same goes for the body of a [drawer](https://docs.wirekit.app/components/drawer), the list of a [notification center](https://docs.wirekit.app/components/notification-center), a [conversation](https://docs.wirekit.app/components/conversation), a [scroll area](https://docs.wirekit.app/components/scroll-area) and the other scrolling regions, where the hidden text could make the page or a box around them scroll. An absolutely positioned element that a page places inside one of them, with no positioned element around it within the region, is now placed against the region and scrolls with its content; see [Positioned Content](https://docs.wirekit.app/components/scroll-area#positioned-content).

- **An event that names a component by a number reaches it.** A [modal](https://docs.wirekit.app/components/modal), [drawer](https://docs.wirekit.app/components/drawer) or [alert dialog](https://docs.wirekit.app/components/alert-dialog), a collapsible [card](https://docs.wirekit.app/components/card), an [inline edit](https://docs.wirekit.app/components/inline-edit), a [stream](https://docs.wirekit.app/components/stream), a [card stack](https://docs.wirekit.app/components/card-stack), a [lightbox](https://docs.wirekit.app/components/lightbox) and a [command palette](https://docs.wirekit.app/components/command-palette) compared the name or key of an event with the one they held by type as well as value, so `$this->dispatch('wirekit-modal-show', name: $order->id)` sent a number that never met the name `"5"` from the attribute, and nothing opened, folded out or showed. An inline edit holding the number missed a `saved` event that named it as text and kept its saving state. A number and the text of its digits now name the same component in each of them, and the same holds for the id that addresses one [app rail](https://docs.wirekit.app/components/app-rail), one [sidebar](https://docs.wirekit.app/components/sidebar) or one [file upload](https://docs.wirekit.app/components/file-upload) among several.

- **A [tab](https://docs.wirekit.app/components/tabs#contract-named-slots-not-wiremodel) keyed by a number is selected.** The tablist held the open tab as text and compared it with each key as PHP held it, so with keys from `pluck('name', 'id')`, years, or an enum of numbers as `default` or `active`, no tab was selected once the script ran, none was in the tab order and every panel stayed hidden until a click. Keys are compared as text now, and `wirekit:tab-changed` reports the key as text after a click as well.

- **A [segmented control](https://docs.wirekit.app/components/segmented-control) keyed by numbers marks its chosen segment before the script runs.** With keys such as `1`, `7` and `30` and the value written as an attribute, no segment was checked or the group's tab stop until the script ran, and an `autofocus` focused nothing. The markup compares keys and value as text now, as the script does.

- **A tab or a [card stack](https://docs.wirekit.app/components/card-stack) part named with a hyphen shows its slot, and a name never stands in for a prop.** A key such as `api-keys` drew an empty panel or part with either way of writing its slot, and in a card stack a part written as `<x-slot:api-keys>` ignored its place in `order`. A tab keyed like a prop of the tabs or a variable of their own showed that value instead of nothing, `label` the tablist's name, and the key `tab` was an error page. A slot named like a prop took the prop's place: tabs keyed `active` and `archived` selected no tab, a tab keyed `items` left the tablist empty, and a part named `order` dropped the order. Each slot is now found under its own name, either way it is written, and every prop keeps the value written on the tag.

- **A [tooltip](https://docs.wirekit.app/components/tooltip) around a button that a toolbar's arrow keys reach leaves the button as it is.** A control that `tabindex="-1"` leaves out of the tab order was read as a disabled one, so the tooltip wrapped it in a stop of its own: a second tab stop in the toolbar, announced as a button around the button and as unavailable. The tooltip now makes no stop around a control that takes the focus itself, and the control's own focus shows it, as for any other button.

- **A hidden input is never where the focus or a description goes.** A [tooltip](https://docs.wirekit.app/components/tooltip) around a small form, its `@csrf` token in front of the button, gave its description to the token, and the button had none. In a [hover card](https://docs.wirekit.app/components/hover-card) or a [navigation menu](https://docs.wirekit.app/components/navigation-menu) panel that starts with a form, the `Tab` key from the trigger stopped on the token, and `Tab` at either end of the panel left it for an unrelated place. An [app shell](https://docs.wirekit.app/components/app-shell) whose navigation starts with a form opened it with the focus on the token. Each looks past hidden inputs now, and the hover card and the navigation menu also past a control their open panel hides, such as a button shown only under a condition.

- **A read-only [combobox](https://docs.wirekit.app/components/combobox#form-submission) keeps its value.** `readonly` stopped the typing, but the arrow keys, Home, End, Enter, the focus and the chevron still opened the list, a choice from it changed the submitted value, and the clear button emptied it. Nothing opens, chooses or clears a read-only combobox now, as with a read-only native field; it keeps its place in the tab order, and without search the trigger says `aria-readonly="true"`.

- **A [floating action button](https://docs.wirekit.app/components/fab) announces only the popup it opens.** The trigger of a speed dial said `aria-haspopup="true"`, which ARIA reads as a menu, over a group of ordinary links and buttons, so a screen reader announced a menu button and the arrow keys did nothing. It is a disclosure button now, with `aria-expanded` and no `aria-haspopup`. A single `fab.button` with `href` is a link that navigates, and it no longer announces a dialog unless `haspopup` names one; a button without `href` still announces a dialog by default. A `haspopup` outside the popups ARIA names is reported while debugging and announces a dialog.

- **A disclosure, a toggle, a tab or a switch says the state it starts in before the script runs.** The open state of a [collapsible](https://docs.wirekit.app/components/collapsible), a collapsible [card](https://docs.wirekit.app/components/card), an [accordion](https://docs.wirekit.app/components/accordion) item and a folding [sidebar](https://docs.wirekit.app/components/sidebar) section, the selected [tab](https://docs.wirekit.app/components/tabs), the view of an [event calendar](https://docs.wirekit.app/components/event-calendar), the density of a [data table](https://docs.wirekit.app/components/data-table), the switches of a [status matrix](https://docs.wirekit.app/components/status-matrix), the buttons of the [editor](https://docs.wirekit.app/components/editor) toolbar, the [theme controller](https://docs.wirekit.app/components/theme-controller), the menus of a [menubar](https://docs.wirekit.app/components/menubar) and a [navigation menu](https://docs.wirekit.app/components/navigation-menu), the submenus of a [dropdown](https://docs.wirekit.app/components/dropdown) and a [context menu](https://docs.wirekit.app/components/context-menu), and the triggers of a [floating action button](https://docs.wirekit.app/components/fab), a [navbar](https://docs.wirekit.app/components/navbar) menu, a [notification center](https://docs.wirekit.app/components/notification-center), a [filter builder](https://docs.wirekit.app/components/filter-builder) and a [color picker](https://docs.wirekit.app/components/color-picker) were written only by the script, so the markup carried no `aria-expanded`, `aria-pressed`, `aria-checked` or `aria-selected` until it ran, and none where it never did. A [reading](https://docs.wirekit.app/components/reading) progress bar had no `aria-valuenow` either. Each now writes the state it starts in beside the binding: the one the server renders where the server knows it, closed for a menu or a panel that opens later, and zero for the reading progress. A collapsible rendered open paints its panel with the page instead of once the script starts, and a remembered sidebar section says its stored state from the first paint, as its panel already showed it.

- **An `error` given as a list of messages shows its first.** `:error="$errors->get('email')"` on a form control was an error page, where `$errors->first('email')` showed the message. Every form control now reads a list as its first message, and a [segmented control](https://docs.wirekit.app/components/segmented-control) reads the `$errors` bag under its name, or turns its error off with `false`, as the other controls do. See [Error State](https://docs.wirekit.app/components/field#error-state).

- **A week start outside 0 to 6 is read as a day of the week.** A negative `week-starts-on` on a [calendar](https://docs.wirekit.app/components/calendar) answered the page with an error, and a number above six shifted the grid of the calendar and of the [event calendar](https://docs.wirekit.app/components/event-calendar) once the script ran. Any whole number now counts around the week, so `-5` starts on Tuesday and `7` on Sunday.

- **A `placeholder` or a `list` written on an [inline edit](https://docs.wirekit.app/components/inline-edit) reaches the field it opens.** Both stood on the element around the component, so the field opened empty without its hint and offered none of its datalist's suggestions. They now go where `maxlength` and `autocomplete` already went: the placeholder to the text, number or long-text field, the list to the one-line fields.

- **An enum bound to a prop is read as the text it stands for, inside a list as well.** `<x-wirekit::badge :intent="$order->status">` with a status cast to an enum was an error page, and so was an enum in any prop that takes text, `scope` included, on nearly every component. Inside a list it was the same: an option's `value` or a whole list from `Status::cases()` in a [combobox](https://docs.wirekit.app/components/combobox#options-format), a [multi-select](https://docs.wirekit.app/components/multi-select#options-format) or the [quick replies](https://docs.wirekit.app/components/quick-replies), and a tab's `key` in [tabs](https://docs.wirekit.app/components/tabs), ended the page, and a [swatch group](https://docs.wirekit.app/components/swatch-group) left out a swatch whose `value` was one. A backed enum is now read as its value and a pure one as its name, as the value of a form control already was. See [Variants & Intents](https://docs.wirekit.app/variants-and-intents#binding-an-enum).

- **A [tooltip](https://docs.wirekit.app/components/tooltip#switching-a-tooltip-off) that is switched off is quiet for a screen reader as well.** With `disabled` it still described its trigger with its text, and around a disabled control it still made a stop of its own that showed nothing. It now does neither, unless `focusable-trigger` asks for the stop, and a switch bound to `data-wk-tooltip-disabled` takes the description away and gives it back as it flips.

- **A [tooltip](https://docs.wirekit.app/components/tooltip) no longer describes a control with the control's own name.** Every button of the [editor](https://docs.wirekit.app/components/editor)'s toolbar, the links and the collapse control of a collapsible [sidebar](https://docs.wirekit.app/components/sidebar), the toggle of an expandable [app rail](https://docs.wirekit.app/components/app-rail) and the status time of a [message](https://docs.wirekit.app/components/message) carried a tooltip whose words were their own name, as its description, so a screen reader read the name twice. Where the slot names its control with the tooltip's words, as its text or its `aria-label`, the tooltip now leaves the description out by itself, as `describes` does; a shortcut drawn after the words keeps it.

- **The statement an [energy label](https://docs.wirekit.app/components/energy-label) or a [tire label](https://docs.wirekit.app/components/tire-label) reads out stays inside the label.** The visually hidden sentence beside each class was placed against the page on a desktop, and on every screen for a label without a link, because nothing in the label had a position of its own: a scroll container around the label did not clip it, and past the edge of one that scrolls sideways it widened the page. The label is now the positioned box for its statement, unless a class on it sets a position.

- **A `disabled`, `required` or `readonly` that reaches no form control is reported while debugging.** The three are valid HTML, so they passed as attributes on every component, and on a component that gives them to no control of its own they landed on the element around its button or field and did nothing: `disabled` on an [accordion](https://docs.wirekit.app/components/accordion) item or a [floating action button](https://docs.wirekit.app/components/fab) left the button enabled. The same held for `wire:loading.attr="disabled"`, which on a [multi-select](https://docs.wirekit.app/components/multi-select) or a [file upload](https://docs.wirekit.app/components/file-upload) left the field operable while a request ran. Such a component now logs a warning that names the attribute, and [`StrictnessGate::controlAttributesWithoutAControl()`](https://docs.wirekit.app/strict-validation#asking-the-gate-instead-of-reading-its-log) gives a test the same answer. The attribute on a `<fieldset>` around a component disables every control inside it. An `autofocus` that reaches nothing that can take the focus is reported the same way.

- **A `wire:model` on a component that binds no value with it is reported while debugging.** `wire:` passes as framework wiring, so a `wire:model` on a collapsible, an accordion or a card landed on the element around its content, where no field shows the property's value, and nothing said so. Such a component now logs a warning that names the binding with its property, and [`StrictnessGate::controlAttributesWithoutAControl()`](https://docs.wirekit.app/strict-validation#asking-the-gate-instead-of-reading-its-log) gives a test the same answer. The form components, a [modal](https://docs.wirekit.app/components/modal), a [drawer](https://docs.wirekit.app/components/drawer) and an [alert dialog](https://docs.wirekit.app/components/alert-dialog) take it as before. A component that binds it in one mode only reports it in a mode where it binds nothing and names what is missing: a [data table](https://docs.wirekit.app/components/data-table) without `selectable`, a [pagination](https://docs.wirekit.app/components/pagination) without `per-page-options`, a readonly [rating](https://docs.wirekit.app/components/rating) or an editor that cannot be edited.

- **A form around a [command palette](https://docs.wirekit.app/components/command-palette) trigger sends nothing for its search field.** The field had no name of its own, so it was named after its id, and a surrounding form sent the typed text as `input-1`. What the field holds goes to the palette, and the field now renders no name.

- **An empty `name` on a form control sends nothing, on every control.** An [input](https://docs.wirekit.app/components/input) given `name=""` already rendered no name, so a form skipped it. A [checkbox](https://docs.wirekit.app/components/checkbox), a [toggle](https://docs.wirekit.app/components/toggle), a [radio](https://docs.wirekit.app/components/radio), a [password input](https://docs.wirekit.app/components/password-input), a [time picker](https://docs.wirekit.app/components/time-picker), a [rating](https://docs.wirekit.app/components/rating) and a [segmented control](https://docs.wirekit.app/components/segmented-control) wrote `name=""`, which HTML does not allow, and a [range slider](https://docs.wirekit.app/components/range-slider), a [one-time code](https://docs.wirekit.app/components/otp-input) and a [phone field](https://docs.wirekit.app/components/phone) built names from it that a form sent: `[min]` and `[max]`, `[]`, `[number]` and `[country]`. Each now renders no name.

- **A Brazilian Portuguese page reads Brazilian where the two varieties differ.** A `pt-BR` page fell back to the European wording for strings its catalog did not carry: the password meter read "Palavra-passe fraca" beside "Mostrar senha", pagination "Seguinte", the typing indicator "está a escrever" and the sign-in buttons "Iniciar sessão". They now read "Senha fraca", "Próximo", "está digitando" and "Entrar com", and so do the other sections, views and dividers that were written the European way.

- **The French catalog addresses the reader as "tu" throughout,** as the other catalogs address the reader informally. Among the sentences in "tu", some said "vous" or used the formal imperative: "Réessayez", "Votre navigateur écrit les dates…", "Cliquez sur une carte…". They now read "Réessaie", "Ton navigateur…" and "Clique…".

- **A shortcut that [`x-wk-shortcut`](https://docs.wirekit.app/components/shortcuts#a-shortcut-the-grammar-does-not-read) cannot read is reported.** It bound nothing without a word, so a typo such as `cmd+shfit+s` read as a shortcut that works. With `APP_DEBUG` on, the page of the overview of keyboard shortcuts warns about it in the browser console, as it warns about a shortcut bound twice.

- **A [list](https://docs.wirekit.app/components/list) without markers and a [stack](https://docs.wirekit.app/components/stack) rendered as a `ul` or `ol` stay lists for VoiceOver on iPhone and iPad.** WebKit treats a list without markers as plain text, and both rendered one without a role: `type="none"` removes the markers of a list, and Tailwind's preflight removes those of every `ul` and `ol`. A screen reader on iOS therefore announced neither the list nor the number of its items. Both now carry `role="list"`, and a `role` on the tag replaces it.

- **A [timeline](https://docs.wirekit.app/components/timeline) row takes a date object for its time.** Given PHP's own `DateTime` or `DateTimeImmutable` as `time` or `datetime`, a row ended the page. Given a Carbon, it showed `2026-10-25 12:00:00` as its text and wrote the same value without its offset as `datetime`, and a Unix timestamp stood in `datetime` as a bare number, which HTML reads as a year. A date object as `time` is now written as the page's language writes a day with a time of day and gives the row its `datetime` as well. In `datetime`, a date object or a timestamp is written with its offset, a string such as `2026-09` as it stands, and a text that names no moment is reported.

- **A date given only as a zone is reported.** A [countdown](https://docs.wirekit.app/components/countdown), a [message](https://docs.wirekit.app/components/message), a [review](https://docs.wirekit.app/components/review), a [date separator](https://docs.wirekit.app/components/date-separator), an [event calendar](https://docs.wirekit.app/components/event-calendar) and a timeline row read `CET`, `UTC` or a single letter such as `x`, which PHP takes for a military zone, as the current wall-clock time with that zone's offset put on it: an instant hours away from now. Such a text names no moment and is reported as an invalid date, as `TBD` is. `now`, `tomorrow`, `+1 day` and a day with its zone read as before.

- **An [activity row](https://docs.wirekit.app/components/activity-row) and a [usage meter](https://docs.wirekit.app/components/usage-meter) take a date object as well.** Given PHP's own `DateTime` or `DateTimeImmutable` as `timestamp` or `resetAt`, either ended the page, and given a Carbon, it showed `2026-10-25 12:00:00`. An activity row now writes a date object as how long ago it was in the page's language, in a `<time>` that carries the moment; a usage meter writes it as the day it resets, "Resets Jan 1, 2027" in English. Text reads as before.

- **A month and a week field take a date object, as a date field does.** An [input](https://docs.wirekit.app/components/input) with `type="month"` or `type="week"` wrote a Carbon given as `value`, `min` or `max` as `2026-10-25 12:30:00`, which the browser drops, so the field stayed empty and set no limit, and PHP's own `DateTimeImmutable` ended the page. Both now write it in their own form, `2026-10` and `2026-W43`, with the week and its year numbered by ISO 8601, and a binding to a date object warns in debug mode as it does on a date field.

- **A `timezone` takes a zone object.** Given PHP's own `DateTimeZone`, as `getTimezone()` of a `DateTimeImmutable` returns it, a countdown, a message, a review and a date separator ended the page: their `timezone` took a zone name only. A zone object now names its zone, as a `CarbonTimeZone` already did.

- **A link under the heading of a [card that folds](https://docs.wirekit.app/components/card#a-card-that-folds) and a button in its hints take their own click.** A press anywhere on the head folds the card, and the area that answers it lay over the whole head: a link in the `description` slot, or the button of a dismissible badge in the hints, folded the card instead of answering. Both stand above that area now, and the words around them stay part of the head.

- **A range no longer tints the days of the previous or the next month that pad a [calendar](https://docs.wirekit.app/components/calendar) grid.** They showed part of the range without its ends, and with two months the same days a second time. The range shows in the grid of its own month, in a calendar as in the dialog of a [date picker](https://docs.wirekit.app/components/date-picker) or a [datetime picker](https://docs.wirekit.app/components/datetime-picker).

- **The text field of a [color picker](https://docs.wirekit.app/components/color-picker) with `popover` reads a hex value typed without its `#`,** as design tools copy one: `B87334` arrives as `#b87334` rather than being called invalid.

- **A list pasted into a [tags input](https://docs.wirekit.app/components/tags-input) one entry to a line, or from the cells of a spreadsheet row, makes one tag per entry.** The field split only at commas, so the browser ran the lines together into a single tag.

- **A [phone](https://docs.wirekit.app/components/phone) number typed with the international prefix `00`, or with `011` on the North American plan, picks its own country as one with a plus does.** `0043 1 234567` on a field that stood on Germany was saved as `+490431234567`, a wrong number, where `+431234567` was meant. Digits after a prefix that name no country bind nothing.

- **A [file upload](https://docs.wirekit.app/components/file-upload) writes the size of each file as an [attachment](https://docs.wirekit.app/components/attachment) does,** whole bytes and one decimal below 10, `512 B` and `24 MB` rather than `512.0 B` and `24.0 MB`, with thousands grouped and in the application's own number format where `WireKit::formatNumbersUsing()` sets one.

- **A [number input](https://docs.wirekit.app/components/number-input#decimal-input) with a step below 0.000001, or with a `min` or `max` that has more decimal places than its step, keeps the value it is given.** It rounded every value to the places of the step alone, so `step="0.00000001"` turned every value into a whole number, and `min="0.99" step="1"` turned 1.99 into 2, which the browser then refused as a value off the step.

- **An empty component that is both `required` and `readonly` no longer stops its form from being sent,** as a read-only native field does not. A [multi-select](https://docs.wirekit.app/components/multi-select), a [tags input](https://docs.wirekit.app/components/tags-input), an [OTP input](https://docs.wirekit.app/components/otp-input), a [combobox](https://docs.wirekit.app/components/combobox), a [datetime picker](https://docs.wirekit.app/components/datetime-picker) and a [date picker](https://docs.wirekit.app/components/date-picker#popover) or [time picker](https://docs.wirekit.app/components/time-picker#popover) with `popover` kept the empty value in the browser's check, so the form showed the browser's message on a field nobody could fill.

- **A link with `target="_top"` or `target="_parent"` on a page no frame holds asks in the kit's dialog before it leaves unsaved changes,** as a link without a target does. Both name the same window there, and the [question before leaving](https://docs.wirekit.app/components/unsaved-hint) took them for another one, so only the browser's own prompt asked, without the list of what is unsaved. Inside a frame they still go to the browser.

- **A `placement` an overlay cannot place is reported under the name of the tag it was written on.** A [status dot](https://docs.wirekit.app/components/status-dot), an [app rail](https://docs.wirekit.app/components/app-rail) item, the [scope switcher](https://docs.wirekit.app/components/scope-switcher) and the collapse toggle of a [sidebar](https://docs.wirekit.app/components/sidebar) handed the word to the tooltip or popover inside them, and the report named that one instead. Each now checks it itself and hands on a word the overlay can place.

- **An entry of `unavailable` that names neither a day nor a time is reported.** A [calendar](https://docs.wirekit.app/components/calendar#limits), a [date picker](https://docs.wirekit.app/components/date-picker#popover) with `popover` and a [datetime picker](https://docs.wirekit.app/components/datetime-picker) left such an entry out without a word, so a closed day written as `2026-13-45` or `24.12.2026`, or a closed time written as `25:00`, stayed open for booking. It is now reported through [strict validation](https://docs.wirekit.app/strict-validation#dates-and-times), as a `min` or `max` that cannot be read is, and still closes nothing. An empty entry, white space and the zero date pass without a report.

- **A [field](https://docs.wirekit.app/components/field) named with a space, such as `first name`, links its own hint and help to the control inside it.** The field built their ids from its name as given, so the control's `aria-describedby` named `first`, `name-hint` and `name-help`, ids no element carries, and a screen reader read neither. A [card](https://docs.wirekit.app/components/card), a [filter builder](https://docs.wirekit.app/components/filter-builder) and a [notification center](https://docs.wirekit.app/components/notification-center) given an `id` with a space build the ids of their parts without it, and a [resizable](https://docs.wirekit.app/components/resizable) panel takes its id without it, so its handle names it. Each run of whitespace becomes a hyphen, as it does in every input and picker; a root keeps the id it was given.

- **A range of [checkboxes](https://docs.wirekit.app/components/checkbox#picking-a-range-with-shift) picked with Shift held leaves out a checkbox the reader cannot see.** A box in a row that a filter hides, with `x-show` or `hidden`, or inside a closed `<details>` was ticked with the rows around it, so an action on the selection afterwards reached rows nobody saw. A checkbox hidden behind a label drawn in its place still counts through that label. A data table with `selectable` was never affected: it renders only the rows it shows.

- **The value under a cell of a treemap [chart](https://docs.wirekit.app/components/chart) takes the decimals its series names,** as its tooltip does. A cell kept the chart's `value-decimals`, so a series with two decimals of its own read `5` in its cell and `4,53` in its tooltip.

- **A preset of a [calendar](https://docs.wirekit.app/components/calendar#presets) or a [date picker](https://docs.wirekit.app/components/date-picker#presets) that starts or ends on an unavailable day can no longer be picked.** With today among the `unavailable` days, "Today" picked it and "Last 7 days" ended on it, where a click on that day picks nothing. A preset that only covers such a day stays open.

- **An animated [stat](https://docs.wirekit.app/components/stat) and a [countdown](https://docs.wirekit.app/components/countdown) write their numbers in the application's own marks.** With a format given through `WireKit::formatNumbersUsing()`, the count of an animated stat ended in the grouping and decimal marks of the locale, so the number the page showed changed its format once the count ended, and the leading unit of a countdown grouped the locale's way. Both write the application's marks now, as a [chart](https://docs.wirekit.app/components/chart) does.

- **A second click on a link opens an [accordion](https://docs.wirekit.app/components/accordion#linking-to-an-item) item, a collapsible [card](https://docs.wirekit.app/components/card#opening-it-from-elsewhere) or a hidden part of a [card stack](https://docs.wirekit.app/components/card-stack) that the reader closed after the first.** A link to the fragment the address already names leaves the address as it is, so the browser fires no `hashchange`, and the page scrolled to the item while it stayed closed. The three read that click as well.

- **A button with `formmethod="dialog"` closes its dialog while a [form](https://docs.wirekit.app/components/form#sending-a-form-once) with `submit-once` is held.** After a download, which leaves the page as it is, the form holds every further submission back for its wait, and the Cancel button of a dialog around it was held back with them, so the dialog stayed open for ten seconds, or for good with a wait of `0`. A submission that closes a dialog goes at any time, and the hold stays.

- **Without an icon package, a [sidebar](https://docs.wirekit.app/components/sidebar) item, a collapsible sidebar group and an [app rail](https://docs.wirekit.app/components/app-rail) item no longer show the icon's name beside their label.**

- **A [floating action button](https://docs.wirekit.app/components/fab) whose icon cannot be drawn shows its plus,** where an unknown icon name in a request left an empty circle.

- **A prop that takes one value from a list reads a list as not given instead of ending the page.** A `size`, a `variant`, an `intent` or another prop with a fixed set of values, given a list, a collection or an object without a text of its own, ended the page in most components, in a request too. Each now goes through [strict validation](https://docs.wirekit.app/strict-validation#values-from-a-list): with debug on, a Pest test or an `artisan` command throws, and a request logs it and renders the component with the prop's default. A prop of the same name that takes a date or a list elsewhere, such as the `max` of a [calendar](https://docs.wirekit.app/components/calendar) or the `columns` of a [data table](https://docs.wirekit.app/components/data-table), is read as before.

- **A [field](https://docs.wirekit.app/components/field), a [sidebar](https://docs.wirekit.app/components/sidebar) group, a mixed [chart](https://docs.wirekit.app/components/chart) and [tabs](https://docs.wirekit.app/components/tabs) given a list where they take a switch or a number no longer end the page.** The `required` of a field, the `collapsible`, `open` and `force-open` of a sidebar group, the `wire-stream-cap` of a mixed chart and the `wrap` of tabs report the list through [strict validation](https://docs.wirekit.app/strict-validation) and render with their default. The `count` of a [reaction](https://docs.wirekit.app/components/reaction), the `quantity` of a [cart line](https://docs.wirekit.app/components/cart-list), the `value` of a [radial progress](https://docs.wirekit.app/components/radial-progress) and the `threshold` of a [reading bookmark](https://docs.wirekit.app/components/reading#reading-bookmark), given a list or an object, render with their default as well.

- **A prop that takes one value, such as `scope`, reads a list as not given instead of ending the page.** The `scope` every component takes, the `srcset` of an [image](https://docs.wirekit.app/components/image), the `timezone` of a [date separator](https://docs.wirekit.app/components/date-separator) and other props for a single value ended the page when given a list, in a request too. Each now reports it through [strict validation](https://docs.wirekit.app/strict-validation#values-from-a-list) and renders without it, and an object such as a time zone or a date is read as before.

- **The [optimistic](https://docs.wirekit.app/extending/optimistic-ui) layer shows its state on its own root, also when a button's click applies it.** The root stayed `idle` while a request ran and the button kept `optimistic` after it settled, because the state was written on the element whose click applied it.

- **A table in [prose](https://docs.wirekit.app/components/prose) fits a narrow column, also without attributes.** A cell breaks a long word where its column is narrower than the word, so a table that a Markdown pipeline renders without attributes no longer pushes the page sideways on a phone. It stays a table.

- **A [bulk selection](https://docs.wirekit.app/components/bulk-selection#with-livewire) whose binding writes every match selects the rows of the page,** from a "Select all" in a toolbar or from a state the page loads with. The notice said every match was selected while the rows and the header checkbox stayed clear.

- **A [map](https://docs.wirekit.app/components/map) drawn with Leaflet that misses one tile writes no load-failure message.** The hint that names a Content-Security-Policy block comes once no tile in view loaded, so a tile missing at the edge of a set that covers one area stays quiet.

- **An `x-ref` written on a part of a component reaches the `$refs` of the code around it,** on the parts of a [tabs](https://docs.wirekit.app/components/tabs), a [tree view](https://docs.wirekit.app/components/tree-view), a [sidebar](https://docs.wirekit.app/components/sidebar), a [dropdown](https://docs.wirekit.app/components/dropdown), a [context menu](https://docs.wirekit.app/components/context-menu), a [menubar](https://docs.wirekit.app/components/menubar), a [resizable](https://docs.wirekit.app/components/resizable) group, a [table](https://docs.wirekit.app/components/table) and an [app rail](https://docs.wirekit.app/components/app-rail), and on the triggers of a [drawer](https://docs.wirekit.app/components/drawer), the [shortcuts](https://docs.wirekit.app/components/shortcuts) dialog and a [command palette](https://docs.wirekit.app/components/command-palette). An item of a dropdown panel is included, though the panel is moved to the overlay root.

- **A range in a [calendar](https://docs.wirekit.app/components/calendar#date-range) draws one continuous band from end to end,** square where it meets an end, where the days between the ends were separate rounded tiles with a gap between them. While the pointer previews an end, the band reaches the day under it, and that day carries a stronger tint than the band. The same holds in the dialogs of a [date picker](https://docs.wirekit.app/components/date-picker) and a [datetime picker](https://docs.wirekit.app/components/datetime-picker).

- **A [calendar](https://docs.wirekit.app/components/calendar#date-range) with more than one month names each month once.** The header named the first month above grids that each name their own, so that month stood twice, and in the dialog of a [date picker](https://docs.wirekit.app/components/date-picker) or a [datetime picker](https://docs.wirekit.app/components/datetime-picker) on a phone, which shows one grid, both names stood directly above one another. With several grids in view the header holds the arrows, and with one grid in view it names the month. A screen reader still hears the change of month, and each grid keeps its month as its name.

- **The grids of a [calendar](https://docs.wirekit.app/components/calendar#date-range) with more than one month fill a calendar that its container stretches,** as one month does. In a `flex flex-col` or a grid the header ran across the whole width while the grids stood together at its start, or narrower than the card on a phone. Side by side the grids now share the width, and each takes a whole line once they wrap. A container that fits its content looks as before.

- **The panel of a [notification center](https://docs.wirekit.app/components/notification-center) stays open while the keyboard moves through it on a phone.** Opening it, the arrow keys in its filters and "Mark all read" moved the focus in a way that let the browser scroll the page, and a scroll that moves the bell closes the panel, so on a page with smooth scrolling it closed under the reader's keys and left the focus nowhere. The focus moves without scrolling the page now.

- **"Jump to latest" in a [conversation](https://docs.wirekit.app/components/conversation#keyboard-interaction) moves the focus to the transcript.** The button hides once the view reaches the newest message, which its own press brings about, and the focus it held fell to the page, so the next Tab started at the top of the page instead of in the conversation. A press with the keyboard, or with a pointer in a browser that focuses the button, leaves the focus on the transcript, where the arrow keys scroll on.

- **The arrow keys that open and close a branch of a [tree view](https://docs.wirekit.app/components/tree-view#handling-selection) no longer send `tree-node-select`.** Right and Left toggled the branch through a click on its row, and that click reached the tree's selection, so a page that opens a record on the event opened one whenever a reader unfolded a branch with the keyboard. A click, Enter and Space still select.

- **An [OTP input](https://docs.wirekit.app/components/otp-input#knowing-when-the-code-is-complete) announces a whole code corrected by overwriting a box.** `wirekit:otp-complete` fired when the boxes filled up, which a full code never does again, so a code corrected the way the page recommends, one pass from the left without deleting, was never announced, and a page that checks the code on the event and leaves a wrong one standing never received the corrected one. The event now fires for every whole code that differs from the one announced last, never for the same code twice in a row, and once every box is empty the next code counts as a new attempt.

- **A row with `x-wk-flash` that starts leaving flashes and goes, also without a new key.** The page on [flashing a row that changed](https://docs.wirekit.app/animations#flashing-a-row-that-changed) has the render that removes a row draw it once more with `data-wk-flash="danger"` and `data-wk-flash-leave`, but the flash played only on a new `data-wk-flash-key`, so a row that kept its key stood there without a flash until the next render took it out. Setting `data-wk-flash-leave` plays the flash now, and a leave that brings a new key along plays it once.

- **A click inside the open list of a [combobox](https://docs.wirekit.app/components/combobox) or a [multi-select](https://docs.wirekit.app/components/multi-select) that chooses nothing keeps the list open.** Both lists are moved out of the component to the overlay root, and the component read every press in them as one outside it, so a click on a disabled option, a group heading, the list's edge or one of its notes closed the list. A click outside the component and its list still closes it.

- **The note under the results of a [combobox](https://docs.wirekit.app/components/combobox) or a [multi-select](https://docs.wirekit.app/components/multi-select) with `server` never stands empty in the list.** For a moment between showing the row and writing its text, the row that says a newer search is still out or that the results were cut stood visible and empty, and in the combobox and the multi-select's panel it is an option, so an accessibility check met an option without a name. An empty row is out of sight and out of the accessibility tree now, and the notes are read out as before.

- **A panel opened again from its trigger while it is still closing stays open.** The panels of a [filter builder](https://docs.wirekit.app/components/filter-builder), a [color picker](https://docs.wirekit.app/components/color-picker) and a [notification center](https://docs.wirekit.app/components/notification-center), the dialog of a [datetime picker](https://docs.wirekit.app/components/datetime-picker) and those of a [date picker](https://docs.wirekit.app/components/date-picker#popover) and a [time picker](https://docs.wirekit.app/components/time-picker#popover) with `popover` close on a press outside them, and they counted their own trigger as outside. A panel opened again while it was still on its way out, as after a filter was applied and its chip removed, closed in the same click and left the focus nowhere. A press on the trigger is left to the trigger, which opens and closes the panel.

- **A confirmed save in an [inline edit](https://docs.wirekit.app/components/inline-edit#where-focus-goes) hands the focus back to the trigger.** The trigger is shown on an animation frame, and the focus could be handed to it before that frame, while it was still hidden, so the focus stayed on the page and the next Tab started at its top. The editor now waits for the frame that shows the trigger, as it already does for the one that shows the field when it opens. The same holds after Escape and after a confirm that changed nothing.

- **An answer to an [inline edit](https://docs.wirekit.app/components/inline-edit#the-editor-stays-open-until-the-save-is-confirmed) reaches only the editor that sent the value.** `wirekit:inline-edit-saved` and `wirekit:inline-edit-failed` name an editor, and every editor of that name took them, so on a page that gives a name more than once an answer for one closed the others too, an editor an error had opened among them, and handed the focus to the last of them. An editor takes an answer now only while it waits for one, also after its save timeout gave up.

- **In a [resizable](https://docs.wirekit.app/components/resizable) layout of three or more panels, a handle follows a panel that another handle moved.** The second handle sizes the middle panel, which a drag on the first handle resizes too, and it kept announcing the size it had written itself and stepped from there, so its next arrow key or step control set the middle panel back near its old size in one press. A handle now reads the size its panel has, announces it with the range that is left, and moves from it.

- **The hint above a [live list](https://docs.wirekit.app/components/live-list#fresh-rows-out-of-sight) rests below whatever pins itself to the top of the list's scroller, and a fresh row under it counts as out of sight.** "New entries above" sat a fixed distance below the top of the viewport and lay under a strip of an [announcement banner](https://docs.wirekit.app/components/announcement-banner), a [sticky navbar](https://docs.wirekit.app/components/navbar#sticky-navbar) or another bar pinned there. It rests below the scroller's `scroll-padding-top` now, which a strip, every pinned bar of the kit and a bar of an application's own with [`data-wk-scroll-inset`](https://docs.wirekit.app/extending/public-css-api#keeping-the-focus-clear-of-a-pinned-bar) report, and in a panel of its own below the top edge of the panel, which a strip of the page does not cover. `--wk-live-list-top` on the list places it below a fixed bar that reports nothing. Where the page scrolls the list, a fresh row that landed under such a bar counted as seen and raised no hint; it counts as out of sight now, and the hint brings it out from under the bar. The reader's line stays where it was while entries arrive, also when such a bar changes its height in the meantime.

- **The hint of a [live list](https://docs.wirekit.app/components/live-list#fresh-rows-out-of-sight) brings its row into view in Safari and on iPhone and iPad.** The hint scrolled to the fresh row and then moved the focus to it, and WebKit stopped the smooth scroll the moment the focus moved: the row stayed out of sight with the focus on it, where the page scrolls the list and in a region of its own. The focus comes first now and the scroll after it, and a row still wholly out of sight once the glide has had its time comes in without the animation.

- **[`wirekit:doctor`](https://docs.wirekit.app/cli-reference/wirekit-doctor) scans the log files where the `single` and `daily` channels write them.** The silent-typo scan looked only at `storage/logs/laravel*.log`, so with the daily files moved into a folder of their own, as a logrotate rule over `storage/logs/*.log` makes advisable, it skipped itself on every run and no rejected prop value surfaced. It reads each channel's `path` now and finds the daily files beside it under the names Laravel gives them.

- **The collapse control of a [sidebar](https://docs.wirekit.app/components/sidebar) lines up with the item icons.** In both states its glyph stood a few pixels left of the column of the icons: its placement never reached the column, and the glyph sat closer to the button's edge than an icon to its row's. Expanded it now starts where the icons start, collapsed it centers in the rail as they do, also on the footer band.

- **The icons of a [sidebar](https://docs.wirekit.app/components/sidebar)'s items and collapsible triggers center on their labels' letters.** Inter sets its letters above the middle of the line, so an icon centered on its row read 1 to 2px low beside the label. The stylesheet lifts it by the new [`--font-wk-icon-nudge`](https://docs.wirekit.app/theming/design-tokens#typography) token, `-1px` for Inter, and keeps it there while the sidebar is collapsed, so folding moves no icon; any element that carries `data-wk-icon-nudge` takes the same offset. The amount suits Inter, so the theme presets with a font of their own, a sans set in `fonts.sans` and `wirekit:install --font` with any font but Inter set it to `0px`.

- **A cell of a stacked [table](https://docs.wirekit.app/components/table#stacked-rows-on-small-screens) aligned to the end shows a label of its own.** Such a cell always stood as the footer of the card, where no name shows, so its `label` never appeared. A label of its own now makes it a named line.

- **An [alert](https://docs.wirekit.app/components/alert#after-an-action) that a Livewire render adds after an action is announced.** Livewire inserts such an alert together with its text, and an inserted `role="status"` is not announced on its own, so the reader who had just submitted a form heard nothing of its result. WireKit's script keeps one polite status region on the page from the start and says the intent, the title and the message of each polite alert a render adds, without its actions or its dismiss button. A `danger` alert is still announced by its own `role="alert"`, an alert inside a status region of the page's own is left to that region, and an alert rendered with the page says nothing on load.

- **[`wirekit:install --font`](https://docs.wirekit.app/cli-reference#wirekitinstall) changes the font of the components, not only of the body copy.** The block it writes into `resources/css/app.css` set `--font-wk-sans`, `--font-wk-serif` or `--font-wk-mono` inside `@layer base`, and a declaration in a cascade layer loses to the unlayered tokens of `wirekit.css` whatever its specificity, so every component kept Inter beside text in the new font. The block now sets the token in a plain `:root` rule; running the command again replaces the old block between its markers.

- **A language named with a locale of the application, such as `pt_BR`, reaches `lang` as the tag HTML reads, `pt-BR`.** The option of a [select](https://docs.wirekit.app/components/select) and of a [segmented control](https://docs.wirekit.app/components/segmented-control), a field of a [translatable input](https://docs.wirekit.app/components/translatable-input) and the label of a [checkbox](https://docs.wirekit.app/components/checkbox) and a [radio](https://docs.wirekit.app/components/radio) wrote it as given, and HTML reads `pt_BR` as an unknown language, so a screen reader kept the voice of the page. A charset or a modifier, as in `de_DE.UTF-8`, is left out as well, and the language props new in this release read it the same way.

- **[Tabs](https://docs.wirekit.app/components/tabs) with [`findable`](https://docs.wirekit.app/components/tabs#find-in-page) start on the tab the server names.** With `active` set to another tab than `default`, the tabs went back to the default tab as soon as the page started, in every browser that supports `hidden="until-found"`: the panel drawn open for the default tab read like a panel the reader had found with the browser's search. The tab the server names now stays.

- **A [sign-in button](https://docs.wirekit.app/components/sign-in-button) without `href` takes the `type` it is given.** It wrote `type="button"` ahead of the attributes it was given, so a `type="submit"` came second and was ignored, and a form that starts the sign-in with a POST request sent nothing. Without a `type` it is a plain button, as before.

- **A [sign-in button](https://docs.wirekit.app/components/sign-in-button) drawn by WireKit is as tall as a finger needs on a touch screen.** Drawn at the medium control height, the button of Google, Apple, Facebook or PayPal stayed below the 44px a touch target takes under a coarse pointer. It reaches that height there now and keeps its size under a mouse, and the button image of a service keeps the size the service draws it at.

- **A [floating action button](https://docs.wirekit.app/components/fab), its actions and a [profile](https://docs.wirekit.app/components/profile) drawn as a button take the `type` they are given,** and a tab, a menu item, a submenu trigger, a command palette option, a close button, a sidebar toggle, a rail item and a toggle button keep `type="button"` without a second `type` beside it. Each view wrote its own `type` ahead of the attributes it was given, and the first of two equal attributes is the one that counts.

### Documentation

- **The [phone number recipe](https://docs.wirekit.app/blueprints/recipes/phone-number-validation) shows its field in the form its title promises,** with the Livewire wiring `wirekit:make` writes, and the [marketing landing page](https://docs.wirekit.app/blueprints/recipes/marketing-landing-page) recipe describes the colors its sparklines are drawn in.

- **The [marketing landing page](https://docs.wirekit.app/blueprints/recipes/marketing-landing-page) recipe no longer stacks a small uppercase label over its sections or a row of invented customer logos under the hero.** Each section opens with its heading and lede, `wirekit:make recipe:marketing-landing-page` writes its sections the same way, and the [landing page with a table of contents](https://docs.wirekit.app/blueprints/recipes/marketing-landing-toc) names its brand without an emoji.

- **The [alert dialog](https://docs.wirekit.app/components/alert-dialog#checking-the-phrase-on-the-server) page shows how an action receives the typed phrase.** `wire:click="destroyEnvironment(typed)"` on the confirm control sends `null`: the dialog's panel stands at the end of the page, outside the element that holds `typed`, and Livewire reads a name it does not find in the Alpine data around an element as a property of the component. The page shows `x-on:click="$wire.destroyEnvironment(typed)"`, which Alpine evaluates with the dialog's data, and the phrase checked again on the server.

- **The [card](https://docs.wirekit.app/components/card) and [liquid glass](https://docs.wirekit.app/components/liquid-glass) pages give a card's title a heading.** Their examples wrote it as text in `card.header`, which gives its content the look of a heading and not its role, so a screen reader listed no heading for the card. Each title now stands in a heading, and the card page says so under Accessibility.

- **The [mixed chart](https://docs.wirekit.app/components/chart-mixed) page says what `wireStreamMode` decides.** It called it the handling of a malformed streamed point. It decides the cap: `strict` keeps each dataset at `wireStreamCap` points and drops the oldest first, `stream` lets the series grow without a bound, as on the [chart](https://docs.wirekit.app/components/chart#props) page.

- **The [brand](https://docs.wirekit.app/components/brand#keyboard-interaction) page names `:href="false"` for a brand that is not a link.** It said `:href="null"`, which a prop reads as not given, so the brand kept its link to `/`.

- **The first example on the [events](https://docs.wirekit.app/events#listening-from-alpine) page shows the tab it hears.** It read a `name` from `wirekit:tab-changed`, which carries the tab's key as `tab` and its label as `label`, so its preview showed a dash after every click, and the sentence below it sent the event from Livewire with a `name` no tab reads. It now reads `tab`, and the sentence points at the way [tabs](https://docs.wirekit.app/components/tabs#observing-tab-changes-server-side) are observed from a Livewire component.

- **The examples that listen to WireKit's events run under a Content-Security-Policy build.** On the [events](https://docs.wirekit.app/events#listening-from-alpine), [sidebar](https://docs.wirekit.app/components/sidebar#your-own-trigger) and [tree view](https://docs.wirekit.app/components/tree-view#handling-selection) pages, a listener used optional chaining, an `if` statement or `console`, none of which Alpine's CSP build evaluates: on a page with Livewire's `csp_safe` or WireKit's CSP bundle, a copied listener did nothing and reported nothing. Each is an assignment, a `&&` or a call now, and the [integration](https://docs.wirekit.app/getting-started/integration#content-security-policy) page says where an example's own logic goes on such a page.

- **The [slider](https://docs.wirekit.app/components/slider#pitfalls), [textarea](https://docs.wirekit.app/components/textarea#pitfalls) and [select](https://docs.wirekit.app/components/select#pitfalls) pages name the Livewire 4 binding that sends.** They recommended `wire:model.change` or `wire:model.blur` in place of `.live`, and without `.live` neither sends anything by itself. The binding that sends when a slider is released is `wire:model.live.change`, and the one that sends when the reader leaves a field is `wire:model.live.blur`.

- **The streaming examples on the [shimmer](https://docs.wirekit.app/components/shimmer#livewire) and [assistant message](https://docs.wirekit.app/components/assistant-message#streaming-and-announcements) pages set their streaming state in a request of its own.** Both turned `$streaming` on and off inside the request that streams, and a streamed request renders the component's state only when it ends, so the shimmer never moved and the message never showed its thinking state or `aria-busy`. `submit()` now sets the state and starts the stream with `$this->js('$wire.ask()')`, and the shimmer example gets the `wire:stream` target and the property its text streams into.

- **The [assistant message](https://docs.wirekit.app/components/assistant-message#streaming-and-announcements) example for `announce="all"` says where its event comes from.** Its listener called `flush()` on `stream-finished`, which none of the examples dispatched, so a message copied from them never announced its answer. The streamed method now dispatches the event as its last step, and keeps the answer in its property, so the last render shows what was streamed.

- **The headless example on the [countdown](https://docs.wirekit.app/components/countdown#headless-your-own-copy-around-the-number) page binds the number rather than a template literal.** A Content-Security-Policy build reads no template literal, so the copied example showed no number there, with no error anywhere. The words now stand in the markup, as in the component's own source, and the page says why.

- **Seven examples close their tags and run as pasted.** On the pages of the [accordion](https://docs.wirekit.app/components/accordion), the [app shell](https://docs.wirekit.app/components/app-shell), the [table](https://docs.wirekit.app/components/table), the [dropdown](https://docs.wirekit.app/components/dropdown), the [drawer](https://docs.wirekit.app/components/drawer), the [command palette](https://docs.wirekit.app/components/command-palette) and the [alert dialog](https://docs.wirekit.app/components/alert-dialog), an example that showed one prop through an opening tag alone ended with a parse error when pasted as it stood.

- **The [optimistic UI](https://docs.wirekit.app/extending/optimistic-ui#using-it) page explains `optimistic-args`.** A control that repeats once per row, such as a checkbox in each line of a task list, tells its method which row it belongs to: the values of `optimistic-args` follow the new value in the call. The page every optimistic component links to did not say so.

- **The [Leaflet & OpenStreetMap](https://docs.wirekit.app/components/map/leaflet) page sets the tile source once for every map, and its examples follow that setting.** Each example set its `styleUrl` to the public OpenStreetMap tile server; now none sets one, so they draw the tiles a site configures, and a copied example loads from wherever the application's other maps load. The [map](https://docs.wirekit.app/components/map#your-own-tile-server) page shows the settings for both engines, and the [MapLibre](https://docs.wirekit.app/components/map/maplibre) page says that the demo style, its tiles and its fonts come from `demotiles.maplibre.org`.

- **The error-state example of the [color picker](https://docs.wirekit.app/components/color-picker) no longer promises a named color** in its hint, which no field of the picker reads.

- **The [price](https://docs.wirekit.app/components/price#minor-units-cents) page says that `minor-units` divides by 100 for every currency,** and how to pass a currency whose minor unit is no hundredth, such as the yen or the Bahraini dinar.

- **The page on [importing only some of the components](https://docs.wirekit.app/dependencies#importing-only-the-components-you-use) shows the same path under a Content Security Policy:** `register()` on the Alpine of Livewire's `livewire.csp.esm.js`, with `@livewireScriptConfig` in the layout, or on `@alpinejs/csp` without Livewire. The README of the bundles points to it and to the `factories` that `wirekit:export-api-map` lists for every component.

- **The [calendar](https://docs.wirekit.app/components/calendar#range-limits)'s range limits say that a range may cover an unavailable day.** `unavailable` closes the days a range can start or end on, not the days between them, so a range that must not include one, a stay for example, is checked on the server.

- **The live example on [overlay events](https://docs.wirekit.app/overlays/events) reads back the event a modal sends when the reader closes it.** It listened for `wirekit-modal-close`, the command a page sends to close a modal, which the modal never sends, so after a close its readout still showed the opening. It shows `wirekit:modal-dismissed` with the route the reader took now, and the page says which of the two events is a command and which a report.

- **The [sidebar](https://docs.wirekit.app/components/sidebar#driving-the-collapse-from-outside) page says where its collapse toggle stands.** It said that `toggle="start"` moves the control to the top, which it never did: with `start` and with `end` the control stands at the foot of the column, lined up with the item icons, and `none` omits it.

- **The accessibility example on the [chart-mixed](https://docs.wirekit.app/components/chart-mixed#accessibility) page gives the label to the chart itself.** It wrapped the chart in a second `role="img"`, which the chart page warns against: two nested images are one to a screen reader, and the chart's own name and the table beside it leave the accessibility tree. The example now passes `aria-label` to `<x-wirekit::chart-mixed>`.

### Components

Every component this release changes, each linked to its page: [Accordion](https://docs.wirekit.app/components/accordion) · [Action Bar](https://docs.wirekit.app/components/action-bar) · [Activity Row](https://docs.wirekit.app/components/activity-row) · [Alert](https://docs.wirekit.app/components/alert) · [Alert Dialog](https://docs.wirekit.app/components/alert-dialog) · [Announcement Banner](https://docs.wirekit.app/components/announcement-banner) · [App Rail](https://docs.wirekit.app/components/app-rail) · [App Shell](https://docs.wirekit.app/components/app-shell) · [Aspect Ratio](https://docs.wirekit.app/components/aspect-ratio) · [Assistant Message](https://docs.wirekit.app/components/assistant-message) · [Attachment](https://docs.wirekit.app/components/attachment) · [Avatar](https://docs.wirekit.app/components/avatar) · [Badge](https://docs.wirekit.app/components/badge) · [Band](https://docs.wirekit.app/components/band) · [Bento Grid](https://docs.wirekit.app/components/bento-grid) · [Blockquote](https://docs.wirekit.app/components/blockquote) · [Bottom Nav](https://docs.wirekit.app/components/bottom-nav) · [Branch Switcher](https://docs.wirekit.app/components/branch-switcher) · [Brand](https://docs.wirekit.app/components/brand) · [Brand Bar](https://docs.wirekit.app/components/brand-bar) · [Breadcrumb](https://docs.wirekit.app/components/breadcrumb) · [Bulk Selection](https://docs.wirekit.app/components/bulk-selection) · [Button](https://docs.wirekit.app/components/button) · [Button Group](https://docs.wirekit.app/components/button-group) · [Calendar](https://docs.wirekit.app/components/calendar) · [Callout](https://docs.wirekit.app/components/callout) · [Card](https://docs.wirekit.app/components/card) · [Card Stack](https://docs.wirekit.app/components/card-stack) · [Carousel](https://docs.wirekit.app/components/carousel) · [Cart List](https://docs.wirekit.app/components/cart-list) · [Cart Summary](https://docs.wirekit.app/components/cart-summary) · [Center](https://docs.wirekit.app/components/center) · [Chart](https://docs.wirekit.app/components/chart) · [Chart Mixed](https://docs.wirekit.app/components/chart-mixed) · [Chat Marker](https://docs.wirekit.app/components/chat-marker) · [Checkbox](https://docs.wirekit.app/components/checkbox) · [Clipboard Button](https://docs.wirekit.app/components/clipboard-button) · [Code](https://docs.wirekit.app/components/code) · [Code Block](https://docs.wirekit.app/components/code-block) · [Collapsible](https://docs.wirekit.app/components/collapsible) · [Color Picker](https://docs.wirekit.app/components/color-picker) · [Combobox](https://docs.wirekit.app/components/combobox) · [Command Palette](https://docs.wirekit.app/components/command-palette) · [Container](https://docs.wirekit.app/components/container) · [Context Menu](https://docs.wirekit.app/components/context-menu) · [Conversation](https://docs.wirekit.app/components/conversation) · [Countdown](https://docs.wirekit.app/components/countdown) · [CTA](https://docs.wirekit.app/components/cta) · [Data List](https://docs.wirekit.app/components/data-list) · [Data Table](https://docs.wirekit.app/components/data-table) · [Date Picker](https://docs.wirekit.app/components/date-picker) · [Date Separator](https://docs.wirekit.app/components/date-separator) · [Datetime Picker](https://docs.wirekit.app/components/datetime-picker) · [Divider](https://docs.wirekit.app/components/divider) · [Drawer](https://docs.wirekit.app/components/drawer) · [Dropdown](https://docs.wirekit.app/components/dropdown) · [Editor](https://docs.wirekit.app/components/editor) · [Empty State](https://docs.wirekit.app/components/empty-state) · [Energy Label](https://docs.wirekit.app/components/energy-label) · [Event Calendar](https://docs.wirekit.app/components/event-calendar) · [FAB](https://docs.wirekit.app/components/fab) · [FAQ](https://docs.wirekit.app/components/faq) · [Feature](https://docs.wirekit.app/components/feature) · [Feature Grid](https://docs.wirekit.app/components/feature-grid) · [Field](https://docs.wirekit.app/components/field) · [File Upload](https://docs.wirekit.app/components/file-upload) · [Filter Builder](https://docs.wirekit.app/components/filter-builder) · [Fit Text](https://docs.wirekit.app/components/fit-text) · [Flag](https://docs.wirekit.app/components/flag) · [Fonts](https://docs.wirekit.app/components/fonts) · [Footer](https://docs.wirekit.app/components/footer) · [Form](https://docs.wirekit.app/components/form) · [Grid](https://docs.wirekit.app/components/grid) · [Header](https://docs.wirekit.app/components/header) · [Heading](https://docs.wirekit.app/components/heading) · [Hero](https://docs.wirekit.app/components/hero) · [Highlight](https://docs.wirekit.app/components/highlight) · [Hover Card](https://docs.wirekit.app/components/hover-card) · [Icon](https://docs.wirekit.app/components/icon) · [Image](https://docs.wirekit.app/components/image) · [Image Compare](https://docs.wirekit.app/components/image-compare) · [Image Editor](https://docs.wirekit.app/components/image-editor) · [Image Gallery](https://docs.wirekit.app/components/image-gallery) · [Image Hotspots](https://docs.wirekit.app/components/image-hotspots) · [Image Hotspots Editor](https://docs.wirekit.app/components/image-hotspots-editor) · [Indicator](https://docs.wirekit.app/components/indicator) · [Inline Edit](https://docs.wirekit.app/components/inline-edit) · [Input](https://docs.wirekit.app/components/input) · [Kanban](https://docs.wirekit.app/components/kanban) · [Kbd](https://docs.wirekit.app/components/kbd) · [Label](https://docs.wirekit.app/components/label) · [Lightbox](https://docs.wirekit.app/components/lightbox) · [Link component](https://docs.wirekit.app/components/link) · [List](https://docs.wirekit.app/components/list) · [Live List](https://docs.wirekit.app/components/live-list) · [Logo Cloud](https://docs.wirekit.app/components/logo-cloud) · [Main](https://docs.wirekit.app/components/main) · [Map](https://docs.wirekit.app/components/map) · [Mark](https://docs.wirekit.app/components/mark) · [Menubar](https://docs.wirekit.app/components/menubar) · [Message](https://docs.wirekit.app/components/message) · [Message Group](https://docs.wirekit.app/components/message-group) · [Message Typing](https://docs.wirekit.app/components/message-typing) · [Mockup](https://docs.wirekit.app/components/mockup) · [Modal](https://docs.wirekit.app/components/modal) · [Multi-Select](https://docs.wirekit.app/components/multi-select) · [Navbar](https://docs.wirekit.app/components/navbar) · [Navigation Menu](https://docs.wirekit.app/components/navigation-menu) · [Notification Center](https://docs.wirekit.app/components/notification-center) · [Number Input](https://docs.wirekit.app/components/number-input) · [OTP Input](https://docs.wirekit.app/components/otp-input) · [Overflow Nav](https://docs.wirekit.app/components/overflow-nav) · [Page Header](https://docs.wirekit.app/components/page-header) · [Page Progress](https://docs.wirekit.app/components/page-progress) · [Pagination](https://docs.wirekit.app/components/pagination) · [Password Input](https://docs.wirekit.app/components/password-input) · [Phone](https://docs.wirekit.app/components/phone) · [Popover](https://docs.wirekit.app/components/popover) · [Price](https://docs.wirekit.app/components/price) · [Pricing Table](https://docs.wirekit.app/components/pricing-table) · [Product Card](https://docs.wirekit.app/components/product-card) · [Profile](https://docs.wirekit.app/components/profile) · [Progress](https://docs.wirekit.app/components/progress) · [Progress Radial](https://docs.wirekit.app/components/radial-progress) · [Prose](https://docs.wirekit.app/components/prose) · [QR Code](https://docs.wirekit.app/components/qr-code) · [Quick Replies](https://docs.wirekit.app/components/quick-replies) · [Radio](https://docs.wirekit.app/components/radio) · [Range Slider](https://docs.wirekit.app/components/range-slider) · [Rating](https://docs.wirekit.app/components/rating) · [Reaction](https://docs.wirekit.app/components/reaction) · [Reading](https://docs.wirekit.app/components/reading) · [Reorder](https://docs.wirekit.app/components/reorder) · [Replay Button](https://docs.wirekit.app/components/replay-button) · [Resizable](https://docs.wirekit.app/components/resizable) · [Reveal](https://docs.wirekit.app/components/reveal) · [Review](https://docs.wirekit.app/components/review) · [Review Summary](https://docs.wirekit.app/components/review-summary) · [Row](https://docs.wirekit.app/components/row) · [Scope Switcher](https://docs.wirekit.app/components/scope-switcher) · [Scroll Area](https://docs.wirekit.app/components/scroll-area) · [Scroll to Top](https://docs.wirekit.app/components/scroll-to-top) · [Section](https://docs.wirekit.app/components/section) · [Segmented Control](https://docs.wirekit.app/components/segmented-control) · [Select](https://docs.wirekit.app/components/select) · [Shell Bar](https://docs.wirekit.app/components/shell-bar) · [Shimmer](https://docs.wirekit.app/components/shimmer) · [Shortcuts](https://docs.wirekit.app/components/shortcuts) · [Sidebar](https://docs.wirekit.app/components/sidebar) · [Sign-in Button](https://docs.wirekit.app/components/sign-in-button) · [Skeleton](https://docs.wirekit.app/components/skeleton) · [Skip Link](https://docs.wirekit.app/components/skip-link) · [Slider](https://docs.wirekit.app/components/slider) · [Spacer](https://docs.wirekit.app/components/spacer) · [Sparkline](https://docs.wirekit.app/components/sparkline) · [Spine-Aware](https://docs.wirekit.app/components/spine-aware) · [Spinner](https://docs.wirekit.app/components/spinner) · [Stack](https://docs.wirekit.app/components/stack) · [Stage Card](https://docs.wirekit.app/components/stage-card) · [Stat](https://docs.wirekit.app/components/stat) · [Stats](https://docs.wirekit.app/components/stats) · [Status Dot](https://docs.wirekit.app/components/status-dot) · [Status Matrix](https://docs.wirekit.app/components/status-matrix) · [Status Tiles](https://docs.wirekit.app/components/status-tiles) · [Step Marker](https://docs.wirekit.app/components/step-marker) · [Stepper](https://docs.wirekit.app/components/stepper) · [Sticky Panel](https://docs.wirekit.app/components/sticky-panel) · [Stream](https://docs.wirekit.app/components/stream) · [Strength Meter](https://docs.wirekit.app/components/strength-meter) · [Structured Data](https://docs.wirekit.app/components/structured-data) · [Swap](https://docs.wirekit.app/components/swap) · [Swatch](https://docs.wirekit.app/components/swatch) · [Swatch Group](https://docs.wirekit.app/components/swatch-group) · [Table](https://docs.wirekit.app/components/table) · [Tabs](https://docs.wirekit.app/components/tabs) · [Tags Input](https://docs.wirekit.app/components/tags-input) · [Team Section](https://docs.wirekit.app/components/team-section) · [Testimonial](https://docs.wirekit.app/components/testimonial) · [Text](https://docs.wirekit.app/components/text) · [Textarea](https://docs.wirekit.app/components/textarea) · [Theme Controller](https://docs.wirekit.app/components/theme-controller) · [Ticker](https://docs.wirekit.app/components/ticker) · [Time Picker](https://docs.wirekit.app/components/time-picker) · [Timeline](https://docs.wirekit.app/components/timeline) · [Tire Label](https://docs.wirekit.app/components/tire-label) · [Toast](https://docs.wirekit.app/components/toast) · [Toggle](https://docs.wirekit.app/components/toggle) · [Toggle Button](https://docs.wirekit.app/components/toggle-button) · [Tool Call](https://docs.wirekit.app/components/tool-call) · [Toolbar](https://docs.wirekit.app/components/toolbar) · [Tooltip](https://docs.wirekit.app/components/tooltip) · [Tour](https://docs.wirekit.app/components/tour) · [Translatable Input](https://docs.wirekit.app/components/translatable-input) · [Tree View](https://docs.wirekit.app/components/tree-view) · [Unsaved Hint](https://docs.wirekit.app/components/unsaved-hint) · [Usage Meter](https://docs.wirekit.app/components/usage-meter) · [Video](https://docs.wirekit.app/components/video) · [Visually Hidden](https://docs.wirekit.app/components/visually-hidden) · [Wizard](https://docs.wirekit.app/components/wizard)