quasar
Build high-performance Vue.js user interfaces (SPA, PWA, SSR, SSG, Mobile and Desktop) in record time
2.27.0
quasarframework/quasar
What this package is like to depend on
Last release today
25 Aug 2026
Release timing varies
gaps range from 8 days to 4 months
Rarely documented
notes for 7 of 339 stable releases
Nothing withdrawn
no release was ever pulled
11 years old
434 releases · first in 2015
30 releases in the last 12 months
see the full history below
Release timeline
434 releases · Jul 2015 to Aug 2026Releases
latest 60 of 434-
2.27.025 Aug 2026Release notes
Open source →Important
Two behavior changes worth checking before you upgrade:
- A click on the target no longer closes a hover-opened QMenu/QBtnDropdown while it is still animating into view. A single move-and-click gesture can no longer dismiss what it just opened; once the menu is fully shown, clicking toggles it closed exactly as before.
- Three language packs now report a standards-compliant
isoName:kur-CKBreportsckb,mmreportsmyandsr-CYRreportssr-Cyrl. The old import paths keep working as deprecated aliases for the whole of Quasar v2, but code comparing$q.lang.isoNameagainst the old values needs updating.
New
- feat(QFab): open on hover -> new
hover,hover-delayandhover-hide-delayprops, the same contract QMenu and QBtnDropdown got in v2.26. The pointer can cross the gap between the main button and the actions without closing them (150ms grace period by default), touch devices keep tap-toggling, keyboard interaction is untouched, and focus is never moved - feat(QTd/QTh): new
col-nameprop -> a QTd or QTh wrapped in your own component inside QTable's#bodyslot can finally say which column it belongs to. The cells used to resolve their column from the vnodekey, which Vue never forwards through$attrs, so a wrapped cell rendered nothing. Existingkey="..."usage keeps working;col-nametakes precedence (#17830) - feat(ui/lang): canonical names for three language packs -> import
quasar/lang/ckb,quasar/lang/myandquasar/lang/sr-Cyrlfor Central Kurdish, Burmese and Serbian Cyrillic.kur-CKB,mmandsr-CYRremain available as deprecated aliases
Fixes
- fix(QMenu): ignore a click on the target while hover is animating the menu into view -> moving the pointer onto a
hovermenu's target and clicking it in one gesture closed the menu the hover had just opened. Also applies to QBtnDropdown (#18524) - fix(QSelect): keep long selected values inside the parent -> a nowrap value made the field grow past its container instead of truncating (#18015). Based on PR #18525 by Timur Arbaev
- fix(QTable): honor the
keyset on the griditemslot content -> the mapped rows reached Vue as keyless Fragments, so removing a row recreated every card after it instead of moving the surviving instances (#18045) - fix(QScrollArea): put the vertical thumb on the left side in RTL -> the bar moved to the left edge while the thumb stayed glued to the right one, because its inline
rightinset could not be flipped by the RTL stylesheet (#17943) - fix(ui): make overlay content clickable over
.q-electron-dragregions in Electron -> menus, dialogs, notifications and tooltips overlapping a draggable title bar lost the overlapping area to window dragging. An explicit drag class on the content itself still wins, and dialogs keep letting you drag the window (#17285) - fix(use-mask): don't read a fill char that satisfies its own token as data -> with
fill-mask="0"and reverse filling, the unmasked value grew by one fill char per keystroke ("0.01" became "00.01", "000.10", ...), which is the docs' own "Price with 2 decimals" example (#18523) - fix(use-mask): keep the fill padding out of the unmasked value -> with
unmasked-valueand forward filling, a typed "1" over###-##withfill-mask="0"was reported as "10000"; with maskAA-AAandfill-mask="A", "X" became "XAAA" (#18523) - fix(use-mask): follow the data, not the render, when placing the caret -> when the fill char is itself a valid data char, "06" arrived as "60" and, on masks with a leading literal, "09" arrived as "90" (#18523)
- fix(use-mask): unmask masks that mix token types -> under
reverse-fill-mask, every mask mixing letters and digits silently rendered nothing for ordinary values ("ab12" overAA-##), including values the control had just rendered itself (#18523) - fix(use-mask): drop a right-aligned separator nothing filled -> "057" over
AA-##rendered "-57", which unmasked back to "57", so what the field displayed was not a value it could read again (#18523) - fix(ui/lang): repair strings across 51 language packs -> stray quotes and characters, leading/trailing/doubled spaces, broken interpolation, Cyrillic text inside the Latin
srpack, Simplified characters insidezh-TW, untranslated English left in translated packs, and year-range plural/agreement errors in some 40 languages (#18522). Ukrainian was corrected first in PR #18522 by Ihor Diachenko
Other
- docs(popup offset): the
offsetprop of the position engine does not translate the popup, it inflates the anchor box, somiddle/centerorigins are offset-invariant by construction. That is why QTooltip's horizontal offset reads as broken on its defaultanchor="bottom middle". Documented on the API of QMenu, QTooltip, QBtnDropdown, QPopupEdit and QSelect, with the direction each offset component expands in, plus the note that QMenu'scoverdrops the offset entirely (#18212) - The language-pack build validator now checks string values, not only pack shape:
validateStringArraywas declared with four parameters and called with three, so its loop never ran. Every string, array entry and formatter result is now checked for padding, doubled spaces and control characters, and formatters are probed across the counts that select their plural branches
Donations
Quasar Framework is an open-source MIT-licensed project made possible due to the generous contributions by sponsors and backers. If Quasar is useful in your workflow and you want to support ongoing maintenance, please consider the following:
-
2.26.021 Aug 2026Release notes
Open source →Important
A few behavior changes worth checking before you upgrade:
- QEditor no longer emits a
placeholderattribute (it was not valid on a div). Custom CSS targeting.q-editor__content[placeholder]must switch to[aria-placeholder]. - QSelect renders its fall-through attributes only on the focus target, no longer also on the
.q-field__nativewrapper. Selectors or tests that matched the wrapper copy (or relied on the attribute matching two elements) need updating. - The touch/hover behavior of QTooltip, context menus, the touch directives and the slider family is now decided per interaction instead of by the mobile UA. Hybrid devices change the most: touchscreen laptops and tablets with a mouse gain hover tooltips and right-click context menus, mobile UAs gain keyboard support on QSlider/QRange/QKnob, and QRange stops emitting UA-dependent SSR markup.
- QDialog dismisses its backdrop on mousedown instead of click, so a press on the backdrop with a menu open closes only the menu on desktop too, matching what touch already did.
- QSlider/QRange/QKnob de-duplicate their emissions:
changefires only when an interaction actually moved the value, and a parent that does not sync the model prop back hears each value once per interaction rather than once per press/release/click. - Firefox now matches QField's autofill styling: the stylesheet moved from
:-webkit-autofillto the standard:autofill, so theq-autofillkeyframe and$input-autofill-colorapply there for the first time.
New
- feat(QMenu): open on hover -> new
hover,hover-delayandhover-hide-delayprops, also forwarded by QBtnDropdown (in split mode hovering either button opens it). A hover-open never steals focus from where you are typing, ESC still dismisses, submenus keep the chain open while the pointer travels between them, and touch devices keep tap-toggling. No effect whencontext-menuis set (#6776) - feat(QRange): new
min-rangeandmax-rangeprops -> constrain the width of the selection. Out-of-limits model values are coerced likeinner-min/inner-maxalready do, dragging and the keyboard clamp each thumb to what the other thumb allows, and a minimum width blocks thumb crossover (#18182, #2100). Based on PR #18182 by Teodor Atroshenko (thexeos) - feat(QTable): new
footerslot -> renders a real<tfoot>element, so a totals/summary row can be made sticky through CSS. Works in default and virtual-scroll modes (not in grid mode) (#7570) - feat(date): support the ISO week year -> new
getISOWeekYear()util and the Moment/Day.js-compatibleGGGG/GGformat tokens, so masks likeYYYY-[W]wwno longer render the wrong pairing at year boundaries (Jan 1st 2022 was formatted as 2022-W52 instead of 2021-W52) (#17088, credit: psevertson) - feat(Ripple): cancel an "early" ripple once the gesture can no longer end in a tap -> a touch that turns into a scroll/pan, or a pressed pointer dragged off the element, now fades the ripple out instead of leaving a full one behind with no click ever happening. On touch, painting waits 100ms (was 50ms) so flick-scrolls are cancelled before anything becomes visible
- feat(ui): correct the CSS vendor prefixes across the stylesheet -> printing keeps the QCheckbox/QRadio/QToggle backgrounds in Firefox and Safari (
print-color-adjust), Firefox gains the QField autofill styling (:autofill), the QFile/QUploader file button styling (::file-selector-button) and the QPagination input styling (appearance), while prefixes no engine reads any more are gone
Fixes
- fix(ui): accept
class,style,keyandrefon components in JSX/TSX -> the exported component types did not carry Vue'sPublicProps, so TSX rejected the universal props. Templates were never affected (#8690) - fix(QTooltip): decide the touch UX per interaction instead of per device -> mouse and pen hover show the tooltip on any device, so touchscreen laptops, tablets with a mouse and hovering styluses get hover tooltips the mobile-UA check denied them, while a touch press keeps the exact mobile behavior (#14763)
- fix(QTooltip): give a pressed stylus the touch UX -> a pencil held against the anchor got hover semantics and no selection suppression, because a pen reports the same
pointerTypewhether it hovers or touches - fix(QTooltip): ignore focus moving within the anchor -> QBtn shuffles focus to an internal helper after every press, so clicking a QBtn with a tooltip flash-hid it on desktop
- fix(useAnchor): serve context menus by capability instead of by mobile UA -> tablets with a mouse gain right-click context menus, the keyboard context-menu key works on mobile UAs, and touchscreen laptops get the same 300ms long-press with selection suppression phones have instead of engine-dependent native timing
- fix(TouchHold/TouchRepeat): suppress text selection per interaction, not per device -> a touchscreen laptop no longer shows selection artifacts during a long-press, and a mouse press on a mobile UA no longer suppresses selection it never needed
- fix(QSlider/QRange/QKnob): wire taps, presses and the keyboard on every platform -> mobile UAs rendered a focusable track that ignored arrow keys, and desktop had no click handler so assistive-tech clicks did nothing
- fix(QSlider/QRange/QKnob): hand each value to a non-syncing parent once -> a controlled model that rejects the update heard the same value re-emitted by the press, the release and the compatibility click
- fix(ui/slider): emit
changeonly when the interaction changed the value -> pressing End with the thumb already at the maximum, clicking the value the slider already had, or dragging away and back all fired a spuriouschange - fix(QKnob): emit
changeonly when a user adjustment lands a new value -> mounting, every parent model write and range clamping used to fire it, contradicting its own API description - fix(QRange): don't leave a thumb's focus ring behind after a track tap -> on touch nothing ever blurs the internal focus state, so the ring stayed on the tapped thumb through scrolling and taps elsewhere
- fix(ui/slider): keep marker tick values float-exact on fractional steps -> a fractional
stepdrifted (0.1 + 0.1 + 0.1 = 0.30000000000000004), somarker-labelsrendered the drifted number andmarker-label-*slot lookups missed - fix(ui): act on backdrop press so an open menu is dismissed alone -> with a menu open inside a QDialog, the first press on the backdrop closes only the menu on desktop too. Non-primary buttons are ignored
- fix(QInfiniteScroll): resume polling when a scroll lock releases with the page at the top -> a window-target QInfiniteScroll that mounted, was re-keyed or left
disablewhile a Dialog or overlay Drawer held the scroll lock never polled again (#18520) - fix(QInfiniteScroll): do not auto-load a window scroll target from inside a fixed-positioned subtree -> content in a Dialog or fullscreen overlay never contributes to the document's scroll extent, so every
done()triggered the next load forever (and reverse mode jumped the page behind the overlay to the bottom on mount). Such a placement now warns once, points at thescroll-targetprop and revives itself if the fixed positioning goes away (#18520) - fix(QSelect): render fall-through attributes only on the focus target -> attributes like QTable's rows-per-page
aria-labelmatched two elements and broke strict single-element queries (PlaywrightgetByLabel, Testing LibrarygetBy*); the wrapper copy was invalid ARIA as well (#18519) - fix(QSelect): always render the hidden form element, like QInput does -> a QSelect with
name/forset but a null or empty model rendered no element at all, soquerySelector('[name=x]')could not find it. Form submission and validation are unaffected (#17951) - fix(QEditor): clicking the placeholder focuses the field on Chrome -> the placeholder rule now reads the
aria-placeholderthe component already renders, and the invalidplaceholderattribute is no longer emitted (#18511) - fix(QDrawer): hide the opposite drawer again when showing one in mobile behavior -> both drawers could end up on screen at once, stacking two backdrops
- fix(QDrawer): apply
roleandaria-*attributes to theasideelement -> they landed on the inner scrolling div, so naming or re-typing the landmark through QDrawer was impossible (#18059) - fix(QField): hide shadow-text on blur while the field has an error -> an invalid field kept showing the shadow text after blur, overlapped with the label (#17155)
- fix(QInput): let the textarea line-height follow the font-size ->
.q-textareapinned its rows to 18px, so a bigger font gave cramped, overlapping lines that apps had to override with!important. The default layout is unchanged (#16772) - fix(QItem): let overline/caption labels, header labels and side sections follow the item color -> an active (
.q-router-link--active) or custom-colored item kept gray secondary text. Derived fromcurrentColorviacolor-mix()at the same emphasis levels, with the legacy values kept as fallbacks (#18300) - fix(QExpansionItem): keep the header icon/toggle colors when using
switch-toggle-side(#18008)
Other
- docs(QDate): the
eventsandoptionsarray forms (and the String handed to their function forms) are always compared asYYYY/MM/DD-- themaskprop never applies to them. Documented on the API instead of changing it; the function form remains the customization point (#16735) - docs(QDrawer):
behavior,breakpoint,show-if-above,persistentandno-mini-animationwere documented by example only. Adds a "Desktop and mobile behavior" section and correctsshow-if-above, which was described as initial-render-only when it actually re-shows the drawer every time the layout goes back above the breakpoint - Regression coverage for the capability-based interaction rework: six cross-engine sweep scenarios (tooltip pointer wiring and pen lifecycle, context-menu ownership arbitration, backdrop press, the slider tap/keyboard burst, per-interaction selection suppression) plus a touch-capable Chromium pass in the matrix, and hardened QSlider/QRange suites
Donations
Quasar Framework is an open-source MIT-licensed project made possible due to the generous contributions by sponsors and backers. If Quasar is useful in your workflow and you want to support ongoing maintenance, please consider the following:
- QEditor no longer emits a
-
2.25.118 Aug 2026Release notes
Open source →Important
A few behavior changes worth checking before you upgrade:
lazy-rulesnow clears an error while you type: while an error is displayed, the field re-checks on each model change instead of waiting for the next blur. Rules that were only ever meant to run on blur will now also run on every keystroke for as long as the field is in error.- Async rules re-validate when the value changes or the field blurs mid-flight: a slow rule that settles after the user moved on no longer paints its verdict onto the newer value; a second validation run is triggered instead.
- The field's hint/error/counter area sits in normal flow: a message taller than one line now grows the field instead of painting over the content below it. Geometry is unchanged for every one-line message, except item-aligned fields, which now reserve that one line (about 20px taller) instead of bleeding messages into the next item. Custom CSS leaning on
.q-field--with-bottom'spadding-bottomor on the absolutely positioned.q-field__bottom--animatedneeds a second look. - QLayout can emit one extra
@scroll: a scroll update suppressed while the body scroll lock was held is now applied when the lock releases without restoring the position.
Fixes
- fix(QField/QInput/QSelect/QFile):
lazy-rulesre-validates on model change while an error is displayed -> the error clears as soon as what you type becomes valid, instead of staying up until the next blur (#17456) - fix(QField/QInput/QSelect/QFile): re-validate when the model changes or the field blurs during a pending async validation -> a slow rule can no longer settle onto a value the user has already replaced, leaving the field showing a verdict for text that is no longer there
- fix(QForm): report a child whose
validate()throws synchronously -> that child now fails and gets focused, exactly as a rejected async rule already did, instead of the exception breaking the wholesubmit() - fix(QField): flow the hint/error/counter area in-layout -> a message longer than one line grows the field instead of painting over whatever follows it, and item-aligned fields no longer bleed their messages into the next item (#17807)
- fix(QLayout): re-sync the scroll state when a scroll lock releases on a changed route -> navigating away from inside a Dialog or under the Loading plugin left the layout holding the pre-navigation scroll state, so a reveal QHeader never reappeared at the top of the new page (#12994)
- fix(QMenu/QTooltip): re-anchor when the iOS visual viewport moves -> with the soft keyboard open or while pinch-zoomed, iOS scrolls only the visual viewport and no window scroll event fires, so an open popup ended up detached from its anchor by the scrolled amount (#16849)
- fix(QSelect): keep the field width stable while loading with
hide-dropdown-icon-> with no icon to swap for, the default spinner appended net-new width and the field jumped on every filter round-trip. The default spinner is now suppressed when the dropdown icon is hidden (an explicitloadingslot still renders), and the clearable icon keeps its place while loading instead of vanishing (#17375) - fix(QTabs): show the overflow arrows when
align="right"-> Blink and Gecko keep start-side overflow out of the scrollable overflow region, which collapsed the measurement and hid both arrows, leaving the overflowing tabs unreachable by pointer (#17847) - fix(QInfiniteScroll): stop polling while a Dialog or an overlay Drawer scroll-locks the page -> opening one over an infinite scroll fired
@loadin a loop until the whole list had been fetched (#13257) - fix(QInput): don't lose a typed char that equals a mask literal -> mask
11##swallowed a typed "1" and04## ### ###a typed "0", because the char could not be told apart from the literal sitting at that position (#15624, #18051) - fix(QInput): soft-keyboard backspace over a mask literal deletes the data char before it -> on iOS the browser removed only the literal, the remask put it straight back, and the edit became a silent no-op that left the caret misplaced, so every digit typed next landed one slot early and scrambled the value (#17639)
- fix(QInput): re-anchor the caret after a dynamic mask change -> with a mask computed from the value being typed, the caret could land inside the value after the layout shifted, so the next digits scrambled it and the last char read as never registering (#7777)
- fix(QInput): drop a stale debounced emission when the mask restores the model's value -> cutting a whole masked value and pasting it back before the debounce fired emptied the model while the input showed the pasted text (#17568)
- fix(ui): resolve a custom Dialog's
show/hidethrough arbitrarily nested components -> a QDialog sitting behind two or more single-root wrapper components failed with "Incorrectly defined Dialog component" and never opened (#18159)
Other
- Regression coverage for the two families reworked here: the validation composable (async races, the QForm submit flow, reset/unmount/disable, reactive rules) and the mask engine (chars equal to a literal, dynamic masks, backspace bursts, the multiple-masks pattern), plus cross-engine sweep scenarios that also run on the iOS Simulator, where the mask and QTabs bugs above behave differently than on any desktop engine
Donations
Quasar Framework is an open-source MIT-licensed project made possible due to the generous contributions by sponsors and backers. If Quasar is useful in your workflow and you want to support ongoing maintenance, please consider the following:
-
2.25.017 Aug 2026Release notes
Open source →Important
A few behavior changes worth checking before you upgrade:
- QMenu no longer claims
role="menu"and QBtnDropdown's toggle no longer emitsaria-haspopup-- a menu may only containmenuitem*children, so the old markup was invalid. Declarerole="menu"on the wrapped QList (its actionable QItems then expose themselves as menuitems automatically) and use the newtoggle-aria-haspopupprop on QBtnDropdown. - SSR'd virtual lists now render their first slice on the server, so item templates of a server-rendered QVirtualScroll/QTable run on the server too and must be SSR-safe.
- QSlideTransition starts animating immediately instead of 100ms later, which shifts the timing of every QTree / QExpansionItem / QStep slide.
- Third-party language packs: this release adds
colorPickeranduploadersections plus several keys. All are optional in the types and read with optional chaining, so existing packs keep working and compiling -- but they will announce nothing for those internals until updated.
New
- feat(QTree): opt-in virtual scroll mode -> new
virtual-scrollprop family,@virtual-scrollevent and key-basedscrollTo(key, edge). Only the rows around the viewport exist in the DOM, so cost stays flat however much of the tree is expanded (22.6k nodes, dev mode: expand-all 2.2s -> 23ms, filter keystroke on a fully expanded tree 560ms -> 29ms, ~600 DOM elements at any scale) - feat(QTree): methods for the state v1 exposed through its per-node meta map ->
getIndeterminateNodes(),isIndeterminate(key),getParentNode(key)and tri-stategetTickState(key)(returns thetrue/null/falsea QCheckbox takes as its model); the header and body slot scopes gain anindeterminateboolean next toticked(#17298) (#12762) - feat(ui): SSR renders the virtual scroll initial window -> server-rendered virtual lists emit their first slice instead of zero items, so crawlers and first paint finally see content. QTable's virtual-scroll mode inherits it; QSelect is unaffected
- feat(QDate): roving-tabindex keyboard navigation for the day grid -> the calendar is a single Tab stop instead of up to 31. Arrows move by day/week, Home/End to the week edges, PageUp/PageDown by month (Shift for year), all crossing month boundaries and honoring RTL, the
optionsprop and the navigation-min/max limits - feat(QTime): direct numeric keyboard entry on the time units -> typing digits on a focused hour/minute/second sets it directly, accumulating multi-digit values within 1.5s (#12467)
- feat(QSplitter): Enter collapses the primary panel to its minimum limit and restores the pre-collapse position on the next press (#12466)
- feat(QSlider/QRange): the
sliderrole now sits on the focusable element, and the whole family gains Home/End - feat(QRange): WAI-ARIA multi-thumb slider semantics -> new
left-thumb-aria-labelandright-thumb-aria-labelprops - feat(QBtnDropdown): new
toggleslot -> renders next to the dropdown arrow, so content like a QTooltip can finally attach to the toggle button in split mode (#16955) - feat(QBtnDropdown): new
toggle-aria-haspopupprop -> names the popup's role on the control that actually opens it, in both the regular and the split design - feat(QList/QItem): new
roleprop -> the documented override path (e.g.menuitemcheckbox, orrole="menu"on a QList) - feat(QLayout): new
$layout-marginal-backgroundand$layout-marginal-colorSass variables for the marginal sections (#10476) - feat(QDrawer): new
escape-keyevent - feat(QField): the
controlslot scope gainsariaInvalid,ariaDescribedbyandariaErrormessage - feat(a11y): the component internals consumers cannot reach now carry accessible names -> QColor's view tabs, header value field and hue/opacity sliders, QUploader's icon-only buttons and hidden file input, QTable's selection checkboxes plus their empty column header, and QPagination's navigation landmark. Adds the
colorPickeranduploaderlang sections plustable.selectAllRows,table.selectRowandpagination.label, translated across all 72 language packs
Accessibility
- fix(QTime): implement the WAI-ARIA spinbutton pattern -> the hour/minute/second controls are localized spinbuttons instead of mislabeled toggle buttons; arrows adjust the focused unit (key-repeat works, the page no longer scrolls) and Home/End jump to the first/last valid value (#12467)
- fix(QDate): give the calendar controls real accessible semantics -> days announce their full localized date instead of a bare number, expose selection through
aria-pressedand mark today witharia-current="date"; the view switcher becomes a real button that Space activates - fix(QOptionGroup): implement the WAI-ARIA radiogroup keyboard pattern -> a radio group is a single Tab stop with arrow-key navigation, wrapping, skipping disabled radios and mirrored in RTL (#17638)
- fix(QOptionGroup): announce a disabled group whatever its type ->
aria-disabledwas set only for radios - fix(QSplitter): implement the WAI-ARIA window splitter keyboard pattern -> the separator is a focusable, value-carrying
separator; arrows move it by 1% (10px inpxunit) and Home/End jump to the limits (#12466) - fix(QSplitter): give the separator bar an accessible name -> new
separator-aria-labelprop - fix(QTabPanels/QTabs): complete the WAI-ARIA tabs pattern -> QTabPanel is focusable so keyboard and screen reader users can reach panel content with nothing focusable inside, and the
tabpanelrole lives solely on the panel components (#6560) - fix(QStepper/QCarousel): correct the ARIA semantics of their panel patterns -> QStep drops the orphaned
tabpanelrole and becomes a group labeled with its title, conveyingaria-current="step"even with header navigation off; QCarousel's navigation is exposed as the tabs pattern it actually is (#6560) - fix(QEditor): complete the WAI-ARIA toolbar/textbox contract ->
role=toolbarwith a localized name, a single Tab stop with roving tabindex, arrow navigation (wrapping, RTL-mirrored) and Home/End (#15675) - fix(QEditor,QTable): name the internals that reuse existing lang keys -> QEditor's toolbar toggles convey their state with
aria-pressedinstead of color alone, and the hyperlink editor's URL field gets a name - fix(QMenu/QList/QItem): derive valid ARIA roles instead of claiming
role=menu(#17162) - fix(QMenu): close the popup when TAB moves focus out of it -> focus no longer drops onto the browser UI leaving the menu open (#15675)
- fix(QMenu): mark its anchor as the popup's trigger ->
aria-expanded/aria-controlsstay in sync without apps mirroring the open state by hand - fix(QMenu,QDialog): render menu portals inside their
aria-modaldialog -> menus anchored in a modal QDialog (a QSelect's listbox included) were pruned from the accessibility tree and never announced (#17078) - fix(QSelect): align the popup with the ARIA combobox pattern -> the
listboxrole wraps only the options, which now carryaria-setsize/aria-posinset(#17344) - fix(QSelect): keep a readonly select focusable and announced -> it used to emit no focusable element at all
- fix(QSelect): expose a disabled select instead of dropping its control
- fix(QSelect,QTable): give the rows-per-page selection an accessible name (#9689)
- fix(QInput,QSelect,QField): expose error state to assistive tech (#18323)
- fix(QFile): expose error state to assistive tech (#17306)
- fix(use-field): drop the error ARIA references when no message renders ->
<q-input error hide-bottom-space>pointedaria-errormessage/aria-describedbyat a missing id - fix(QTree): tickable nodes trapped the keyboard -> tickboxes leave the Tab order and Space toggles them from the node header (#17603)
- fix(QTree): make every visible node keyboard-reachable, disabled ones included -> arrow navigation used to skip every leaf in a tree without selection
- fix(QTree): don't hijack keys typed into interactive header content (#17790)
- fix(QTree): demote a stale roving Tab stop -> re-expanding could leave two Tab stops
- fix(QTree,useRefocusTarget): never let focus land in an
aria-hiddencontrol (#17810) - fix(QCarousel): give the prev/next arrows an accessible name -> new
carousellang-pack section, translated across all packs (#7423) - fix(QDrawer): let ESCAPE dismiss the drawer in its modal states, under exactly the conditions the backdrop accepts a click (#7423)
- fix(QItem): attach pointer listeners only on interactive items -> WCAG checkers flagged the no-op handlers on a non-clickable QItem (#7423)
- fix(QStepper): announce a disabled step header as an unavailable button instead of inert text
- fix(QRating): ArrowDown/ArrowUp move focus in the documented radio-group direction
- fix(QSlider,QRange): say "no value" instead of announcing a limit as one -> a null QSlider announced the minimum, an untouched QRange the whole range as selected
- fix(QSlider,QRange,QImg): emit valid ARIA in three edge cases
- fix(QIcon): keep the ligature text out of the accessibility tree (#18084)
- fix(a11y): give the scrollable regions keyboard access -> QMarkupTable and QTable's horizontally scrolling middle are Tab stops, so a table wider than its container is no longer pointer-only
- fix(ui): drop spec-invalid ARIA from QToggle, QPagination, QChip, QFab, QImg, QLinearProgress, QTimeline and QBtn
- fix(types): keep the screen-reader lang keys optional -> a third-party language pack written before them kept compiling
Performance
- perf(QTree): the tree was rebuilt around lazy rendering, per-node render isolation and incremental state -> collapsed subtrees mount on first expansion instead of being pre-rendered behind
v-show(22.6k-node tree, dev mode: 2196ms/299,713 DOM elements -> 31ms/169), a state change re-renders only the affected nodes, and the monolithic O(N) meta rebuild became layered derivation that recomputes only on its own triggers. Per-key state of keys that left the model is pruned, andgetTickedNodes()/getExpandedNodes()use keyed lookups - perf(QSlideTransition): start animating immediately instead of 100ms later -> every QTree, QExpansionItem and QStep slide loses 100ms of idle latency, and
duration <= 0short-circuits to an immediate settle - perf(ui): a broad mount-cost sweep ->
useQuasar()resolves through the instance's global properties (~0.6ns/read vs ~37ns), size styles are module-cached, and trivial computeds were flattened out of the render path across ~70 files (QBtn, QItem family, the checkbox family, QChip, QTab/QRouteTab, QList, spinners and 12 bulk-mounted leaves, plus use-dark/use-align/use-form/use-transition/use-router-link/use-split-attrs) - perf(ui): every component of that sweep was then re-benchmarked in a real browser, and the computeds whose removal cost more than it saved were restored
- perf(QIcon): module-level parse cache, no per-instance computeds
- perf(date): compile
formatDatemasks once and cache per mask - perf(QScrollArea): allocation-free
@scrollpayload assembly - perf(ui): allocation-free
isKeyCode, loop-basedsumSize, regex-freehexToRgband allocation-free mask token testers - perf(QInput/QSelect/QTab): test the cheap event flags before
shouldIgnoreKey()
Fixes
- fix(QSelect): allow cancelling keyboard actions (#18507)
- fix(QInput): allow cancelling mask keyboard actions (#18515)
- fix(QEditor): allow cancelling the CTRL keyboard shortcuts ->
@keydown.ctrl.b.preventcould observe the key but not stop QEditor toggling bold - fix(QTab/QRouteTab): allow cancelling the keyboard actions -> the event was emitted after the tab had already acted on it
- fix(QEditor): commit a link only when the user asks for it -> opening the link toolbar used to wrap the selection in an
<a href="https://">straight away, leaving a broken link behind if you walked away (#18289) - fix(QEditor): keep the link editor open when the command sits in a toolbar dropdown (#17920)
- fix(ui): add validation for the q-editor link
- fix(QMenu): keep popups open on clicks inside a fullscreen-detached child (#18512)
- fix(QMenu): follow the anchor through a fullscreen detach -> the menu stayed open at stale coordinates, painted over by the fullscreen element (#18513)
- fix(useFullscreen): keep focus and caret through the detach/restore moves -> a caret placed in a QEditor before entering fullscreen was lost (#17843)
- fix(QMenu/QTooltip): follow an anchor still moving during the enter transition -> the popup no longer lands at a stale spot and snaps into place at transition end
- fix(QDialog/QMenu): don't throw on focus when the inner ref holds a non-Element stub (#12780)
- fix(QDialog/QTooltip): resolve fall-through attrs on the render path -> a dynamic
:classon an open QDialog never reached the portal root, and a dynamicidwent stale on QTooltip - fix(QDialog): stop fighting the iOS scroll position while the viewport is zoomed
- fix(QScrollArea): stop trapping fixed-positioned children -> a
position: fixeddescendant anchored itself to the scroll area and was clipped there (#12109) - fix(QSelect): display falsy (non-null) selected values with
fill-input(#17763) - fix(QInput): restore the textarea inline styles when
autogrowis toggled off (#17535) - fix(QFab): stop forwarding the FAB's own props to the trigger button -> every FAB shipped an anchor carrying invalid DOM attributes like
direction="up"andlabelposition="right" - fix(ui): QFab/QFabAction internal top/bottom label was never stacked -> an internal
label-position="top"/"bottom"laid icon and label out in a row instead of a column - fix(QColor): drop the dead
hideSelectionprop from the alpha slider - fix(QTree): align dense virtual scroll root leaves with the nested layout
- fix(ui): QVirtualScroll SSR-rendered padding mismatching the client's -> no more "Hydration style mismatch" warning in every SSR app rendering a QVirtualScroll
- fix(ui): Morph SSR hydration class false-positive
- fix(ui): Screen plugin -> honor the documented
config > screen > bodyClasseskey on SSR, which never emitted its body class into server-rendered HTML - fix(ui): widen
useQuasar()'sinject()fallback past the no-instance case - fix(ui): actually print the UMD missing-Vue guidance error -> it was dead code behind a cryptic "Cannot read properties of undefined" throw
Other
- Test infrastructure: SSR hydration coverage for every component and directive (with a Quasar-config and icon-set install axis), a hydration sweep over the playground, a UMD suite running the built bundles under both global Vue builds, a cross-engine regression sweep page, and an
[Accessibility]category in the Specs workflow
Donations
Quasar Framework is an open-source MIT-licensed project made possible due to the generous contributions by sponsors and backers. If Quasar is useful in your workflow and you want to support ongoing maintenance, please consider the following:
- QMenu no longer claims
-
2.24.005 Aug 2026Nothing published for this version
-
2.23.503 Aug 2026Nothing published for this version
-
2.23.431 Jul 2026Nothing published for this version
-
2.23.328 Jul 2026Nothing published for this version
-
2.23.227 Jul 2026Nothing published for this version
-
2.23.124 Jul 2026Nothing published for this version
-
2.23.024 Jul 2026Nothing published for this version
-
2.22.021 Jul 2026Nothing published for this version
-
2.21.416 Jul 2026Nothing published for this version
-
2.21.313 Jul 2026Nothing published for this version
-
2.21.210 Jul 2026Nothing published for this version
-
2.21.106 Jul 2026Nothing published for this version
-
2.21.003 Jul 2026Nothing published for this version
-
2.20.302 Jul 2026Nothing published for this version
-
2.20.230 Jun 2026Nothing published for this version
-
2.20.116 Jun 2026Nothing published for this version
-
2.20.011 Jun 2026Nothing published for this version
-
2.19.306 Apr 2026Nothing published for this version
-
2.19.226 Mar 2026Nothing published for this version
-
2.19.124 Mar 2026Nothing published for this version
-
2.19.024 Mar 2026Nothing published for this version
-
2.18.717 Mar 2026Nothing published for this version
-
2.18.613 Nov 2025Nothing published for this version
-
2.18.518 Sep 2025Nothing published for this version
-
2.18.417 Sep 2025Nothing published for this version
-
2.18.316 Sep 2025Nothing published for this version
-
2.18.220 Jul 2025Nothing published for this version
-
2.18.106 Mar 2025Nothing published for this version
-
2.18.001 Mar 2025Nothing published for this version
-
2.17.718 Jan 2025Nothing published for this version
-
2.17.603 Jan 2025Nothing published for this version
-
2.17.514 Dec 2024Nothing published for this version
-
2.17.418 Nov 2024Nothing published for this version
-
2.17.316 Nov 2024Nothing published for this version
-
2.17.206 Nov 2024Nothing published for this version
-
2.17.119 Oct 2024Nothing published for this version
-
2.17.017 Sep 2024Nothing published for this version
-
2.16.1106 Sep 2024Nothing published for this version
-
2.16.1004 Sep 2024Nothing published for this version
-
2.16.915 Aug 2024Nothing published for this version
-
2.16.807 Aug 2024Nothing published for this version
-
2.16.705 Aug 2024Nothing published for this version
-
2.16.610 Jul 2024Nothing published for this version
-
2.16.503 Jul 2024Nothing published for this version
-
2.16.414 May 2024Nothing published for this version
-
2.16.313 May 2024Nothing published for this version
-
2.16.208 May 2024Nothing published for this version
-
2.16.107 May 2024Nothing published for this version
-
2.16.006 May 2024Nothing published for this version
-
2.15.423 Apr 2024Nothing published for this version
-
2.15.318 Apr 2024Nothing published for this version
-
2.15.229 Mar 2024Nothing published for this version
-
2.15.114 Mar 2024Nothing published for this version
-
2.15.012 Mar 2024Nothing published for this version
-
2.14.708 Mar 2024Nothing published for this version
-
2.14.629 Feb 2024Nothing published for this version