WireKit v2.70.0
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
ratioof an aspect ratio, an image and an image compare, theheightof a chart, a mixed chart, a sparkline and a map, themax-heightof a conversation, an editor and a scroll area, theoffset,max-heightandwidthof a sticky panel, thewidthandlist-max-heightof a scope switcher, thewidthof a dropdown panel and of the reading minimap, thesticky-header-maxof a table, thelogo-aspectof a brand and a testimonial and the brand'smobile-logo-aspect, theoverlayof a lightbox, theoffsetof an indicator, thedurationof a shimmer and theheat-fromandheat-toof a status matrix went into astyleattribute 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 ascalc(),min()orvar(). 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 for an image that names what it shows.
<x-wirekit::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 sendsimage-hotspots> wirekit:image-hotspots-selectwith 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 that places the points of an image with hotspots.
<x-wirekit::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 listimage-hotspots-editor> image-hotspotstakes asmarkers, bound withwire:modelorx-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 sendswirekit:image-hotspots-editor-select, so the page can show its own fields for that point. -
New video player for a video in the page.
<x-wirekit::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 sendsvideo> wirekit:video-consent, which a consent manager can take and answer withwirekit:consent, andconsentedstarts a player whose consent the page already holds. YouTube plays from its cookieless host and Vimeo without tracking.tracksadds captions, andbackgroundruns a file as a muted loop with a pause button, still underprefers-reduced-motionand Save-Data. A stream plays natively in Safari and through hls.js elsewhere, handed over withregister.Hls Engine() -
New image editor for a crop over an image.
<x-wirekit::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 asimage-editor> 9/16when one is given. The image stays as it is: the value is the crop, a rectangle in percent of the image, bound withwire:modelorx-model, andPushery\turns it into pixels for a resize and moves the markers of image hotspots into the crop.WireKit\ Support\ ImageCrop -
An accordion item and an FAQ question can start open.
openrenders 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 withopenstays open. -
Whether a collapsible, a sidebar section or an accordion item starts open can be set once, in the configuration.
components.,collapsible. open components.andsidebar. collapsible. open components.set the start of every box whose call does not say, and all three ship asaccordion. item. open 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 withopenstarts open. -
A 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 withwire:modeland submits with a form. A day picked without a time waits for one rather than becoming midnight;default-timegives it one, andwith-confirmationkeeps both until Select.interval,min-time,max-timeandtime-formatshape the list of times, and amax-timebefore themin-timelists the night. Withtime="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,maxandunavailableclose days, times and spans, a span such as22:00-06:00runs over midnight, and a date object among them closes a booked moment. The moment is written in the application's locale, or in the onelocalenames, 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 inlang, on the trigger and in the list of times. The calendar in the dialog takes the calendar's own options, thetriggerslot takes a button of the page's own, and the picker dispatcheswirekit:datetime-picker-open,wirekit:datetime-picker-closeandwirekit:datetime-picker-clear. Its dialog, and the dialogs of the date and the time picker withpopover, carry the theme markerdata-wk-picker-dialog. -
A datetime picker with
rangepicks 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 withtime="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 receivesname[start]andname[end], andwire:modelbinds the two ends as paths of an array or of aDateTimeRange.default-timetakes a time for each end,min-rangeandmax-rangelimit the days, andpresetslists ranges as on the calendar, a preset taking its whole days. -
A datetime picker 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. Withrangethe 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 asmin-rangeandmax-rangeallow. In a field too narrow for the whole moment the time goes on a line under the date. -
On a phone the datetime picker 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 and a time picker 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 withtime="input"takes the time typed in segments with the list as suggestions. The value, the field names andwire:modelstay the same, so switching it on changes nothing on the server, and withoutpopoverboth render as before. Withpopover,formatsets the time picker's clock, amaxbefore theminlists 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, and next to a<label for>of the page's own pointed at the picker'sid, 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. Withreadonlyboth show their value and open nothing, as the datetime picker does. A range shows a validation message filed under one of its ends,{name}.startor{name}.end, as it shows one filed under its name, here and on the datetime picker. -
A 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 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 inlang, 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 moves a year with Shift and Page Up or Page Down, as far as
minandmaxallow, 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 takes
min,maxandunavailable, and in range modemin-rangeandmax-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.minandmaxtake a day, a date and time, a date object,todayornow, each read as its day in the application's time zone, text that names no day is reported through strict validation, and a limit that a Livewire render changes reaches the grid without resetting it. -
A Livewire property typed with
DateRangebinds a calendar or a date picker withrange, and stays a range.Pushery\reads every value the two components take for a range, and a range a form is still filling in is one too:WireKit\ Values\ DateRange hasStart(),hasEnd()andisComplete()say which ends there are, and a missing end throws nothing. It is a period of Carbon, sowhereBetween()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 asperiod.startandperiod.end.DateTimeRangekeeps a time of day on each end, to the minute. -
A calendar and a date picker with
rangetakepresets, 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.presetsalone offers today, yesterday, this week, the last 7 days, this month, the year to date and, withmin, all time; a list of keys names others, from days, weeks, months, quarters and years back or ahead tocustom, 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 receivesname[preset], a date picker binds it as a third path beside the two ends, and aDateRangereturns it frompreset(), so a filter set to "Last 7 days" is still "Last 7 days" when it is read again tomorrow.DateRange::computes the days of a preset for today, and each preset is a static constructor as well,fromPreset() DateRange::. With presets, the grid's mark of today and the today button count from the application's day as the presets do.last7Days() -
A calendar takes a today button, a column of week numbers, six weeks in every month, the month it opens on and three sizes.
with-todayadds 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-numbersadds the ISO 8601 number of each week, counted on its Thursday, as the header of its row.fixed-weeksdraws six rows in every month, so a calendar keeps its height from month to month.open-tonames the month a calendar without a value opens on, as a day,YYYY-MMor a date object.sizedraws the days atsm,mdorlg.week-starts-ontakes any day from0to6, andlocalefor the first day of the application's locale, read from the locale data of PHP'sintlextension;nullinconfig/makes that the default for every calendar.wirekit. php -
An editor names the engine it opens in with
engine. An application with several schemas registers one factory per name inwindow., and a field withwirekitEditors engineopens in that factory and in no other, waiting for it when its script runs after awire:navigatevisit. 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 takeswindow.as before.wirekitEditor -
fitstands a table as wide as its columns, at most as wide as the space. Wider than that it behaves as withoutfit: 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 asw-fitorinline-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-fablifts 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 among them, without the buttons that stand on--wk-fab-liftthemselves:--wk-fab-lift: var(--wk-scroll-inset-below-fab, 0px)raises a floating action button and a scroll-to-top stacked over it while the bar stands.--wk-scroll-inset-bottomcounts 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 or modal with its primary control, from a field as well. An alert dialog presses the control inside
alert-dialog., a modal the control a page marks withconfirm 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, sowire:clickand a page's own listeners hear it as one. The overview of keyboard shortcuts lists it among the open dialog's shortcuts, and the control carries it inaria-keyshortcuts.confirm-shortcutturns it off for one dialog,components.andalert-dialog. confirm-shortcut components.in the configuration for every one.modal. confirm-shortcut -
A navigation menu item, an FAQ question, an accordion item and a 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-langand an option'slangwrite 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, an image gallery and a lightbox name the language of an alternative text and of a caption. Where either differs from the page's language,
alt-langandcaption-langwrite it on the image and on its caption alone; alangon the tag landed on the figure and reached both. A gallery takesaltLangandcaptionLangper 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 takes the
levelof its questions. Its questions stood on level 3 wherever it stood, so right under the page'sh1the outline missed a level, and under anh3they could not go to 4.level, 1 to 6, reaches every question asvariantandsizedo. -
The breadcrumb builder takes a list of steps.
Schema::took abreadcrumb List() name => urlmap, 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 theBreadcrumbListone 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 and an alert take a
levelfor their title. Both drew the title as a heading in adiv, 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. Withlevel, 1 to 6, the title is a heading of that level in the component's own size; without it, it stays thedivit was. -
A table column can give way to the table's width only from a window width up, and
table.stand-inshows what stands in for it.hide-below-container-fromontable.thandtable.tdsets the window width from whichhide-below-containerapplies, 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-inwith 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 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 ashortcutthe count stands before the key hint. -
A badge with
truncatestays 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. Withtruncateit stops at--size-wk-badge-max, the label ends in an ellipsis, and the whole label shows in a tooltip while it is cut. Withtooltipas well, one panel shows the whole label above the tooltip's text. -
A stat can be a toggle button that sets the filter it counts. With
pressed,trueorfalse, the whole tile is a<button type="button">witharia-pressedand 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 followsaria-pressedwherever it is set, so a binding of the page moves it as well.wire:click,wire:keyanddata-*reach the button, which is named by what the tile shows. -
A range of checkboxes picked with Shift held.
x-wk-range-selecton 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, sowire:modelon 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, each list picks in itself. A data table withselectablepicks a range by itself. -
A radio or checkbox card holds a description and a trailing part inside its frame. With
variant="card", thehintstands under the name as the option's description, and thetrailingslot 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 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 inconfig/.wirekit. php -
wirekit:themederives 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 takes the shortcut of another while it is on the page. With
takes-hotkey, a palette that shares itshotkeywith 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 for one of the others stops stating the key while it is taken, inaria-keyshortcutsand at its end. -
An action bar 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. Thesummaryslot 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 selects every match of a server list, not only its page. Around a table of the application's own,
bulk-selection.is the header checkbox, checked when every row of the page is and mixed when some are. Once the whole page is selected andtoggle totalsays 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 thatwire:modelbinds both ways. While it holds, the rows of each page the reader turns to are selected as they render, and a render with anotherfilterclears 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 for a setting of its record, is no row, so selecting or clearing the page leaves it as it is. -
A data table 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", andselection-changecarriesallMatches. Anothersearchorfilterclears 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 opens a page of values in the same palette.
opensnames acommand-palette., 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 itspage aria-keyshortcuts. A page withremotetakes its values from the application's search, as the top level does: the query event names the page inpage. Command Palette with Pages shows both kinds. -
The overview of keyboard shortcuts 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 newhotkey-area="page"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
kbddraws 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 (Strgin German), and a sequence such asg dwith "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 draws the shortcut its control binds withx-wk-shortcut, or the one its newshortcutprop names, after its text, and so does the tooltip of an app rail module. A single-key shortcut is drawn only while single keys work. Ashortcutthe grammar does not read is reported through strict validation, and thekbddraws its slot in its place. A shortcut that namesctrlbesidecmddraws ⌃ beside ⌘ on a Mac, in the overview as well, since it needs both keys there. -
An application's own number format, through
WireKit::. 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 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.format Numbers Using() -
A series of a chart names its own decimals.
decimalson a dataset takes the place ofvalueDecimalsfor 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 of returned units beside a return rate writes12and4,53on a German page, where one setting for the whole chart wrote12,00. A series without it keeps the chart'svalueDecimals. -
Amazon's button image in one file per pixel density. A sign-in button 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.
logoandwirekit.takesign_ in. logos. amazon ['1x' => …, '2x' => …], written assrcset, so the button stays sharp at the size Amazon gives it, and a2xfile 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 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,autothe 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., a link of the same site withoutconfirm wire:navigateasked in the browser's own words, which name nothing and stand in the browser's language. It now asks in the unsaved hint's dialog, as awire:navigatelink 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:unsavedonwindowsays whenever the page gains its first unsaved field or loses its last, andwirekit:unsaved-releasesent towindowstops 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 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
detailsaround 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:savedwithtrigger: truecounts 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 markeddata-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 countsvariants.3.skuand every other field under that path, for a save of several parts that says which went through, andwirekit:not-savedreads both the same way. See unsaved hint. -
A countdown can be stopped.
pausableputs 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.staticworks 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 firewirekit-countdown-expired, and the button ofpausablegoes with the clock, handing the focus to the next control after the countdown when it has it. A headless countdown readspausedand callstogglePause()for a control of its own, which leavespausedas it is past the deadline. -
Two taps on the quantity of a till line ask the application for a quantity. In a cart line with
stepper="buttons", two taps on the quantity between − and +, or a double click, dispatchwirekit:cart-quantitywith 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 takes buttons and a sentence under its heading.
card.headertakes anactionsslot for buttons at its end anddescriptionfor 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: thereactionsis reported and left out, and a heading that links gives the card its destination instead. -
wirekit:card-openedsays when a collapsible card 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 towirekit:card-openwhen 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 then shows no message and no invalid state and reads nothing from the shared$errorsbag, 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, afieldturns it off for the control inside it as well, and afield.setturns its group message off the same way while its controls still leave the group's entries alone. Without it nothing changes, anderror="false"written without the colon means the same. -
A drawer 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-belownames the breakpoint,smto2xl, 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 takes the names of its − and + buttons.
decreaseLabelandincreaseLabelname them where the label alone words them badly, and without them the buttons are named from the label as before. A cart line 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 can link to its product.
hrefmakes 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.nameLangsets the language of a name that is not in the page's, on the name alone. -
A link without an
hrefcan 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 anhrefthe link rendered an<a>without one, which looks like a link and takes neither focus nor a click. Withplain-without-hrefit renders a<span>instead, without the link's color, underline, pointer and focus ring, and keepssizeand the attributes it is given, except those only a link reads, such astarget,rel,wire:navigateandwire:current. With anhref, and without the prop, a link renders as before. -
An image compare can be disabled. It submits a position like a field and had no way to be locked.
disabledlocks 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 the slider is locked the same way and now looks it, and a press that still reaches the handle moves nothing. -
A field set 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 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 with
submit-oncelets 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 carryaria-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 aftersubmit-once-releasemilliseconds for an answer that leaves the page as it is, ten seconds unless the form names its own. A plain<form>asks the same withdata-wk-submit-once, and a submission another script has taken over, aswire:submitdoes, is left alone. -
A table 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'salign. 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-idwrites the text as a hidden description for the fields of the column to list in theiraria-describedby. -
A heading 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 dispatcheswirekit:field-helpwith the heading'sid, and classes given to the heading go on the row that holds both. -
A navbar takes a
menuslot 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 inactionstakeshidden md:flex, so each is rendered once. Underforce-mobilethe menu shows it at every width, and a bar withmobile="scroll", which has no menu, renders nothing of it. -
A file upload can send each file of a selection in a request of its own. With
multipleandwire: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. Addupload-separatelyand 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, andupload-separatelyin the config turns it on for every upload. -
A link to an accordion item or an FAQ question opens it. An item's
idstands on the item itself, so/help#shippinglands 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-namenames the quantity of a cart line 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. Withquantity-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-fieldnames the field the help of a field set explains. A click on the question mark beside the legend reports it asnamein its event, where the set's ownnameis not that field. -
A node of a tree view takes
value, andtree-node-selectcarries 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., which isdetail. value nullfor a node without one. -
A product card's stars take a note, the
ratingNoteslot 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 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 itssizeand at least as wide. An unavailable pill strikes its name through and reads "unavailable" with it, and acoloror animagegiven with a pill is a dot before the name. A swatch group takesshape="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 takes the values of an axis over its price. The
optionsslot 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 takes its style or its tiles from the config when it sets none.
components.is the style a MapLibre map loads,map. maplibre. style-url components.the tiles a Leaflet map draws, andmap. leaflet. style-url components.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 ownmap. leaflet. attribution style-urlkeeps it and shows only its ownattribution. All three default tonull: a MapLibre map then loads MapLibre's demo style, with its tiles and its fonts, fromdemotiles., which receives each visitor's IP address, and a Leaflet map draws no tiles, as before.maplibre. org -
A calendar takes
disabledandreadonly, as the date and datetime pickers do.disabledlocks every control and takes the calendar's fields out of the form.readonlylets the reader page through the months and move between the days, picks nothing, and still sends the value. Neither stops an empty submit withrequired. -
A card takes
intent, which draws its border in the color of an intent.info,success,warninganddangertake the border a callout draws for the same intent, in place of the border of the card's surface;neutraland no intent keep it. An intent the card does not know is reported. -
A row with
align-fieldsandwrapwraps its fields into lines, each lined up on its own controls. The fields take as many columns as fit atmin, 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 takes an
afterslot for what follows it in its cell, a button that adds a value under a select for example. In a row withalign-fieldsthe 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 item, checkbox item and radio item and the command palette's trigger take a
shortcutas a list of keys, such as['Ctrl', 'K'], as a menubar item and a command palette item do, and draws them with a space between them. A list ended the page before. -
wirekit:doctor:propsnames a list item written as a bare element. A<dt>or<dd>written straight into a data list, or an<li>straight into a 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. -
actionsontable.tdsays which cell of a stacked table holds the row's actions. Wherestack-belowlays the rows out as cards, that cell stands as the card's footer without a name. Unset, it is a cell withalign="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, andactionsmakes any cell the footer. -
stack-below-containerontablestacks 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 ofstack-below. The new prop takes the container scale a column'shide-below-containerreads,smto5xl, 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. -
tableon a chart 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, withvalue-decimals,value-prefixandvalue-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, andchart-mixedtakes the prop as well.
Changed
-
ApexCharts 8 is a supported version of the chart, and
wirekit:verifyno 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 runswirekit:verify --fail-on=warningno longer fails on the ApexCharts version when 8 is installed. -
A calendar marks today with a dot under its number instead of a ring, and draws the month and year selects of
selectable-headeras 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 with
close-on-confirmneeds a control that confirms, and strict validation says so. The option closed the dialog only throughalert-dialog., so a dialog whose action was a plain button stayed up after the action, withconfirm aria-modal, over a page it kept out of reach, and nothing said why. A control markeddata-wk-dialog-primaryconfirms 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-auditfails onJs::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 asJSON.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\writes every shape as a literal the evaluator reads, a number or a string as well as an array. The CLI reference lists the condition, and the examples for a toast flashed to the session and for the inbox blueprint use the attribute encoder.WireKit\ Support\ AlpinePayload:: from($value) }} -
The tooltip of an app rail 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 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
chevronclass block, so a personalization can restyle it, and the arrow takes its color from it. A rule an application sets on.wk-card-chevronstill reaches the arrow. -
A select reports
multipleand a list as its value. Withmultiplethe 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 for several values, and the attribute stays where it was, so a page that styled the list box keeps it. A list asvalue, whichold('country')gives after a request that sentcountry[], 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 item, a context menu or menubar entry, a command palette item, a sidebar or app rail entry or a floating action button, fails a console command or a test also without an icon package, as it does on an icon. A request still draws the page and logs the name.
-
The backdrop behind a 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-overlaynow defaults tooklch(0% 0 0 / 0.35)and/ 0.5in the dark theme; a theme that wants the old strength sets it back. The 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.andjs wirekit-alpine.bring their own Alpine, and 3.17.5 no longer appliescsp. js x-cloakagain 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
localesuch asPOSIX,C,xxorde_DE@euro, a calendar, a datetime picker and a 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, down to the application'sfallback_locale, and a locale they take stays as it was set. A component that formats in the browser was handeden-US.UTF-8underen_US.UTF-8, which the browser'sIntlrefuses, and now readsen-US. -
An
x-modelon 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,selectedon a combobox,passwordon a password input orvalueon a 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 with
popovershows a color an Alpine page writes into it. It kept showing the color it started with, or the last one picked in it, when anx-modelof the page changed the value. -
With
optimistic, anx-refon a textarea, select, checkbox, toggle or time picker reaches the$refsof the Alpine component around it. The field carried the component's ownx-reffirst, 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, a color picker and a 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 and the 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 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 asEURdoes, and strict validation reports the value. An emptycurrencyreads as none, so the default currency of the configuration counts instead ofXXX, the code for no currency, and a list given ascurrencyno longer answers with an error page. A product card, a pricing table, a cart list and a cart summary draw their amounts through it. -
A radial progress with an infinite
maxreads it as out of 100, as a progress bar does. The ring stood empty, and screen readers were told a maximum ofINFand0%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, a range slider, a number input, a cart line, a date picker's own field and the moments of a datetime picker took a
minabove theirmaxas 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 keeps a window across midnight, such as17:00to09:00, which HTML defines. -
A date picker without
popovertakestoday,nowand 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 noYYYY-MM-DD, so the field had no bound at all where the calendar of the same picker closed the days outside it. -
A rating, a strength meter, a skeleton with its text and table forms, and an OTP input draw at most a hundred stars, bars, lines, rows, columns or boxes. Each drew one per unit of its
max,lines,rows,colsorlength, 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 ownidtook the name as its id:aria-describedby="first name-hint"namedfirstandname-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 and picker. Each run of whitespace in an id now becomes a hyphen; the field'snamestays as given. -
A tab 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'saria-labelledbynamed…-tab-newandyork, ids no element carries, and a screen reader read the panel without a name; the tab'saria-controlssplit the same way. Anidgiven to the tabs with a space did the same for every tab. A row of the 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
falseis no image. Given one, an avatar, a brand, a product card, a 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 with no address draws nothing, an image gallery shows an entry's zoom in its place or leaves the entry out, an image compare reports a missing image through strict validation, and the attendees of an event calendar show their initials. -
A link address that is empty or white space is no link. A button, a text link, a 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, a 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 givenfalseis no link. -
A link address of
0is a link. A button, a text link, a card, a 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, and0is not: givenhref="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, a review, an event calendar, a message and a date separator drew 1 January 1970, and given the zero date0000-00-00that 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
minormaxsuch as2026-13-45or a word set no bound on a date picker and a time picker, without a report, and the time picker wrote it into its field as given. An event calendar's event with such astartstood on no day, and one with such anendlasted no time. Each is now reported through strict validation, 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 anend. An event whose start is no date,null,false, an empty text or the zero date, is left out without a report;nullandfalseput 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 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.2026or a Unix timestamp, reached the browser as written, where Chrome reads31.12.2026as 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 and an input with
type="time"wrote9:30into their field as given, and a field takes two digits for the hour, so the value stood empty andmin="9:00"bounded nothing. A time with seconds from atimecolumn, such as08:00:15given asminon 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 wherestepcounts them, as a date object already was, and adatetime-localfield takes2026-03-15 9:30as well. The list of a time picker withpopoverreads no time from the zero date0000-00-00 00:00:00, which names no date. -
A keyboard key with no key to show draws nothing. A
shortcutof 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 item with a blankshortcutdrew one in its row. A slot still stands in for a shortcut that names no key. -
The caption of a table 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 with a
localein 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 nolang, 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 inlangnow, 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 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 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 keeps its name and description through an update while it is open.
-
Every size an 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::, beside the sizes below ten, which went through both. A card could readformat Numbers Using() 2,4 MBthrough the application's format beside512 Band24 MBwithout it, and1022 KBstood 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 read8 / 10 GBfor 7.5 GB where the locale's way writes7.5 / 10 GB. It now keeps up to three decimals with no zeros at the end, as it does withintl. -
A file upload with
multipleandwire:modelholds on its property exactly the files its list shows. Livewire 4 adds every selection of amultiplefield 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. Withupload-separatelythe 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 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 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 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 and the brand of an 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 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 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
valuenow reaches the engine without a form field, and the form still submits nothing for either. -
A branch of a 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-expandedto the branch's state, which the update keeps. -
A tree view, a resizable split and a 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 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 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-controlsnamed 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 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. 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 in
detailbreaks 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. Insummarythe 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 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 stands in its columns. A
data-list.itemthere 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 ownlayoutkeeps it. -
The description of a 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 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 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 and the segmented control, and the top and bottom pair of the sticky panel, the scope switcher and the sidebar, mirrored right to left as before.
-
The first unsaved change of a status matrix, the first selected row of a data table and the empty state of a 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.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:empty role="none"keeps an application that announces the empty state itself from being heard twice. -
The reading time 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 in
renderedmode 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 sorted with
alpine-sortinside 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, the popover with a top or bottom placement, and with it the scope switcher, the color picker, the filter builder and the 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 still moves into the window over the point it opened at.
-
A data table 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, andall-matchesfor 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 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, a multi-select or a dropdown placed
leftorright, a tour step beside its target and the submenus of the dropdown, the menubar and the 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, the menubar and the 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, 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
placementit cannot place. A tooltip, a popover, a hover card, a dropdown, a tour step and the submenus took any word, and one outside the twelve placements, such asbotom, 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 and the multi-select already did. -
A prop that takes one of a few values reports any other. The
sizeof a combobox, a checkbox, a date picker and twelve more form controls, thepositionof a toast region and a scroll-to-top button, thevariantof an accordion, a navbar and a sidebar, theorientationof a stepper, and fifty-three more props took any word and rendered their default for one they did not know, while an 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 cut the line without its tooltip, astruedoes. Each now goes through strict validation as every prop with a fixed set of values does: with debug on, a Pest test or anartisancommand throws on an unknown value, and a request logs it and renders what it rendered before. A boundnullor an empty string is still the default, without a word. A prop whose default is none, such as an avatar'sstatus, stays none for an unknown value rather than taking the first of the list. A stats grid given itscolsas a number,:cols="3", now lays out three columns, where it fit its stats to the width before. A chart whose stream mode was another word thanstrictorstreamlet a streamed series grow without a bound; the word is reported and the series is capped, asstrictdoes. -
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
delayShowofsoonon a tooltip, amaxTagsoftenon a tags input, aweekStartsOnofmondayon a calendar, amaxof1OOor astepof0,5, while a prop with a fixed set of values reported an unknown one. Each now goes through strict validation: with debug on, a Pest test or anartisancommand 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 thesearchDebounceof a 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 theminValueandmaxValueof a 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 itsarraycast. A select, a combobox, tabs, a 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: with debug on, a Pest test or anartisancommand 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's author, the comma-separated value of a multi-select or a tags input, and a single country written as text on a phone field. The arguments of a chart keep the types its class declares: a text in itslabels,datasetsoroptionsstill 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, ahint, atitleor 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.returns a list when the key names a group of lines rather than one. Each now goes through strict validation: with debug on, a Pest test or anaddress') artisancommand throws, and a request logs it and renders the component without the prop. An object that writes itself as text, such as anHtmlStringor a date, is read as before, and so is a list given to the author of a message or to the badge label of an app rail item. -
A label given as markup, an
HtmlString, names its element by its text. Written intoaria-label,placeholder,titleoraria-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, a menubar, an alert dialog or a drawer places at the end of the page and the search field of a 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: thealtof an avatar or a flag, thebefore-altandafter-altof an image compare, thenameof an assistant message, a profile, an attachment or an item of a cart list, thefilenameof a code block, thetriggerof a navigation menu item or a collapsible, thequestionof an unsaved hint, and thetooltipthat names a 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 and of the date, time and date and time pickers, the end field of a date range, the name of a stat with anintent, the remove button of a dismissible badge, and the placeholder of a 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's
helpgiven as markup shows the markup in its tooltip, not its tags. AnHtmlStringas the help of any field showed its tags as text in the tooltip, and so did one as the heading of shortcuts. The placeholder of a date and time picker, the name of the menu of an overflow nav, the words of a sign-in button and the name a 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::sharesaw it as the heading of every alert and empty state written without one, and a value shared under the name of another prop, such aslabel,sizeorhref, 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, and a text shared asmetaended the page of every 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 atitleinto every view replaced the title of every alert and 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 theregister()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 took the
sizeand the headinglevelof a card around it, the items of a navbar inside a compact toolbar were compact, and a table inside a page header written withstack-belowstacked 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 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-headerandsticky-columnfrom 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 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 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 sorted with
alpine-sortmoves 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 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
langordirnames the same language and direction. A menu, a popover or a dialog in a section withlang="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 withdir="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 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 and the menu of a menubar, and a 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 or a 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, Escape closes that menu and leaves the card, which closes on the next one.
-
The arrow keys of 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 given something other than a paginator says so. A number,
trueor a list ended the page with a type error that named neither the component nor the prop, and a collection, asall()returns wherepaginate()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
surfaceof a badge, a button or a card, thevariantof a card or an empty state, theintent,toneorsizeof a feature, thelayoutorasideWidthof a hero, thesizeof an icon, thekindof an activity row, thepresetof a reveal, theintentof a spinner or thevalueof a rating, a number such as1e21ended 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: theprogressof an uploading attachment, thesearchDebounceof a data table or a filter builder with a search field, themaxof the deprecatedprogress.circle, thesizeandmarginof a QR code, thedetailsColspanof a table row, thestepof a time picker withpopover, themonthsof a date picker withpopover, and themaxlengthof an input or a textarea withcounter. Below PHP 8.5 the number turned into an unrelated one there, such as a search field waiting8446744073709551616msfor-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 draws the layout for the months it shows. Given a
monthsthat holds no whole number,1e21or1.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 and a datetime picker hand their calendar that number. -
An
idwith a space keeps the references built on it. Given one, such as an id written from a row's name, an inline edit named it in its label'sforwhile 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's caption and the panels of a 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
setTimeoutandsetIntervalas a 32-bit integer and run a timer whose delay does not fit at once. Given such a number,PHP_INT_MAXamong them, thedurationof a toast region, thedelayShowanddelayHideof a tooltip or a hover card, theintervalof a carousel, thedurationof a clipboard button, theshowAfterof a page progress, thesimulateSpeedof a stream, thesearchDebounceof a combobox, a multi-select, a data table or a filter builder, thesubmitof a form and theOnce Release saveTimeoutof an 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 anintervalof zero or below turns at its default instead of as fast as the browser lets it. -
An 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
blockorhiddenclass on the tag never reached it. -
A radio item of a 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 asfilters.sortbinds 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, an event calendar, a message, a review and a date separator read
2026-02-30as 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, a date picker, a datetime picker and a time picker report a prop written wrong that they dropped without a word. An
openTothat names no day or month (no day or moment on a datetime picker), aminRangeormaxRangethat holds no number, adefaultTimethat names no time and aformatother than12hor24hare reported through strict validation now, asmin,maxandminTimeare. In a request each still draws as if it were left out. -
An OTP input with parentheses, brackets, braces, a slash or a bar in its
alphabetkeeps its pattern. Browsers compile a field'spatternwith thevflag, 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, a hover card and a context menu without their
triggerslot, and an image compare without its images, ended the page with an undefined variable; each names the slot or the props it needs now. An 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
dismissibleof a modal readtrue,false,on,off,yes,no,1and0, and any other text as on without a word, sodismissible="flase"left the dialog dismissible. Each switch now goes through strict validation: with debug on, a Pest test or anartisancommand 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. Thewrapof a row reports a word other thanresponsive, as the other props that take a switch or one word do. -
An entry of status tiles without an
intentdraws 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 with
rangesends{name}[start]and{name}[end], and a rule on one end files its message as{name}.startor{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 carriesaria-invalid, as it does for a message filed under its name. A range slider does the same for a rule on one handle,{name}.minor{name}.max. -
A form control without a
nameis no longer sent under a name WireKit made up. An input, a toggle, a select, a tags input, a multi-select and twelve more took theiridas their name, the last two with[]after it, and without anidfrom the page that was one WireKit counted out: an unnamed search field in a GET form putinput-1=…into the address. Such a control now sends nothing, as the input page said it did. Anidthe page gives still names the field, and the radios of a single-choice swatch group keep a shared name, which is what makes them one choice. An OTP input without anamestill writes its code to the fieldwire:modelbinds. -
A
readonlyon a toggle, a checkbox, a radio, a slider or a color picker is reported while debugging. HTML ignoresreadonlyon 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, andStrictnessGate::gives a test the same answer.control Attributes Without AControl() -
A color picker with
popoverhandsautofocusto 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 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
requiredand 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 theeditorslot. -
What acts on a field reaches it on three more components. A
min,maxorstepon an 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. Asteporliston a date picker withrangereaches both dates, as it reaches a single date. Apatternon a translatable input reaches every language's one-line field, asmaxlengthalready did. -
A
disabledorautofocuswritten as"false"turns nothing on. HTML reads both by their presence, sodisabled="false"on a field set disabled every field in it, on a copy button, the close button of a modal or a drawer and seven more it disabled the button, andautofocus="false"focused a button, a tab 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-describedbyon a 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
tabindexon a file upload, a multi-select, a tags input, a one-time code or a translatable input reaches its fields. It landed on the element around them, sotabindex="-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:focusandwire:bluron a form component made of several parts run as the reader leaves or enters the control. 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 thebluralready and now fire thefocusas well. -
A color typed into a color picker 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:
#B87334arrived as#b87333. The color now stands as it was read until the reader moves the plane or the hue slider. -
A filter builder panel, a dropdown or any element with
x-showand a transition, opened again while it closes, reports no unhandled rejection. 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 bound with
wire:model.livekeeps 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, a color picker, a date picker range, an image comparison, a number input, a phone field, a slider, a range slider, a tags input, an editable status matrix, a toggle button and a branch switcher bound with
wire:model.livekeep 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 bound with
wire:model.livekeeps a second step taken while the first is on its way. Each move firedinputon 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. Nowinputfires only on an end that moved, and on an end whose thumb does not show the stored value: both ends of a slider withoutmin-valueandmax-value, whose first move replaces the stored range, and an end the scale held inside it. -
The tooltip of a cut text 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 ownlang, 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
nullleaves a component's own name, role and id in place, and so does a name, a description or a live region bound tofalse. 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 lost "Main navigation", the dialog of a modal its name, a combobox its role, a phone fieldautocomplete="tel"and a data table its id, and a number input marked its steppers disabled for anulldisabled. 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, a button that shows a symbol only, lost "Dark mode", a bottom navigation "Main" and a rating "Rating", and a cart summary wrote an empty heading. An emptylabel,aria-labelorplaceholdernow 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's add button, which had left the button without a name, and anaria-label,aria-labelledbyoraria-describedbygiven as an empty text counts as not written, in every component, so the dialog of a modal with a header is named by its header. -
A 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 takesas="div". -
A ticker's delta and the number of reviews on a 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 %and1.234 Bewertungenin 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 abadgeslot that holds nothing, or only the markers Livewire writes around a condition, drew an empty pill on a dropdown item, a sidebar item, an app rail item, a bottom nav item, a tab, an indicator, a product card and an activity row. They draw nothing now, and0stays a count. The name of a bottom nav entry reads its count as the pill shows it,1,234rather than1234. -
A count in the badge of a tab given through
itemsis grouped as the page writes numbers. A tab of its own wrote1,234, and one fromitemswrote1234; both write1,234in English and1.234in German now. -
Page Up and Page Down in a calendar 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 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
remainingholds 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'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'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 takesas="span"for that place, rendering as a block with its caption as a line of its own, and the gallery uses it. The collapsible page's slot example no longer puts a<div>and a<p>in its button. -
A text prop given
falseor an empty string reads as none. A condition at the call site such as:help="$isNew && __('Optional')"writesfalsewhen it fails, and a review drew an empty heading, the label of a form field a help button with nothing to say, a sticky panel a landmark with an empty name, a field set and a sidebar group0as their legend and name, and a 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, asnulldoes;0stays 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 with an empty label keeps its name. An emptyplaceholderstill means no placeholder, as it does in HTML. -
A word a component writes for itself, given
falseor an empty string, gives way to its own. Givenfalse, a badge'sdismissLabelleft its dismiss button without a name, a radial progress'svalueTextwrote an emptyaria-valuetext, a pricing table named its interval switch with nothing, and thebeforeLabelandafterLabelof an image compare, a notification center and theaddLabelof a filter builder drew empty labels, links and buttons. An empty string reads as none in the same way: a tier of a pricing table with an emptypriceLabelno longer loses its price, and a data table with an emptyemptyTextsays its own sentence when nothing matches. -
An alert dialog without a description no longer points
aria-describedbyat nothing. The reference went out wheneverdescribedbywas not set, and onlyalert-dialog.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 unlessdescription describedby="false"was written. Unset, the dialog now points at its description when it holds one;falseandtruework as before. -
A price in another language than the page marks its amounts with
lang. With alocalewhose language is not the page's, the amount, the struck price, the delta and the unit price carry it, so a screen reader reads1.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, a cart line, a cart summary and a tier of a pricing table show their prices this way, and an emptylocalereads 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 out and keeps the page, and a console or a test still fails on it. A dropdown item and submenu, a sidebar item and collapsible group, an app rail item, a menubar submenu, a context menu item and submenu, a command palette item and its search field and a floating action button 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, a highlight, a hover card on a name, a status dot, a flag, a swatch, the label of a form field, a 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, a heading and a 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 or a 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 does, and so do the layer of an optimistic toggle button and the wrapper of a scroll to top button that the page shows and hides.
-
A field set 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 namedemails, 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 asemails.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 named the way a form names its controls shows its message once. Laravel files the error of
address[country]underaddress.country, and a set namedaddress[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>. Afield.setnow reads its name in the spelling of the bag, as every control does, soaddress[country],roles[]andaddress.countryeach 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, a kanban column and a command palette showed an empty bar with its border and padding, a footer a rule above an empty row, a callout a margin over nothing, and a select or a combobox with no options turned itself off and showed an empty message for anemptyslot 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 shows its default slot when itsoffslot holds nothing. The same holds where such a slot stands in for another part: a tooltip whosecontentslot holds nothing shows itstextrather than an empty panel, so the control it sits on keeps its description, a product card keeps itsimagebeside an emptymediaslot, and a sidebar with a header and an empty footer, or the reverse, draws no empty band. -
A call to action, a hero, a timeline item, a tour step and a 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, anddescription,eyebrowandtaglinewritten 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-labelon a 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. Anaria-labelledbygoes the same way. -
The help of a 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-labelgiven to a skeleton, the editor's toolbar, a tab list or a button group names it. These wrote a name of their own, "Loading", "Editor commands" or the one theirlabelgave, 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 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
disabledand 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'sdisabledandreadonlyand every fieldset around it. -
A date picker with
rangehandsform,readonly,autocompleteandautofocusto 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, andautofocusgoes to the start date. -
wirekit:doctor:a11ychecks an icon-only button whose attributes hold a>. A value such as:attributes="new Componentended the button's tag for the scan at the arrow, so a button with only an icon and noAttribute Bag(['row' => $id])" aria-labelwent unreported. A button group is no longer read as a button either. -
A swatch in the label of a 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 stands alone where its picture does not load. Given with an
image, thecolorlies 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 page say where the color goes. -
A y-axis label formatter a page sets for every chart through
window.Apexstays 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-areatraces a container variant that follows another variant. A class such asxl:@max-5xl/was listed as compiled CSS that no source emits, because only a class that opened with thewk-table:hidden @was read as a container variant. -
wirekit:class-by-areareads 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 beforewirekit:publish-fontsin the same Composer run and renders no page. It also said the text fell back to system fonts, which the package route prevents: fonts serves such a family through PHP. The line is written now when a page renders<x-wirekit::, once per family and hour, in the words of the comment it writes into the page: the family is served through PHP, andfonts /> php artisan wirekit:publish-fontsmakes 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 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 builds a narrower stylesheet in a Laravel application. Tailwind reads the whole folder around a
@sourcethat lies in a directory git ignores, andvendor/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/, so the lines already declared narrow the build as they are.tailwind/ card. txt wirekit:doctornow 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 block keeps its padding with one Tailwind source per component. It takes its inline padding from
WireKit::, which builds the class in PHP, and the source ofspinePadding() spine-awarecarried 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, andphp artisan wirekit:doctornamesspine-aware.txtfor a view that calls the helper while no declared source carries its classes. -
A navigation menu in a navbar names its landmark apart from the bar's. Both named their landmark
Main navigationwhen 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 nameMain 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 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 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 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 waits while single-key shortcuts are off. A palette on
/opened through the reader's switch in the overview of keyboard shortcuts and throughdata-wk-single-keys="off"on a screen, which every other single key obeys (WCAG 2.1.4). A hotkey withcmd,ctrloraltis not a single key and keeps working. -
Charts group the thousands of their values. An ApexCharts chart wrote
278984,46in its tooltip, in the cells of a treemap and on its y-axis, beside a page that wrote278.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 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's press stepper take the touch size as their own. With
stepper="buttons", − and + drew a 44px hit area around their square. Atsize="sm"it reached into the quantity between them, and in the compact layout atsize="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 defaultsize="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-clearancekeeps the end of a long page clear of a button back to the top over the floating action button. The room it reserves counted the floating action button alone, so at the end of a long page on a phone the button back to the top withabove-fabcovered 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-liftas well. -
A field bound with
wire:model.blurorwire:model.counts as unsaved. The unsaved hint 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 withchange .liveor.lazy. Without.live,.blurand.changedecide 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.
-
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 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-unsavedinside 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 stayed hidden, and.confirmdid 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 dodata-wk-unsaved-off, awire:submitof a form in a dialog and awirekit:savedwithtrigger. -
The button that takes a chip out is a 24px target. The remove button of a pill in a multi-select, of a tag in a tags input and of a chip in a 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 of type
searchwithoutclearable, the cross the browser draws is a control, and the pointer now says so over it. -
The close button of a dismissible badge 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 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.settakes the same asas-field, for any set that stands for one field. -
A translatable input without
localeshas 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
localesit 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.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, andenter autocomplete="off"ormaxlengthdid nothing there. Aformthat 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.hintsgives 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 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 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 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-touchthe button in its head is 44px tall, as the triggers of accordions and collapsibles are. -
On a phone, checkboxes and radios 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, 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-touchthe label is a 44px row, as before. -
The box of a checkbox and the circle of a 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 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 with
variant="select"draws the chevron of the 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
erroron a form field reads the$errorsbag as if noerrorwere given. With an entry in the bag, a field givenerror=""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 bound with
wire:modeland nonameshows its validation error. Every field read the$errorsbag under itsnamealone, so after a failed$this->validate()a field bound only withwire:modelshowed no message and no invalid state. Livewire files the message under the bound property, and a field without anamenow reads it there:wire:model="form.underemail" form.email, with any modifier. Anamestill wins, and a checkbox bound to the key of itsfield.setleaves the message to the group. -
A field around a form control that shows the same error no longer repeats it. With
nameon 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 describes the form control inside it. The field rendered its hint below the control, and nothing pointed
aria-describedbyat 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}-hintalready, the field's takes{name}-field-hint, and a field without anamenames its hint after the control. Markup of the application's own still references{name}-hintby hand. -
The label of a field names every form control inside it. A segmented control or a swatch group in a field had no accessible name at all, and an interactive rating or a one-time code 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 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 aslandmark-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 follow, since they are accordion items. -
A required one-time code, range slider or tags input says so where the reader lands. Each wrote
aria-requiredon the group around its parts, where ARIA does not allow it and axe reports a criticalaria-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
requiredof a field reaches the form control inside it. The field marks its label with an asterisk that is hidden from assistive technology, and withrequiredon 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 carriesaria-required="true". It never takes the native attribute from the field, so the browser checks an empty field only when the control is givenrequireditself, as before. -
The
helpof a field 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 anamenames it after the control. -
readonlymakes a one-time code, a tags input, a multi-select and an 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. Anautocompletewritten on an inline edit now reaches its field as well. -
A disabled group locks a combobox and an open 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 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
requiredof the field set. -
A keyboard shortcut 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 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 checkbox or switch that cannot reach its Livewire component shows the value it holds. Outside a Livewire component, or with a
bindthat 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
optimisticexplains the prop and names the file it needs. In every component that takesoptimistic, the comment that explains it stood aboveoptimisticArgs, so the reference the MCP server answersget_componentwith gave its text tooptimisticArgsand none tooptimistic. Each prop carries its own text now, and the one ofoptimisticsays that the page loadswirekit-optimistic.beside its bundle, without which no control calls its method.js -
Names and labels built from a slot or a markup label read as written,
Tom's & Jerryincluded. A tooltip with acontentslot named its trigger, a table that stacks its rows named its columns, a command palette item titled its line and an 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, metTom's & Jerry. The same reached the buttons that an input, a combobox, a password input and a kanban column name after a label given as anHtmlString, and the parts a field with such a label names. The first count of a textarea counter counted the references, 28 for 16 characters, until the page's scripts started, and a floating action button 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 sentemail[], and a rule such asstringsends the reader back to the form with it. An input, a password input, a number input, a one-time code input, a phone field, a combobox, a segmented control, a date picker, a time picker, a color picker, an inline edit, a radio, a checkbox and a toggle threw a PHP error on it, and so did a multi-select, a tags input and a 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 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, "0.3" in a slider's bubble and "0.5" under its mark, "12.5 / 100" beside a progress bar and "3 / 12500" under a 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 reads2026. A count is grouped as the pagination groups one,12.500in German and12,500in English: the readout of a progress bar, the character counter, and the badge of a sidebar item, an app rail module, a dropdown item, a tab, a bottom navigation item, an indicator, an activity row and a product card, the counts of a kanban column, a stage card and a reaction, an optimistic one included, and the count of new messages on the jump-to-latest button of a conversation. A badge that is no plain whole number, such as99+,Newor007, 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 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]andname[country]; with the script it sends E.164 alone, as before, and awire:modelstill binds that value only.DialingCodes::reads either shape and returns E.164, so one line in front of the validation covers both, see Without JavaScript.fromField() -
A form sent from a page that runs no script keeps the selection of a multi-select and the tags of a 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 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, andimplode('', (array) $request->input('code'))reads the code from either shape; with the script the form sends the code alone, as before, see Form Submission. -
A form with a required combobox, multi-select, tags input, OTP input, rating, calendar or editor can be sent from a page that runs no script. These controls check
requiredthrough 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 checksrequiredeither way, and with the script an empty field stops the submit as before. -
A combobox 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-inputthe 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 withfree-inputthe value, from the first render. -
A label of a bottom nav and the name of a message'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, a password input and a 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 list stand on an element that may carry them. Each group took the
grouprole on a list item, which ARIA in HTML does not allow, so an accessibility check reportedaria-allowed-rolefor every combobox with grouped options and for every combobox withserver, 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 took the first character of the first two words, so "Ada Byron Lovelace" read "AB" there and "AL" in a 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 and a 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 already did, and the calendar reads the same rule in the browser. For those names the color an avatar derives from the initials changes with them.
-
An 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:clickon a component that listens to clicks itself runs beside the component's own. On a context menu item, a menubar item, a dropdown trigger, the close control of a modal, the trigger and the close control of a drawer, the confirm and cancel controls of an alert dialog, the trigger of a command palette or of the keyboard shortcuts overview and the toggle of a sidebar, a listener written withx-on:clickstood 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 forx-on:keydownon a dropdown panel,x-on:mouseenterandx-on:mouseleaveon a navigation menu item, the pointer, key and focus listeners of a resizable handle, andx-on:click.on an item of an interactive bottom navigation. Both run now, the component's first.prevent -
A usage meter and a radial progress write a percentage as the page's language does. A German page read
(13%)beside a usage meter's figures and heard13%from a radial progress, where WireKit writes13 %elsewhere, as for the change of a price. The deprecated 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-CAoren-GBevery count read in its first form, "3 Stern" for a rating's third star or "von 57 Treffer" in a 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 underde_AT. 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 describes the fallback.
-
A Portuguese count that reaches zero in the browser reads as the server writes it. A countdown, a scope switcher's result count or a 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'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'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 that corrected a value on leaving the field said "Auf 2.5 gesetzt" on a German page, and the selection of a 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. 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, a multi-select, a data table and a scope switcher folds accents away so
munchenfindsMü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 renders a date that names its offset. An ISO 8601 date with an offset or with
Z, the formtoISOString()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 renders a
timestampthat is a plain PHP date. ADateTimeor aDatestopped 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.Time Immutable -
A Unix timestamp is written in the application's time zone. Handed to a message, a countdown, a review or an 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 axis that steps in tenths or fifths read
-0, or-0,0in 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 just below zero did, colored as a price drop. Such a value reads0now, and one that rounds away from zero keeps its minus. -
A 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 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.comes back from the browser exactly. The selection of a data table, a click on an event calendar's event or a map's marker and the events of a 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.MAX_ SAFE_ INTEGER -
A backed enum is a value, as a model attribute cast to one hands it over. A select, a radio, a checkbox, an input, an inline edit, a multi-select and the
defaultof tabs stopped the page with an error when an enum such as$post->statuswas 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 with
type="date"ortype="time"wrote a date object, such as an attribute with adatecast orold('due', $task->due_on), as2026-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 as2026-03-15 14:30:00from 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 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 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 wherestepcounts them now. -
An event calendar puts a day from a model on that day. A day marker whose
datecame from adatecast stood on the day before in every time zone east of UTC, so ablockedholiday 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 PHPDateTimemarker 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 labels a date on its date axis as the time it names. A day from a
datecast stood on the day before on ApexCharts' axis, which is labeled in UTC, in every application east of UTC, and a plain PHPDateTimewas 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 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 PHPDateTimeas[object Object]. It shows as PHP prints it now, in its own time zone, and sorts as the dates do. -
A saved filter on a date field shows its day. A rule whose value was a date object read
Created after 2026-12-24T23:00:00.000000Zon its chip, the day before for a date of an application east of UTC, or[object Object]for a plain PHPDateTime, and the date field stayed empty when the rule was edited. The value of a rule on adatefield is written as the day it names now. -
A number that is not finite no longer ends the page. A chart, a sparkline or a data table whose data held
INForNAN, as a rate divided withfdiv()by a base of zero gives, stopped the page withInf and NaN cannot be JSON encoded. Such a number is written asnullnow, as JavaScript's ownJSON.writes it: a chart draws a gap, a cell shows nothing. An editor given its document as an array writes one asstringify() nullas well, as the browser writes it when the document is saved, where the render failed before. -
A 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,
INForNANshowed no arguments block at all, without a word. The byte shows as U+FFFD now and the number asnull, beside the other arguments, and arguments JSON cannot hold at all are named in the log in debug mode. -
A numeric prop that holds
NANorINFno 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, soNANandINFtake the default a text takes. That holds for the numeric props that default to nothing as well, such as thesecondsof a tool call, theindexof a wizard step or adategiven as a timestamp, and for theoffsetof a popover. A 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'ssuccess, a tool call'sname, a kbd'sshortcutand other text props left it out, an editor wrote such a document into its field as a JSON string, which the next save kept, and an activity row'skindended the page. Every component reads a fluent string as its text now. AnHtmlStringstays markup: asuccessmessage given as one is written as markup, ashintis, a map'sattributionreaches Leaflet as the HTML it holds, and where a prop is text for a script or for a name, such as a countdown'sexpired-text, it is read as its text rather than written as[object Object]. -
A grid or a feature grid with a
colsvalue it does not know falls back to one column in production. Outside debug mode a value such as13or a typo ended the page with aTypeError, where an unknown value is meant to be logged and replaced by the fallback, and the fallback then came out as a bare class1rather thangrid-cols-1. -
A Collection handed to a control that holds one value is reported, as an array is. A combobox, a select or a 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 still reads a Collection as its list. -
A display in a component's
classtakes the place of the component's own.class="hidden md:inline-flex"left a button on a phone's screen,class="hidden"left a badge there, andclass="block"kept a stack a flex column: Tailwind writes the display utilities in the order of their names, so a component's owninline-flexcame afterhiddenand won, as its ownflexdid afterblock. 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 inclass="md:hidden", leaves the component's own in place. See Customization. -
A position in a component's
classtakes the place of the component's own.class="absolute top-2 right-2"left a tooltip around a copy button in the flow, and a dropdown or an avatar placed that way stayed where it stood, whileabsoluteleft a button back to the top fixed to the window: Tailwind writes the position utilities in the order of their names, soabsoluteandfixedcame before a component's ownrelativeand lost, andabsolutebefore its ownfixed. A position written without a breakpoint in front now replaces the component's own. See Customization. -
A display or a position in a component's
classreaches a component that writes its layout inline. A header, a data list and its items, a mixed chart, an inline sparkline, a page progress bar and a reading progress bar write their display or position intostyle, 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, andclass="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. -
A flat card, a transparent navbar and the create action of a scope switcher keep their own color over a personalized block 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, andbg-white/80won 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 header given a font size or weight inclassrecognizestext-[1.25rem]/7,text-[clamp(…)]andfont-(--weight)too, andpbs-*andpbe-*count as padding where a component takes a padding out. -
A name given to a control reaches the control.
aria-labeloraria-labelledbyon the confirm or cancel control of an alert dialog, a theme controller, the collapse toggle of a sidebar, a menubar menu, a navigation menu item with a flyout or a 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 named with
aria-labeloraria-labelledbyis a landmark. The name stood on an element without a role, where it names nothing; it now makes the region the named landmark thatlabelmakes it. -
An
aria-labelledbyoraria-describedbyon a drawer or an alert dialog names and describes the dialog. Both took onlyaria-labelto 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 wrote itsdescribedbyand 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 and a command palette trigger, do the same witharia-describedby. -
Five tab stops draw the kit's focus ring. The control a modal or drawer close renders when its slot holds no control of its own, a replay button, the create action of a scope switcher and the search field of a command palette drew the browser's own ring or none, which follows neither
--ring-wk-widthnor--color-wk-ring. They draw the kit's ring now, and a 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 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 showed the children of a collapsed node until the script folded them and moved the page. Both start hidden now.
-
A
wire:keygiven 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 awire:keyon 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-showandwire:showhid that inner element and left the outer one in the layout, where anx-showorwire:showon 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-showorwire:showgiven to it goes on an element around both. -
A modal with a long body scrolls the body alone. A visually hidden text below the body's fold, such as the "Loading" of a spinner or the hidden input of a 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, the list of a notification center, a conversation, a 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.
-
An event that names a component by a number reaches it. A modal, drawer or alert dialog, a collapsible card, an inline edit, a stream, a card stack, a lightbox and a 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 asavedevent 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, one sidebar or one file upload among several. -
A tab 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 asdefaultoractive, 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, andwirekit:tab-changedreports the key as text after a click as well. -
A segmented control keyed by numbers marks its chosen segment before the script runs. With keys such as
1,7and30and the value written as an attribute, no segment was checked or the group's tab stop until the script ran, and anautofocusfocused nothing. The markup compares keys and value as text now, as the script does. -
A tab or a card stack part named with a hyphen shows its slot, and a name never stands in for a prop. A key such as
api-keysdrew 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 inorder. A tab keyed like a prop of the tabs or a variable of their own showed that value instead of nothing,labelthe tablist's name, and the keytabwas an error page. A slot named like a prop took the prop's place: tabs keyedactiveandarchivedselected no tab, a tab keyeditemsleft the tablist empty, and a part namedorderdropped 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 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 around a small form, its
@csrftoken in front of the button, gave its description to the token, and the button had none. In a hover card or a navigation menu panel that starts with a form, theTabkey from the trigger stopped on the token, andTabat either end of the panel left it for an unrelated place. An 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 keeps its value.
readonlystopped 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 saysaria-readonly="true". -
A floating action button 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, witharia-expandedand noaria-haspopup. A singlefab.buttonwithhrefis a link that navigates, and it no longer announces a dialog unlesshaspopupnames one; a button withouthrefstill announces a dialog by default. Ahaspopupoutside 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, a collapsible card, an accordion item and a folding sidebar section, the selected tab, the view of an event calendar, the density of a data table, the switches of a status matrix, the buttons of the editor toolbar, the theme controller, the menus of a menubar and a navigation menu, the submenus of a dropdown and a context menu, and the triggers of a floating action button, a navbar menu, a notification center, a filter builder and a color picker were written only by the script, so the markup carried no
aria-expanded,aria-pressed,aria-checkedoraria-selecteduntil it ran, and none where it never did. A reading progress bar had noaria-valuenoweither. 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
errorgiven 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 reads the$errorsbag under its name, or turns its error off withfalse, as the other controls do. See Error State. -
A week start outside 0 to 6 is read as a day of the week. A negative
week-starts-onon a calendar answered the page with an error, and a number above six shifted the grid of the calendar and of the event calendar once the script ran. Any whole number now counts around the week, so-5starts on Tuesday and7on Sunday. -
A
placeholderor alistwritten on an 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 wheremaxlengthandautocompletealready 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::with a status cast to an enum was an error page, and so was an enum in any prop that takes text,badge :intent="$order->status"> scopeincluded, on nearly every component. Inside a list it was the same: an option'svalueor a whole list fromStatus::cases()in a combobox, a multi-select or the quick replies, and a tab'skeyin tabs, ended the page, and a swatch group left out a swatch whosevaluewas 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. -
A tooltip that is switched off is quiet for a screen reader as well. With
disabledit 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, unlessfocusable-triggerasks for the stop, and a switch bound todata-wk-tooltip-disabledtakes the description away and gives it back as it flips. -
A tooltip no longer describes a control with the control's own name. Every button of the editor's toolbar, the links and the collapse control of a collapsible sidebar, the toggle of an expandable app rail and the status time of a 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, asdescribesdoes; a shortcut drawn after the words keeps it. -
The statement an energy label or a 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,requiredorreadonlythat 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:disabledon an accordion item or a floating action button left the button enabled. The same held forwire:loading., which on a multi-select or a file upload left the field operable while a request ran. Such a component now logs a warning that names the attribute, andattr="disabled" StrictnessGate::gives a test the same answer. The attribute on acontrol Attributes Without AControl() <fieldset>around a component disables every control inside it. Anautofocusthat reaches nothing that can take the focus is reported the same way. -
A
wire:modelon a component that binds no value with it is reported while debugging.wire:passes as framework wiring, so awire:modelon 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, andStrictnessGate::gives a test the same answer. The form components, a modal, a drawer and an 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 withoutcontrol Attributes Without AControl() selectable, a pagination withoutper-page-options, a readonly rating or an editor that cannot be edited. -
A form around a 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
nameon a form control sends nothing, on every control. An input givenname=""already rendered no name, so a form skipped it. A checkbox, a toggle, a radio, a password input, a time picker, a rating and a segmented control wrotename="", which HTML does not allow, and a range slider, a one-time code and a phone field 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-BRpage 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-shortcutcannot read is reported. It bound nothing without a word, so a typo such ascmd+shfit+sread as a shortcut that works. WithAPP_DEBUGon, 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 without markers and a stack rendered as a
ulorolstay 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 everyulandol. A screen reader on iOS therefore announced neither the list nor the number of its items. Both now carryrole="list", and aroleon the tag replaces it. -
A timeline row takes a date object for its time. Given PHP's own
DateTimeorDateasTime Immutable timeordatetime, a row ended the page. Given a Carbon, it showed2026-10-25 12:00:00as its text and wrote the same value without its offset asdatetime, and a Unix timestamp stood indatetimeas a bare number, which HTML reads as a year. A date object astimeis now written as the page's language writes a day with a time of day and gives the row itsdatetimeas well. Indatetime, a date object or a timestamp is written with its offset, a string such as2026-09as it stands, and a text that names no moment is reported. -
A date given only as a zone is reported. A countdown, a message, a review, a date separator, an event calendar and a timeline row read
CET,UTCor a single letter such asx, 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, asTBDis.now,tomorrow,+1 dayand a day with its zone read as before. -
An activity row and a usage meter take a date object as well. Given PHP's own
DateTimeorDateasTime Immutable timestamporresetAt, either ended the page, and given a Carbon, it showed2026-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 with
type="month"ortype="week"wrote a Carbon given asvalue,minormaxas2026-10-25 12:30:00, which the browser drops, so the field stayed empty and set no limit, and PHP's ownDateended the page. Both now write it in their own form,Time Immutable 2026-10and2026-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
timezonetakes a zone object. Given PHP's ownDateTimeZone, asgetTimezone()of aDatereturns it, a countdown, a message, a review and a date separator ended the page: theirTime Immutable timezonetook a zone name only. A zone object now names its zone, as aCarbonTimeZonealready did. -
A link under the heading of 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
descriptionslot, 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 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 or a datetime picker.
-
The text field of a color picker with
popoverreads a hex value typed without its#, as design tools copy one:B87334arrives as#b87334rather than being called invalid. -
A list pasted into a 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 number typed with the international prefix
00, or with011on the North American plan, picks its own country as one with a plus does.0043 1 234567on a field that stood on Germany was saved as+490431234567, a wrong number, where+431234567was meant. Digits after a prefix that name no country bind nothing. -
A file upload writes the size of each file as an attachment does, whole bytes and one decimal below 10,
512 Band24 MBrather than512.0 Band24.0 MB, with thousands grouped and in the application's own number format whereWireKit::sets one.format Numbers Using() -
A number input with a step below 0.000001, or with a
minormaxthat has more decimal places than its step, keeps the value it is given. It rounded every value to the places of the step alone, sostep="0.00000001"turned every value into a whole number, andmin="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
requiredandreadonlyno longer stops its form from being sent, as a read-only native field does not. A multi-select, a tags input, an OTP input, a combobox, a datetime picker and a date picker or time picker withpopoverkept 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"ortarget="_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 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
placementan overlay cannot place is reported under the name of the tag it was written on. A status dot, an app rail item, the scope switcher and the collapse toggle of a 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
unavailablethat names neither a day nor a time is reported. A calendar, a date picker withpopoverand a datetime picker left such an entry out without a word, so a closed day written as2026-13-45or24.12.2026, or a closed time written as25:00, stayed open for booking. It is now reported through strict validation, as aminormaxthat cannot be read is, and still closes nothing. An empty entry, white space and the zero date pass without a report. -
A 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'saria-describedbynamedfirst,name-hintandname-help, ids no element carries, and a screen reader read neither. A card, a filter builder and a notification center given anidwith a space build the ids of their parts without it, and a 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 picked with Shift held leaves out a checkbox the reader cannot see. A box in a row that a filter hides, with
x-showorhidden, 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 withselectablewas never affected: it renders only the rows it shows. -
The value under a cell of a treemap 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 read5in its cell and4,53in its tooltip. -
A preset of a calendar or a date picker that starts or ends on an unavailable day can no longer be picked. With today among the
unavailabledays, "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 and a countdown write their numbers in the application's own marks. With a format given through
WireKit::, 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 does.format Numbers Using() -
A second click on a link opens an accordion item, a collapsible card or a hidden part of a 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 withsubmit-onceis 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 of0. A submission that closes a dialog goes at any time, and the hold stays. -
Without an icon package, a sidebar item, a collapsible sidebar group and an app rail item no longer show the icon's name beside their label.
-
A floating action button 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, avariant, anintentor 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: with debug on, a Pest test or anartisancommand 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 themaxof a calendar or thecolumnsof a data table, is read as before. -
A field, a sidebar group, a mixed chart and tabs given a list where they take a switch or a number no longer end the page. The
requiredof a field, thecollapsible,openandforce-openof a sidebar group, thewire-stream-capof a mixed chart and thewrapof tabs report the list through strict validation and render with their default. Thecountof a reaction, thequantityof a cart line, thevalueof a radial progress and thethresholdof a 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. Thescopeevery component takes, thesrcsetof an image, thetimezoneof a 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 and renders without it, and an object such as a time zone or a date is read as before. -
The optimistic layer shows its state on its own root, also when a button's click applies it. The root stayed
idlewhile a request ran and the button keptoptimisticafter it settled, because the state was written on the element whose click applied it. -
A table in 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 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 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-refwritten on a part of a component reaches the$refsof the code around it, on the parts of a tabs, a tree view, a sidebar, a dropdown, a context menu, a menubar, a resizable group, a table and an app rail, and on the triggers of a drawer, the shortcuts dialog and a command palette. An item of a dropdown panel is included, though the panel is moved to the overlay root. -
A range in a calendar 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 and a datetime picker.
-
A calendar 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 or a 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 with more than one month fill a calendar that its container stretches, as one month does. In a
flex flex-color 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 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 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 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 announces a whole code corrected by overwriting a box.
wirekit:otp-completefired 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-flashthat starts leaving flashes and goes, also without a new key. The page on flashing a row that changed has the render that removes a row draw it once more withdata-wk-flash="danger"anddata-wk-flash-leave, but the flash played only on a newdata-wk-flash-key, so a row that kept its key stood there without a flash until the next render took it out. Settingdata-wk-flash-leaveplays the flash now, and a leave that brings a new key along plays it once. -
A click inside the open list of a combobox or a 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 or a multi-select with
servernever 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, a color picker and a notification center, the dialog of a datetime picker and those of a date picker and a time picker with
popoverclose 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 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 reaches only the editor that sent the value.
wirekit:inline-edit-savedandwirekit:inline-edit-failedname 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 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 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, a sticky navbar or another bar pinned there. It rests below the scroller's
scroll-padding-topnow, which a strip, every pinned bar of the kit and a bar of an application's own withdata-wk-scroll-insetreport, 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-topon 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 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:doctorscans the log files where thesingleanddailychannels write them. The silent-typo scan looked only atstorage/, so with the daily files moved into a folder of their own, as a logrotate rule overlogs/ laravel*.log storage/makes advisable, it skipped itself on every run and no rejected prop value surfaced. It reads each channel'slogs/*.log pathnow and finds the daily files beside it under the names Laravel gives them. -
The collapse control of a 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'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-nudgetoken,-1pxfor Inter, and keeps it there while the sidebar is collapsed, so folding moves no icon; any element that carriesdata-wk-icon-nudgetakes the same offset. The amount suits Inter, so the theme presets with a font of their own, a sans set infonts.sansandwirekit:install --fontwith any font but Inter set it to0px. -
A cell of a stacked table 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
labelnever appeared. A label of its own now makes it a named line. -
An alert 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. Adangeralert is still announced by its ownrole="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 --fontchanges the font of the components, not only of the body copy. The block it writes intoresources/setcss/ app. css --font-wk-sans,--font-wk-serifor--font-wk-monoinside@layer base, and a declaration in a cascade layer loses to the unlayered tokens ofwirekit.csswhatever its specificity, so every component kept Inter beside text in the new font. The block now sets the token in a plain:rootrule; running the command again replaces the old block between its markers. -
A language named with a locale of the application, such as
pt_BR, reacheslangas the tag HTML reads,pt-BR. The option of a select and of a segmented control, a field of a translatable input and the label of a checkbox and a radio wrote it as given, and HTML readspt_BRas an unknown language, so a screen reader kept the voice of the page. A charset or a modifier, as inde_DE.UTF-8, is left out as well, and the language props new in this release read it the same way. -
Tabs with
findablestart on the tab the server names. Withactiveset to another tab thandefault, the tabs went back to the default tab as soon as the page started, in every browser that supportshidden="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 without
hreftakes thetypeit is given. It wrotetype="button"ahead of the attributes it was given, so atype="submit"came second and was ignored, and a form that starts the sign-in with a POST request sent nothing. Without atypeit is a plain button, as before. -
A 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, its actions and a profile drawn as a button take the
typethey 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 keeptype="button"without a secondtypebeside it. Each view wrote its owntypeahead of the attributes it was given, and the first of two equal attributes is the one that counts.
Documentation
-
The phone number recipe shows its field in the form its title promises, with the Livewire wiring
wirekit:makewrites, and the marketing landing page recipe describes the colors its sparklines are drawn in. -
The 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-pagewrites its sections the same way, and the landing page with a table of contents names its brand without an emoji. -
The alert dialog page shows how an action receives the typed phrase.
wire:click="destroyon the confirm control sendsEnvironment(typed)" null: the dialog's panel stands at the end of the page, outside the element that holdstyped, and Livewire reads a name it does not find in the Alpine data around an element as a property of the component. The page showsx-on:click="$wire., which Alpine evaluates with the dialog's data, and the phrase checked again on the server.destroy Environment(typed)" -
The card and 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 page says what
wireStreamModedecides. It called it the handling of a malformed streamed point. It decides the cap:strictkeeps each dataset atwireStreamCappoints and drops the oldest first,streamlets the series grow without a bound, as on the chart page. -
The brand 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 page shows the tab it hears. It read a
namefromwirekit:tab-changed, which carries the tab's key astaband its label aslabel, so its preview showed a dash after every click, and the sentence below it sent the event from Livewire with anameno tab reads. It now readstab, and the sentence points at the way tabs are observed from a Livewire component. -
The examples that listen to WireKit's events run under a Content-Security-Policy build. On the events, sidebar and tree view pages, a listener used optional chaining, an
ifstatement orconsole, none of which Alpine's CSP build evaluates: on a page with Livewire'scsp_safeor WireKit's CSP bundle, a copied listener did nothing and reported nothing. Each is an assignment, a&&or a call now, and the integration page says where an example's own logic goes on such a page. -
The slider, textarea and select pages name the Livewire 4 binding that sends. They recommended
wire:model.orchange wire:model.blurin place of.live, and without.liveneither sends anything by itself. The binding that sends when a slider is released iswire:model., and the one that sends when the reader leaves a field islive. change wire:model..live. blur -
The streaming examples on the shimmer and assistant message pages set their streaming state in a request of its own. Both turned
$streamingon 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 oraria-busy.submit()now sets the state and starts the stream with$this->js('$wire., and the shimmer example gets theask()') wire:streamtarget and the property its text streams into. -
The assistant message example for
announce="all"says where its event comes from. Its listener calledflush()onstream-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 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, the app shell, the table, the dropdown, the drawer, the command palette and the 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 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 ofoptimistic-argsfollow the new value in the call. The page every optimistic component links to did not say so. -
The Leaflet & OpenStreetMap page sets the tile source once for every map, and its examples follow that setting. Each example set its
styleUrlto 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 page shows the settings for both engines, and the MapLibre page says that the demo style, its tiles and its fonts come fromdemotiles..maplibre. org -
The error-state example of the color picker no longer promises a named color in its hint, which no field of the picker reads.
-
The price page says that
minor-unitsdivides 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 shows the same path under a Content Security Policy:
register()on the Alpine of Livewire'slivewire., withcsp. esm. js @livewirein the layout, or onScript Config @alpinejs/cspwithout Livewire. The README of the bundles points to it and to thefactoriesthatwirekit:export-api-maplists for every component. -
The calendar's range limits say that a range may cover an unavailable day.
unavailablecloses 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 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 showswirekit:modal-dismissedwith the route the reader took now, and the page says which of the two events is a command and which a report. -
The sidebar page says where its collapse toggle stands. It said that
toggle="start"moves the control to the top, which it never did: withstartand withendthe control stands at the foot of the column, lined up with the item icons, andnoneomits it. -
The accessibility example on the chart-mixed 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 passesaria-labelto<x-wirekit::.chart-mixed>
Components
Every component this release changes, each linked to its page: Accordion · Action Bar · Activity Row · Alert · Alert Dialog · Announcement Banner · App Rail · App Shell · Aspect Ratio · Assistant Message · Attachment · Avatar · Badge · Band · Bento Grid · Blockquote · Bottom Nav · Branch Switcher · Brand · Brand Bar · Breadcrumb · Bulk Selection · Button · Button Group · Calendar · Callout · Card · Card Stack · Carousel · Cart List · Cart Summary · Center · Chart · Chart Mixed · Chat Marker · Checkbox · Clipboard Button · Code · Code Block · Collapsible · Color Picker · Combobox · Command Palette · Container · Context Menu · Conversation · Countdown · CTA · Data List · Data Table · Date Picker · Date Separator · Datetime Picker · Divider · Drawer · Dropdown · Editor · Empty State · Energy Label · Event Calendar · FAB · FAQ · Feature · Feature Grid · Field · File Upload · Filter Builder · Fit Text · Flag · Fonts · Footer · Form · Grid · Header · Heading · Hero · Highlight · Hover Card · Icon · Image · Image Compare · Image Editor · Image Gallery · Image Hotspots · Image Hotspots Editor · Indicator · Inline Edit · Input · Kanban · Kbd · Label · Lightbox · Link component · List · Live List · Logo Cloud · Main · Map · Mark · Menubar · Message · Message Group · Message Typing · Mockup · Modal · Multi-Select · Navbar · Navigation Menu · Notification Center · Number Input · OTP Input · Overflow Nav · Page Header · Page Progress · Pagination · Password Input · Phone · Popover · Price · Pricing Table · Product Card · Profile · Progress · Progress Radial · Prose · QR Code · Quick Replies · Radio · Range Slider · Rating · Reaction · Reading · Reorder · Replay Button · Resizable · Reveal · Review · Review Summary · Row · Scope Switcher · Scroll Area · Scroll to Top · Section · Segmented Control · Select · Shell Bar · Shimmer · Shortcuts · Sidebar · Sign-in Button · Skeleton · Skip Link · Slider · Spacer · Sparkline · Spine-Aware · Spinner · Stack · Stage Card · Stat · Stats · Status Dot · Status Matrix · Status Tiles · Step Marker · Stepper · Sticky Panel · Stream · Strength Meter · Structured Data · Swap · Swatch · Swatch Group · Table · Tabs · Tags Input · Team Section · Testimonial · Text · Textarea · Theme Controller · Ticker · Time Picker · Timeline · Tire Label · Toast · Toggle · Toggle Button · Tool Call · Toolbar · Tooltip · Tour · Translatable Input · Tree View · Unsaved Hint · Usage Meter · Video · Visually Hidden · Wizard