fix(deps): update dependency quasar to v2.32.2 #2
No reviewers
Labels
No labels
bug
dependencies
documentation
duplicate
enhancement
good first issue
help wanted
invalid
javascript
question
wontfix
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set
Reference
Griefed/serverpackcreator-de!2
Loading…
Reference in a new issue
No description provided.
Delete branch "renovate/quasar-2.x"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
This PR contains the following updates:
2.11.10→2.32.2Quasar: Prototype pollution in the extend() utility
CVE-2026-73647 / GHSA-3r53-75j5-3g7j
More information
Details
Summary
quasar@2.20.1, the latest published version at the time of testing, appears to be vulnerable to prototype pollution through the publicextend()utility exported from the package root.When
extend(true, target, source)is used for a deep merge, attacker-controlled object keys are recursively copied into the target object without blocking prototype-pollution primitives such as__proto__,constructor, orprototype.This can allow attacker-controlled properties to be written to
Object.prototype.Details
Affected source:
Distributed files include:
The package root publicly exports
extend. During deep merge, source object keys are recursively assigned into the target object. If the source object contains an own__proto__property, the merge can descend into the prototype object and assign attacker-controlled properties ontoObject.prototype.PoC
Observed output:
Expected output:
Impact
This is a prototype pollution vulnerability.
If an application passes user-controlled or partially user-controlled objects into
extend(true, ...), an attacker may be able to polluteObject.prototypein the same JavaScript process.Depending on how the polluted property is later consumed, this may lead to logic bypass, unsafe default option injection, denial of service, or other application-specific security impact.
Suggested Fix
Reject or safely ignore dangerous keys before assignment, including:
The merge implementation should also avoid descending into prototype-related properties during recursive merge.
Severity
CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:L/I:L/A:LReferences
This data is provided by OSV and the GitHub Advisory Database (CC-BY 4.0).
Quasar Framework: Stored/Reflected XSS via unescaped SSR meta tag rendering in getHead()
CVE-2026-106102 / GHSA-pq96-jpmf-w254
More information
Details
Vulnerability Details
File:
ui/src/utils/meta/Meta.js— actuallyui/src/plugins/meta/Meta.js(lines 149-176:getAttr()andgetHead())Sink:
injectServerMeta()(same file) →ctx.headTags += getHead(data), interpolated verbatim into the raw HTTP response<head>by the production SSR template (app-vite/templates/entry/ssr-prod-webserver.js+app-vite/lib/plugins/vite.html.js)Entry point: the public
useMeta()composable (ui/src/composables/use-meta/use-meta.js) — the single documented way apps set page title/meta/link/script tagsRoot Cause
getHead()is Quasar's SSR-only serializer that turns the meta/link/script/title data collected from everyuseMeta()call into a literal HTML string, using plain template-literal interpolation with zero HTML-entity escaping and zero attribute-quote escaping:Contrast this with the client-side equivalent,
apply()(same file, used only in the browser post-hydration), which builds the same tags viadocument.createElement(...)+tag.setAttribute(att, val)— the browser DOM API automatically escapes attribute values, so the client-side path is not vulnerable.getHead()is a separate, parallel implementation for the SSR case that never received the same protection.Any string containing
</title>,", or>in atitle,meta.*.content,link.*.href, or any other attribute value passed touseMeta()breaks out of its intended HTML context and injects arbitrary markup — including a live<script>tag — directly into the raw HTML response sent to every visitor.Attack Scenario
useMeta()pattern — e.g.useMeta(() => ({ title: post.title, meta: { description: { name: 'description', content: post.excerpt } } }))for a blog/CMS/product page.My Post</title><script>alert(document.cookie)</script>.getHead()emits this payload unescaped directly into the<head>of the raw HTML response.<script>executes immediately, before hydration, with full access todocument.cookieand the DOM.Impact
useMeta()— an extremely common pattern, e.g. blog titles, product names, user display names)useMeta()use case (rendering any dynamic title/description), so it can be triggered even by ordinary content containing&,<, or"without malicious intent, in addition to being trivially exploitable deliberately.Vulnerable Code (
ui/src/plugins/meta/Meta.jslines 149-176)Recommended Fix
Verification
Confirmed end-to-end on v2.21.1 via a local Node.js HTTP lab harness that imports the real, unmodified
Meta.jssource and reproduces the exactuseMeta()→injectServerMeta()call sequence a real SSR app performs, reached via actualcurlrequests (not just isolated function calls):POST /submitwith{"title":"My Post</title><script>alert(document.cookie)</script>","description":"\"><script>alert(document.domain)</script>"}GET /render/1returned a raw HTTP response whose<head>contained:<title>My Post</title><script>alert(document.cookie)</script></title><meta name="description" content=""><script>alert(document.domain)</script>" data-qmeta="description">grep: 0 occurrences of<(nothing was escaped), 1 occurrence of a literal, unescaped<script>alert(...)</script>tag in the actual HTTP response body.A fix branch (
fix/xss-meta-tag-escaping) is ready with the minimal patch above (adds anescapeHtml()helper used ingetAttr()/getHead()); re-running the same PoC against the patched code shows the payload fully HTML-entity-encoded (<script>...) with no live<script>tag, while normal titles containing&still render correctly (&).Severity
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:C/C:H/I:H/A:NReferences
This data is provided by OSV and the GitHub Advisory Database (CC-BY 4.0).
Quasar Framework: Super-linear regex backtracking on User-Agent lets one request stall a Quasar SSR server
CVE-2026-106104 / GHSA-68jq-fhch-4xq4
More information
Details
Summary
One unauthenticated request with a crafted
User-Agentstalls a Quasar SSR server for seconds.Quasar auto-installs its
Platformplugin on every server-side render, andPlatform.parseSSR()feeds the raw, unboundedUser-Agentrequest header into a chain of backtracking regular expressions ingetMatch(). One of those patterns contains a greedy capture followed by two unbounded.*scans, so a crafted header costs time proportional to the cube of its length. An 8 KBUser-Agentblocks the Node.js event loop for about 4.4 seconds, and a 16 KB one for about 35 seconds. During that time the server answers nobody, so a handful of tiny requests take an SSR site completely offline.Details
Platformis in theautoInstalledPluginsarray inui/src/install-quasar.js, so it is installed unconditionally byapp.use(Quasar, ...). The generated SSR entry (app-vite/templates/entry/app.js, called fromapp-vite/templates/entry/server-entry.js) runs that for every HTTP request, and it runs before routing, so requests to paths that do not exist are affected too. On the server the plugin takes the header verbatim (ui/src/plugins/platform/Platform.js):getPlatform()lowercases the string and passes it togetMatch()(ui/src/plugins/platform/Platform.js:23-45), which evaluates an ordered chain ofexec()calls. The sixth alternative, atui/src/plugins/platform/Platform.js:32-34, is the problem:([\w.]+)is greedy and unbounded, and it is followed by two unbounded.*scans. When the input containswebkit/, manyversion/tokens, and nosafari/, the pattern can only fail after the engine has tried every combination of "where([\w.]+)stops" against "whichversionoccurrence the first.*lands on" against "how far the second.*searches forsafari". That is O(k * m * L) states, and none of the earlier alternatives short-circuit it because none of them match. The fifth alternative has the same shape.Measured on the functions loaded verbatim out of
ui/src/plugins/platform/Platform.js, cost grows by a factor of eight for every doubling of the header:A same-length header of ordinary characters costs 0.1 ms, so this is the regex and not the length.
Client-side rendering is not affected: there
getPlatform()only ever seesnavigator.userAgent, which the attacker does not control. The problem is specific to the SSR path, where the string arrives from the network.PoC
The vulnerable pattern ships in the published package. From
node_modules/quasar/dist/quasar.server.prod.jsofquasar@2.23.1:Build the header:
Server used for the end to end run, which performs exactly the per-request work Quasar SSR performs, through the real published package:
Results of driving that server with the 7998-byte header:
Step 5 is the part that matters. The victim sends an ordinary request with an ordinary
User-Agentand waits 4.2 seconds for it, because the event loop is busy backtracking on somebody else's header. Step 6 shows 39 KB of attacker traffic buying 21.6 seconds of total unavailability.Negative control on the library itself. One line changed in the installed
node_modules/quasar/dist/quasar.server.prod.js:Re-running the identical attack against the patched build:
Detection of real browsers is unchanged by the cap (
chrome 126.0.0.0, platformlinux), which confirms the blow-up comes from the unbounded attacker string reaching the regex and nothing else.The same numbers come out of a server that never touches
parseSSRdirectly and instead boots Quasar the way the generated entry does, lettinginstall-quasar.jsrun the auto-installed plugin list on its own:Impact
Uncontrolled resource consumption through inefficient regular expression complexity. Any app built and served in SSR mode is affected, including SSR plus PWA, in both
quasar dev -m ssrandquasar build -m ssr. There is no configuration that turns it off, becausePlatformis part of the auto-installed plugin set, and no authentication or user interaction is involved: a single unauthenticated GET to any path carries the payload.Node.js is single threaded, so the cost is not paid by the attacker's connection alone. Every other visitor is queued behind it. Roughly 40 KB of traffic buys 20 seconds of downtime in the measurements above, and the cost scales with the cube of the header size, so an attacker who can send 16 KB headers gets about 35 seconds per request. Common reverse proxies do not help: nginx accepts an 8 KB header line by default and Node accepts 16 KB.
Apps built for SPA, PWA, Electron, Cordova, Capacitor or browser-extension targets are not affected, since there the parser only ever sees the local
navigator.userAgent. Static site generation is not affected either, because thessrContextused there is supplied by the developer rather than by a request.Severity
CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:N/VI:N/VA:H/SC:N/SI:N/SA:NReferences
This data is provided by OSV and the GitHub Advisory Database (CC-BY 4.0).
Quasar Framework: DOM Clobbering in Quasar openURL() SafariViewController Integration Causes Client-Side Denial of Service
CVE-2026-106101 / GHSA-89vp-x45c-52cq
More information
Details
Summary
A DOM Clobbering vulnerability exists in Quasar's
openURL()utility when handling the iOSSafariViewControllerbridge.The vulnerable implementation only checks whether
window.SafariViewControllerexists before invoking it as a native bridge object. An attacker who can inject HTML content containing a named element such as<a id="SafariViewController">can cause the browser to expose that element aswindow.SafariViewController.When
openURL()is later called in an iOS environment, Quasar incorrectly treats the DOM element as the native bridge object and attempts to invoke bridge methods that do not exist, resulting in:This can cause client-side denial of service and break navigation-related workflows in Quasar applications.
Details
Quasar provides the
openURL()utility to open external URLs. On iOS platforms, this utility supports integration with the nativeSafariViewControllerbridge.The vulnerable code is located in:
The affected logic is:
The issue is that Quasar only verifies that
window.SafariViewControlleris notundefined. It does not verify whether the value is the expected native bridge object or whether required methods such asisAvailable()andshow()are valid functions.Modern browsers expose elements with specific
idornameattributes as properties of the globalwindowobject. Therefore, attacker-controlled HTML such as:can cause:
to resolve to an
HTMLAnchorElementinstead of the expected native bridge object.When Quasar later executes:
the DOM element is incorrectly treated as the bridge object, causing:
The root cause is insufficient validation of browser-controlled global properties before using them as trusted native bridge objects.
The vulnerability was verified through the Quasar
QEditorrendering path. When attacker-controlled HTML content is rendered into the DOM and creates theSafariViewControllernamed element, subsequent calls toopenURL()fail.Additional component-level affected paths were identified in
QSelectandQChatMessagewhen applications enable HTML rendering features and provide attacker-controlled content. These paths require specific application configurations and were not used as the primary end-to-end reproduction.PoC
Steps to reproduce
QEditor.The value resolves to the injected DOM element instead of the expected native bridge object.
The URL opening workflow fails because Quasar attempts to invoke native bridge methods on the DOM element.
The same underlying issue can also affect other HTML rendering paths such as
QSelectandQChatMessagewhen attacker-controlled HTML is rendered and the application later callsopenURL().Impact
This vulnerability is a client-side DOM Clobbering and type confusion issue affecting Quasar applications that use the iOS
SafariViewControllerintegration. An attacker who can control HTML content rendered into the application DOM may cause Quasar'sopenURL()functionality to fail by replacing the expected native bridge object with a DOM element through browser named property resolution.Potentially affected workflows include external URL navigation, OAuth/login redirects, help or documentation links, payment flows, third-party service redirects, and other application actions that rely on URL opening functionality.
The confirmed impact is client-side denial of service and navigation or workflow disruption. When the vulnerable condition is triggered, Quasar throws an exception while attempting to invoke methods on the clobbered
SafariViewControllerobject, preventing the expected URL opening behavior.Severity
CVSS:3.1/AV:N/AC:H/PR:N/UI:R/S:U/C:N/I:N/A:LReferences
This data is provided by OSV and the GitHub Advisory Database (CC-BY 4.0).
Release Notes
quasarframework/quasar (quasar)
v2.32.2Compare Source
Security fixes
<a id="SafariViewController">through QEditor, or QSelect / QChatMessage with HTML rendering enabled) shadowed the native bridge global, so every lateropenURL()call threwTypeError: window.SafariViewController.isAvailable is not a functionand the URL never opened.openURL()now hands the URL to the bridge only when it exposes the expectedisAvailable()andshow()functions, and opens a regular window otherwise (GHSA-89vp-x45c-52cq)Fixes
framework.config.globalNodes-> the option has been honored since #8634 (it sets the CSS class of the nodes Quasar appends to<body>for portals, Notify, Loading and LoadingBar) but was never declared inQuasarUIConfiguration, so a typedquasar.configfile orapp.use(Quasar, { config: { globalNodes } })rejected it. It is typed now, with itsclassmember documentedDonations
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:
v2.32.1Compare Source
Changes
groupthat both start withmodel-value: true(ordefault-opened) threw on mount since v2.32.0 and were left with every body visible under a collapsed header. The group sibling that has to close is now settled closed before its content element is ready, withafter-hideemitted as usual (#18547)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:
v2.32.0Compare Source
New
ssr-prerender-> until now QImg only set the image source once the client had mounted, so under SSR/SSG the browser started fetching it after the JS bundle had downloaded and the app had hydrated: the preload scanner never saw it, crawlers and no-JS clients got an empty box, and any hero image behind QImg was a late LCP by construction. The server and the pre-hydration client now render the<img>themselves, visible from the first paint like a native image, with the placeholder underneath; on mount the component reconciles against the element it finds instead of trusting load events, so an image that finished before hydration still goes through the regular load (or error) path. Only images whose box shape is known (ratio,initial-ratioorheight) are server-rendered by default, since otherwise the box would visibly snap from the default ratio to the natural one at hydration; the newssr-prerenderBoolean prop opts the rest inpanevent with the stage of the swipe gestures -> the swipe-to-open and swipe-to-close gestures ran silently: an app could only learn that the drawer had opened or closed after the fact, through the model and theshow/hideevents, never that a swipe was in progress, so content mounted on open only came in once the drawer had already been dragged fully into view and the swipe itself showed an empty panel. QDrawer now emitspanwith the gesturetype('open'or'close') and itsstage:'start'once the pan is detected,'end'when it crossed the threshold andshow()/hide()ran,'cancel'when the finger let go short of it and the drawer sprang backrefresh()method -> everything the component settles at mount (the scrolling container and the way the media is moved along it, the media size, the position) was only re-checked on the events it listens to, so an ancestor changing itsoverflow, a media swapped without a load event or ascroll-targetthat only appears later left it stale with no way to tell it so.refresh()re-runs all threeOther
Element.animate()on aViewTimelineof the component root wherever the API exists and nothing scrollable sits between the root and its scroll target. The browser then moves it on its own thread, in step with the scroll whatever the main thread is doing, where the JS tracking wrote its transform a frame behind (one scroll step off in every other compositor frame) and stalled together with the main thread; the keyframes carry the exact numbers the JS tracking used, so the movement itself is unchanged. On that path the component registers no scroll or resize listener and no IntersectionObserver at all, the tracking being created only where thescrollevent or thecontentslot needs the percentage, and there it reads the timeline's own progress instead of measuring. Firefox, and any layout the timeline cannot express (anoverflow: hiddenwrapper, ascroll-targetthat is not the nearest scroll container), keep the JS tracking, itself now measuring once per frame instead of once per scroll event. The media is also no longer left hidden until the first measurement, and a media without a natural size yet no longer measures adisplay: noneboxcalc-size()is supported -> the height slide (so QExpansionItem, QTree and the vertical QStep) measured the content on every toggle, onescrollHeightread on show and two on hide, each forcing a layout: toggling N nodes in one tick (QTree expand/collapse all, filtering) forced N layouts on show and 2N on hide. Where the engine sizes acalc-size(auto, size)keyframe at layout (Chromium 129+) the slide is now anElement.animate()between 0 and that keyframe: no measurement, no forced layout, the height tracked live while sliding, and an interrupted slide of a kept element played backwards. Engines withoutcalc-size()keep the measuring CSS transition, untouched. Chromium 153 headless, 200 boxes toggled in one tick: forced layouts on show 219 -> 20 and on hide 418 -> 19, layout time 13.7ms -> 8.4ms and 22.2ms -> 6.3msv-show. They now call the slide engine on the element themselves. Chromium 153 headless, a QTree with 780 nodes (155 parents) mounted expanded, median of 12 mounts: 43.1ms -> 32.3msfield-sizingwhere supported -> autogrow textareas now getfield-sizing: contentand skip the JS measuring routine entirely on browsers that implement the property: no rAF layout thrash per keystroke, no inline height/overflow writes, noscrollTopjuggling, and the browser handles amax-heightwith native scrolling. Browsers below the property's floor (Chromium before 123, Safari before 26) keep the routine, which also coalesces to one measurement per frame now (a keystroke used to schedule two) and cancels a pending frame when autogrow turns off or the component unmounts. Height parity between the two paths was verified in Chromium, Firefox and WebKit across plain, labeled, outlined, filled, dense, max-height and custom font-size casesaspect-ratio-> thepadding-bottompercentage hack needed a dedicated filler element in QImg and QResponsive (plus a width-inheriting wrapper in the latter) and a zero-height root in QVideo.aspect-ratiois under the Baseline floor, so the ratio now sits on the root element itself and those nodes are gone: one element fewer per QImg, two fewer per QResponsive. See the note at the topDonations
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:
v2.31.0Compare Source
New
paletteslot, and the picker is fully keyboard-accessible -> the palette view had no way to be customized: swatches were plain divs, laid out 10 per row, reachable by pointer only. The new scopedpaletteslot replaces the default swatches while keeping the other views and the view switcher, handing over the resolved colors (palette), aselect(color)function and aneditableflag. The default swatches become buttons following the roving tabindex pattern (arrows move, Up/Down by one visual row, Home/End jump to the edges, Enter/Space picks), and the spectrum panel, the last pointer-only part of the picker, becomes a WAI-ARIA slider over its two axes: arrows step the saturation and the brightness by one, ten with Shift, Home/End and PageUp/PageDown jump. Both follow the visual direction in RTL, both draw a two-tone inset focus ring that stays visible on any color, and the spectrum spells out its value through two new lang-pack keys,colorPicker.saturationandcolorPicker.brightness, translated across every pack (#8613)$shadow-color/$dark-shadow-colorSass variables, so the UMD build, the Vite plugin and every other prebuilt-CSS flavour had no way to revert or tune it short of restyling each component. Both colors are now declared on:rootas--q-shadow-colorand--q-dark-shadow-color, with the Sass variables as their defaults so existing Sass overrides keep working. Nothing moves by a pixel out of the box, and the pre-v2.11 look is a one-liner (body.body--dark { --q-dark-shadow-color: #​000 });transparentremoves the shadows altogether. The tints are derived onbody, so the tokens are read at the:root/bodylevel (abody.body--darkrule,setCssVar()), not on a deeper element (#15144)formatNumberpack key, localized digits in QDate, QTime and QPagination -> a Persian calendar coupled with thefa-IRpack showed Persian month names next to Western day numbers, with no way to change that short of a font that remaps the ASCII digit glyphs. Language packs (and thelocaleprop) can now define an optional root-levelformatNumber(value), which receives the ASCII digit string the component would display, zero-padded where it is padded ("5", "05", "1403"), and returns the localized rendering. QDate routes its day cells, navigation year, years grid, header title and subtitle, the "N days" count and the day buttons'aria-labelthrough it, QTime its header units and clock face, QPagination its page buttons and theiraria-label. Model strings, date hashes and QTime'sstringModelstay ASCII. Thefaandfa-IRpacks opt in; every other pack is unchanged (#12735)autoWidthin the column definition -> shrinking a column to its content required a per-columnheader-cellandbody-cellslot override with<q-th auto-width>/<q-td auto-width>, cumbersome for dynamically built columns, the only alternative being an undocumented class throughclassesandheaderClasses. A column can now simply declareautoWidth: true, which applies to the auto-rendered cells as well as to QTh/QTd fed with the slot props (#8206)Fixes
v-close-popupthat opens a dialog made the two portals compete for focus, and the closing one won on both counts: the dialog opened without focus in its autofocus field (on Android the soft keyboard never showed), and it had captured, as the element to return focus to, an element inside the closing portal, destroyed with it, so closing the dialog dropped focus altogether. A portal closing while another one sits on top of it in its opening transition now hands its own anchor to the opener instead of restoring focus itself; portals that take no focus (no-focus, hover-shown menus) or that are already fully open decline the hand-off, so everything else is unchanged (#8211)readonlywas still true got dropped and nothing re-synced afterwards: a handler flippingreadonlyoff and callingfocus()in the same tick left the input holding DOM focus with the field unfocused, label resting over the caret. The gate itself was the problem, not its timing, since a readonly control stays in the tab order and a keyboard user tabbing onto it got no visible focus indication at all. The focused state now mirrors DOM focus, onlydisablekeeping a field from counting as focused. See the note at the top (#16056)controlslot wrapper to the control -> with acontrolslot, autofocus,focus()and every other way of focusing the field (QForm/QDialog/QMenu autofocus,clearValue, a click around the control) landed on theq-field__nativewrapper: the field looked focused and emittedfocus, but the slotted control never received the caret. The wrapper now forwards any focus it receives to the element bound to the slot scope id, else to the first focusable element of the slot, and keeps it only when the slot holds nothing focusable (#12648)backface-visibility: hidden, which Chromium answers with a permanent compositor layer per label. With a few hundred fields on a page each hover repaint re-runs the layer assignment pass against all of those interleaved layers and it goes quadratic: on the reported layout (100 rows x 5 labelled number inputs) headless Chromium held ~22 fps with 50-67 ms frames while native inputs held 60. The rule dates from the Qv1 stylesheets with no recorded purpose and the settled label renders pixel-identical without it. Measured after: 6 composited layers instead of 461, ~65 ms of Layerize per hover sweep instead of ~1.7 s (#16024)new-value-mode/@new-value, Enter or Tab then re-selected that option and silently dropped the text the user had just typed,@new-valuenever being emitted. The highlight now remembers whether it was placed automatically or by the user, and only the automatic one yields to typed text under new-value mode: navigated or hovered options still win,fill-input's filled-in label is not user text so Enter right after opening still re-selects, and selects without new-value mode never consult it (#16514)$q.screen(:vertical="$q.screen.lt.sm") lost the active step's content, form state included, whenever the viewport crossed the breakpoint, andkeep-alivecould not bridge it either, the two orientations rendering different trees with two different caches. Both orientations now render every QStep under.q-stepper__content, with one plain Transition per step driving the vertical height slide and the horizontal slide alike.keep-alive-max, which the vertical mode never honoured, is now counted by the stepper itself, and the stepper'stransition-durationalso drives the vertical slides (default unchanged). See the note at the top (#9703)active-icon="none"-> the header decided the dot's content with two computeds that disagreed on which state wins, so an active step that also haderror, withactive-iconset tonone, got neither the icon nor the prefix and the dot was left empty; a step-levelactive/error/done-iconofnonehit the same blank. The state icon is now resolved once, with the step prop taking precedence over the stepper one, and both the prefix decision and the rendered icon derive from it (#15259)--q-drawer-widthcustom property, documented as usable by user CSS, and the mini rule sizes the item from it, so 24px icons land on the standard inset at any scale factor, bordered or not (#18320)position: fixed, which collapses the root element to zero height, and a body background propagates to the canvas with the root box as its positioning area: a gradient or a cover-sized image stopped painting the moment a popup locked the page, showing a blank canvas behind the dialog. A solid color needs no positioning area, which is why the default dark page never showed it, and desktop and Android use the viewport clip lock, so only iOS was affected. The lock class now gives the root elementmin-height: 100%,min-heightso userhtml { height }rules still win (#16799)offsetWidth/offsetHeight, the border box, but observed the default content box, so a padding or border change on the observed element itself grew the border box without touching the content box and no notification fired. QHeader, QFooter and QDrawer size the layout through it, so apadding-top: env(safe-area-inset-top)rule placed on.q-header(the iOS PWA status-bar pattern) left QPageContainer with a page padding that ignored the inset until the device rotated. Padding on the toolbar child, which is what Quasar's ownq-ios-padding/q-safe-area-paddingrules use, was already tracked (#7526)q-mt-mdcard, say) collapsed through it and pushed the page down inside QPageContainer; together with the page'smin-heightthe layout then exceeded the viewport and the window grew a scrollbar even when the content fit the screen. A last child's bottom margin did the same at the other end. The page now establishes a block formatting context, through a zero-specificity rule so display utilities on the page and user overrides keep winning (#9536)'auto'resolves on SSR/SSG clients once they take over -> since v2.18.2 the ssr-client build reads its initial dark state from the server-emitted body class, and the server renders'auto'as light, soconfig.dark: 'auto'ended up as a plainfalseon every SSR/SSG app: no media query listener, light forever. The server now flags an'auto'render with a body attribute, and the client resolves it on takeover unless the app already set an explicit value meanwhile. A SSR+PWA shell boot, which has no server markup to read, starts from the config like an SPA does; the config was silently dropped there too. See the note at the top (#7530)immediateoption could re-enter itself from within its own invocation and fire again instead of being held back for the wait period (#18544)morph()defers its work to arequestAnimationFramecallback, and when the destination's subtree was removed in between (av-ifor an unmount in the same tick as the model change) the validity check still accepted it, because a detached subtree keeps itsparentNode, and the fixed-position parent walk then reachednulland threw insidegetComputedStyleOther
errorprop rendered a Transition component around its messages element, only to animate the hint-to-error swap. With Vue 3.5 that instance is about a quarter of a QInput's mount JS (2000 labelled inputs with hints: 148 ms to 113 ms on Chromium), and it was the single biggest item in the reporter's own devtools timeline. The messages element is keyed by its content, so a swap already re-creates it, and a keyframe on the new element reproduces the enter half of the old transition; nothing animates on page load and no field gets a composited layer at mount. See the note at the top (#12369)quasar devcompiles the Sass verbatim, so dev servers paid for a layer per radio, checkbox, toggle, slider ring, linear progress, date indicator, tree arrow, spinner and notification badge; the JS-built strings (QLinearProgress, QCircularProgress and through it QKnob, QAjaxBar, Ripple, QTabs' indicator) reached production as written, so those are a production win too. Every value is rewritten as its exact 2D equivalent and the minifiedquasar.prod.css/quasar.rtl.prod.cssare byte-identical before and after. QLayout's layer hack and QParallax's media transform stay 3D on purposeDonations
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:
v2.30.1Compare Source
Fixes
updated/beforeUnmount-> Vue defers a directive'supdatedto the post-flush queue but runsbeforeUnmountsynchronously, so a queuedupdatedcan outlive the element's unmount and find its context already gone. v2.30.0 dropped the early return that covered this, and the hook threw aTypeError. In production Vue logs it; in development it rethrows,flushJobsnever clearscurrentFlushPromiseand nothing reactive is ever flushed again, freezing the app on whatever was painted. Reported for the four touch directives (a QScrollArea inside<keep-alive :include>, dropped from the cache in the same tick it re-renders), the guard is restored across all eleven:v-close-popup,v-intersection,v-morph,v-mutation,v-ripple,v-scroll,v-scroll-fireandv-touch-hold/v-touch-pan/v-touch-repeat/v-touch-swipe(#18543)@loadand renders a loading placeholder taller thanoffsetwhile that runs (from its ownmountedhook, anextTickor an async component) had already grown the content by then, so that report read "out of reach" and an observer never re-reports a state that merely holds:@loadnever fired and the placeholder waited for data nobody had asked for. The first load is decided on mount again, off the DOM as it stands, by the same reach test the observer applies, and it is no longer routed through the debounced poll, so a paused fake clock (Playwright'spage.clock) does not hold it back either. A component mounted out of reach stays quiet as before, and the observer still owns every load after the first (#18542)v-ripplere-read its argument and modifiers only when the value reference changed and only for an object value, so three things were frozen at mount:v-ripple:[color]with no value never picked up a new color, a modifiers object that changed while the value did not was ignored (QBtn hits this on its own, so toggling itsroundprop left the ripple starting from the press point instead of the center, or the other way round), and setting the value back totrueafter an object kept that object's options. All three now re-derive (#18541)deepEqual()handles null-prototype objects -> comparing two objects created withObject.create(null)threw, because thevalueOffallback saw a missing method as an override ofObject.prototype's and called it. Both conversion fallbacks now require an actual callable on both sides, so null-prototype objects, and objects whose ownvalueOf/toStringis not a function, compare by their keys. Two objects of the same constructor where only one carries such an override are compared key by key too, instead of through that one side's conversion (#18540)header-<name>slot defaults styled.q-iconand.q-avatarinside the node header at a specificity that tied with each component's own icon sizing and won on source order, so a QBtn placed in a header slot rendered a fixed 21px icon whatever itssizeprop said. The defaults are scoped through:where()and lose every tie, while still applying to plain slot icons (#16753)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:
v2.30.0Compare Source
New
useIntersection()composable -> observe any element's visibility fromsetup()with a plain object, a ref or a getter (target,root,rootMargin,threshold,once,disabled,onIntersect), getting back a reactiveisIntersectingand astop(). The observer pool behind it is now shared by the composable,v-intersectionand QIntersection (rebuilt on top of the composable), so a page mixing the three with the same options runs a single IntersectionObserversideprop, pull from any edge of the content to refresh -> the pull can start from thetop(the default, unchanged),bottom,leftorrightof the content, as an inward pan from that edge while the scroll target sits at it.bottomis the messenger case,left/rightserve horizontally scrolling content (#7599)cursor-positionprop, position the tooltip at the pointer -> on a large trigger a tooltip placed against the anchor's box ends up far from what the user is pointing at, which is why the nativetitleattribute opens at the cursor. The pointer becomes the anchor point (anchorno longer applies,selfandoffsetkeep working), after waiting for the pointer to settle so a tooltip opening mid-sweep can't freeze at a point already left behind; a touch or stylus press opens at the contact point without waiting, and a keyboard focus or a bare model toggle keeps the regular anchor-relative placement (#6019)overflow: hiddenon desktop, so the only way to reach offscreen tabs was the arrow icons and a horizontal trackpad swipe or a wheel tilt did nothing. It now scrolls on its own axis on every platform, the cross axis staying hidden, the scrollbar staying invisible and the arrows still tracking the position. Vertical wheel over horizontal tabs is deliberately not remapped, so a tab bar in a page never captures the page scroll (#7404)staggerprop -> each action fades and scales on its own, cascading outwards from the trigger when opening and back towards it when closing, which is the Material speed dial behavior.staggersets the milliseconds between consecutive actions (default 40; 0 animates them all at once); the delays are derived in CSS withsibling-index(), so no number of actions is special-cased and browsers predating those functions simply animate the actions together (#6413)ellipsisslot to replace the "..." buttons -> the ellipsis buttons were hard-wired to jump to the first hidden page on their side and there was no slot to attach anything else. The slot replaces the button entirely and hands over{ side, page, btnProps, onClick }(plustowhento-fnis set);btnPropsreplicates the default button but carries neither the click handler nor the router target, so spreading it onto a QBtn hosting a QPopupEdit does not also trigger the jump. Without the slot the rendered output is unchanged (#11341)dropdown-hover,dropdown-hover-delayanddropdown-hover-hide-delayprops are forwarded to the QBtnDropdown of every toolbar dropdown. Click, tap and keyboard interactions keep toggling as before, and touch devices fall back to themextractDate()parses ISO week dates -> the week (w/wo/ww), ISO week year (GG/GGGG) and day of week (d/do/E/ddd/dddd) tokens were emitted by the parser but never mapped, so aGGGG-[W]ww-Emask resolved to Jan 1st 1900 instead of the day it described and twelve formatting tokens could not survive aformatDate()round trip. A mask carrying a week number now resolves as an ISO week date, an explicit calendar day still winning. See the note at the top (#7732)v-intersection, QIntersection anduseIntersection, clipping through every scrollable ancestor up to the viewport, and takes the fraction of the element that must be visible as an argument (v-scroll-fire:0.5, default 0). See the note at the top.mouseon a device without touch) can be armed later. The notes are gone from the four pagesscroll-targetprop accepts a Vue component reference, standing for its root element -> QInfiniteScroll, QScrollObserver, QVirtualScroll, QParallax, QPullToRefresh, QTree and QTable share the prop, and the resolver behind it has always unwrapped a component instance to its root element, but the prop type rejected it: in production it worked, in development Vue's prop validation refused it and building the warning threw ("Cannot convert object to primitive value"), aborting the update. A value without a root element now falls back to auto detection with a warning naming the causequasar.configspinner of Loading and Notify is typed by name ->framework.config.loading.spinnerandframework.config.notify.spinnertake a spinner's name ('QSpinnerGears'), which the CLI imports for you, but the typing dropped both keys altogether, so naming a spinner there was a type error.quasarnow also exports theQuasarSpinnersunion of the spinner component namesFixes
rootBoundsfrom a cross-origin iframe for every entry of the viewport root, and a 2020 guard read that null as the element having been caught out of the DOM by a Vue transition, re-observing forever. So inside Codepen, jsFiddle and StackBlitz previews nov-intersectionor QIntersection handler ever ran, since 2020 (the docs advised therootprop as a workaround and Codepen was disabled on the examples). Firefox was unaffected. The guard is dropped, the docs' workaround paragraph with it, and the Intersection examples get their Codepen link backmousedownandtouchstartonly, so a page cancellingpointerdown(Cesium does it on every mouse press with a registered action) suppressed the compatibilitymousedownand the popup stayed open, in every engine. QSelect's dropdown got stuck along with it. A mouse or penpointerdownnow arms a 0ms fallback that themousedownof a normal press cancels in the same task, so every existing path is unchanged (#12575)top/left, so a popup with a bottom or right self origin kept its top edge frozen: content growing after the decision extended it over its own anchor until the next pass re-derived the position and it jumped. The engine now writes its inset from the edge the self origin anchors, like the native onemax-height/max-widthprops, the stylesheet ceilings ($menu-max-height, ...) and any app CSS at once. Before the amendment a flip towards a roomier side could widen the popup past those bounds (#18536, #18537)center/middlehad no viewport correction at all, and now shifts back inside the viewport, frozen at decision time. The offset was applied with a fixed positive sign whatever the self origin, so a popup growing up or left opened onto the coordinate instead of clearing it; it now carries the sign of the direction the popup grows. Visible today for a QMenu opened at a coordinate. See the note at the topdisable/readonlyin the toolbar, keep the fullscreen root opaque ->getBtn()overwrote the editor-wide disabled state with the per-button definition, so every plain toolbar button of a disabled or readonly editor stayed actionable (only the dropdowns behaved), which is how a disabled fullscreen editor's fullscreen button could be clicked.readonlykeeps the read-only commands (fullscreen, print, viewsource),disabletakes the whole toolbar out of play. The global.disabledrule also sat on the root, which in fullscreen is a viewport-sized fixed element, so the page composited straight through it. See the note at the top (#15486)disable/readonlytoggle, QTabPanels/QStepper/QCarousel destroyed every panel (KeepAlive state included) on aswipeabletoggle, QDrawer re-created its content on ano-swipe-closetoggle and QSplitter its separator slot ondisable. The directive now stays attached and is disarmed in place. QColor's spectrum, QSlider/QRange's track and QDrawer's backdrop got the same treatment internally (#12668, #18535)isFinalpayload never arrived: QSplitter kept its--activeclass and dropped theupdate:modelValue, QPullToRefresh stayed in its pulling state, QDrawer's close pan lost its end on a breakpoint crossingv-intersectionaccepted Booleanfalseonly and threw onundefined, andv-mutationtolerated a non-function value only by accident, keeping the observer connected and rebuilding it on every handler change (an inline arrow function on each render). Both now disarm cleanly,v-mutationdropping its observer and only swapping the callback target on a handler change (#18531)inject()fallback factory was never flagged as one, so the function itself landed in$faband a QFabAction rendered outside a QFab crashed instead of showing itself as an enabled, standalone button (#18538)v-morph.tween="{ name, group, model }"lost the tween. The directive modifiers are the base now and the object overrides only the keys it definesdeepEqual()compares binary data by content -> ArrayBuffers, DataViews and typed arrays were compared through the generic object path, and the typed-array branch was duck-typed on a.bufferproperty, so a plain{ buffer: ArrayBuffer }(and DataView) spun forever. Binary views are recognised throughArrayBuffer.isView(), which also covers views over a SharedArrayBuffer, and both sides'byteLengthis compared before anything is allocated (#18539)ComponentInstance, not aComponent-> QFile, QForm, QPopupProxy, QScrollArea, QSelect, QTable, QTree, QUploader, QVirtualScroll anduseVirtualScrollhand over mounted component instances that the generated typings declared with Vue's definition type.Componentstays where a definition really is passed: the plugins'spinneroptions and Dialog'scomponentOther
v-ripple,v-scroll,v-close-popup,v-intersection,v-morphand the four touch directives now share module-level listeners instead of allocating a set of closures per element,v-intersectionshares one IntersectionObserver per distinct config (per-scroll main-thread time on 3000 observed elements 4.1ms -> 2.5ms) andv-scrollone listener per target (2000 elements on window: mount 8.9ms -> 2.0ms, unmount 8.3ms -> 0.8ms, one scroll event 1.74ms -> 0.08ms). QInfiniteScroll and QPullToRefresh watch the content through the intersection pool rather than a scroll listener and render their indicator in a sub-component, so a load or a pull no longer re-renders the slot content, and QPullToRefresh arms TouchPan only while the pulled edge is on screen, keeping JS out of the touch path of every other scroll gesture. Every template ref in the ui package is ashallowRef()useFullscreen()relocation (#18513)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:
v2.29.0Compare Source
New
clickfrom the handler they bind whileclickable, so a@clickon an item or chip without that prop was dead code. See the note at the top (#16731)getClosestIsoName()maps a locale to the nearest language pack -> language packs carry a region subtag only when a language ships more than one translation, so a browser locale likees-MXorsr-Cyrl-RShas no pack of its own and every app hand-maintained a locale-to-pack map.Lang.getClosestIsoName(locale, isoNames)(also on$q.lang) picks the closest of the packs your app ships: exact match, then the RFC 4647 lookup chain with the script outranking the region (sr-Cyrl-RSreadssr-Cyrl,zh-Hant-TWreadszh-TW), then the CLDR likely subtags (zhreadszh-CN,ptreadspt-BR,de-ATreadsde-DEoverde-CH). Malformed entries are skipped, so alang/*.jsglob's deprecated files do no harm, andgetLocale()can be passed straight in. The docs' dynamic boot-file recipe now uses it (#12174)Fixes
blurand ran lazy validation (an empty date input went red just for opening the picker). QMenu and QDialog dispatch bubblingpopup-show/popup-hideDOM events again, the way Quasar v1 did, and QField holds its focused state, styling and lazy validation until the popup hides. Hover-shown menus and tooltips take no focus and stay silent (#9779)position: fixeddialog is attached to, and it reveals the focused field only for a user-initiated focus, so a field focused programmatically (autofocus or a.focus()call) opened the keyboard with a bottom-anchored dialog left entirely underneath it. QDialog now tracks the visual viewport while shown on iOS and insets its inner element to it. Verified on the iPhone 17 Pro simulator (#17594)100dvhnow and the platform override is goneoffsetWidth, which rounds each one up, so three justified tabs in a 440px container summed to 441,scrollableflipped on, the tabs collapsed to their natural width and nothing re-measured. It repeated at every third pixel of width, which is the on/off alternation of the report. Tabs are now measured withgetBoundingClientRect()and an overflow of a pixel or less is never treated as scrollable (#18532)offsetHeightas 29, so the paddings standing in for the items outside the slice put the content half a pixel per item off on every re-slice and the rows visibly jittered while scrolling, worse the deeper into the list. Both directions measure throughgetBoundingClientRect()now (#15754)$q.screenand the CSS breakpoints. A standard layout now reports$q.screen.width; containerized layouts are unchanged (#15506)disableis toggled -> all three baked!disableinto the root vnode key, so flipping the prop destroyed and rebuilt the whole subtree instead of leaving the content as it was. Disabling now travels through the directive value. One related change: with QIntersection'sonce, an observer that has already fired is no longer re-armed by togglingdisableoff and on, which was a side effect of the remount and contradictedonce(#12668, #18531)overflow: clip, which is not a scroll container; layout is unchanged (#17464)ssrContext-> Node (and Vitest) resolvequasarthrough thenodeexport condition to the SSR build, so a test setup that does not go through @quasar/vite-plugin installed it and crashed with "Cannot convert undefined or null to object". The error now explains what happened and how to fix it, and the Vite plugin docs gained a "Testing with Vitest" section (#15469)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:
v2.28.0Compare Source
Perf
New
position-anchor/anchor()insets, so the browser keeps it glued through any scroll, layout shift, resize or animation with zero listeners. Every other engine keeps the JS positioning engine, whose behavior was aligned with the native one so a flip in Chromium and a flip in Safari are the same flip by construction. Menus now follow ANY scrolling container on both paths, ending the long-standing "the menu only follows a container carrying thescrollclass" limitation (the #8343 family)hover,hover-delayandhover-hide-delayprops, the same contract QMenu, QBtnDropdown and QFab settled on. A hover-shown open never steals focus and never pretends to be focused, so a pointer merely passing over the select emits no focus/blur and cannot trip lazy validation;@filterselects still load their options on hover. A real click or Tab upgrades the show to a regular focused open (#11675)behavior="dialog"finally has a visible dismiss affordance, a labeled button in the in-dialog control row where the dropdown arrow would sit, so the software keyboard can never cover it. Follows thecolorprop, styleable throughq-select__dialog-close, opt out with the newhide-dialog-closeprop (#6858)no-chip-removeprop -> withuse-chips, drops the chips' remove icon and disarms the chip-armed Backspace removal, so a select that must always hold a value is possible with chips.clearable's own affordances stay intact when explicitly enabled alongside it (#17937)no-option-labelprop -> a plain no-options message without having to reach for theno-optionslot (#9463)q-select__selected-valueclass as an officially targetable hook, e.g.white-space: pre-lineto render embedded newlines (#17973)lazymodifier -> Vue implements it only on native elements and leaves the deferral to components, which QInput ignored. The emission now stays pending until the change event or blur, matching the modifier's native semantics; an external model change cancels it (#18023)onCancel/onDismiss-> the callbacks receive'cancel','backdrop','escape'or'programmatic'(which includes an app route change), so the Cancel button can finally be told apart from a backdrop click, ESC or ahide()call. Custom components built onuseDialogPluginComponentget it with no template changes. New exported TS type:DialogDismissReason(#17938)onCancel/onDismiss-> the same argument,'backdrop','escape'or'programmatic'scroll-targetprop stays with its other, narrower meaning: the box the scroll percentage is computed againstenginesfield (node >= 10!) move to Node 22Fixes
<KeepAlive>never received its transition-end, so it came back stuck half-faded (#18201, #18526)once+ssr-prerender, freshly hydrated content was destroyed and rebuilt on every page load (#17099)body-cell-<name>/header-cell-<name>slots were dropped unkeyed into the row, so changingvisible-columnsmade Vue diff one column's compiled slot output against another's, producing hybrid cells (one column's label with another's href) and worse after repeated toggles. Production-only, which is why it survived dev testing. Same treatment fortop-row/bottom-rowandtop-selection(#16047)sortOrder: 'da'showed an up arrow even though the first click sorts descending (#18009)td:first-child { position: sticky }also matched the hidden spacer cells, and mutating a sticky cell during a scrollbar thumb drag made Chromium ratchet the scroller to the end (#17107)scrollTo()-> a scroller with CSSscroll-behavior: smoothanimated the internal repositioning (#18168)hide-scrollbaron the root element -> since Chrome/Edge 121 honorscrollbar-width, and it only reaches the viewport scrollbar from the root element, the anti-flicker resize logic had quietly stopped working (#17122)naturalWidth/naturalHeightfrom the img's current laid-out box, so when the load event lost the race with layout the wrong ratio got locked in andobject-fit: covercropped the image (#15652)unmasked-value, the first re-render after a keystroke rewrote the field to the raw text and it never recovered; the same happened after an IME compositiontoolbarprop rendered fine but crashed on entering source view (#16940)validate()returns nullish instead of breaking (#17921)hide()-> thehide/before-hideevents carried no payload on ESC dismissal, so listeners could not tell a keyboard dismissal from a backdrop onearia-activedescendantwas never set there either, breaking the combobox pattern's active-descendant navigation (#16599)bodyinstead of returning it to the control (#6858)behavior="dialog"anduse-input, typing into the focused but closed control was a dead end: the text piled up while the filter early-returned (#15976)@filteroptions andmap-options, a preloaded model value displayed raw until a user interaction loaded the options. QSelect now fires that one filter call itself (#17983)@popup-show/@popup-hide-> both events always receivedundefined(#14678)no-optionslot) left the typed filter text behind in the input (#16135)coverwithtransition-show) for JSX/TSX consumers and the docs API card listed none of them.separate-close-popupis the one documented exception: the menu branch overrides it (#18530)q-focusable/q-hoverablehelpersbody.desktop, so the keyboard navigation QSelect just gained on mobile moved a focused state nothing painted (#16599)Other
escape-keyevent, and QVirtualScroll's entirely undocumented QList / QMarkupTable attrs forwarding is now declared. Both reach the generated TS types and the docs API cardserrorprop reserves the bottom space even whenfalse-> thefalsevsnulldistinction (reserve the error line vs no external validation at all) was undocumented and kept getting reported as a bug (#17662)<object>fallback, IE-era normalize rules), the hover engine shared by QMenu/QFab/QSelect moved into one composable, and the API builder gained mixin/extends features that let components pull pass-through definitions straight from their source component instead of hand-copying themDonations
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:
v2.27.0Compare Source
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 movedcol-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)quasar/lang/ckb,quasar/lang/myandquasar/lang/sr-Cyrlfor Central Kurdish, Burmese and Serbian Cyrillic.kur-CKB,mmandsr-CYRremain available as deprecated aliasesFixes
hovermenu's target and clicking it in one gesture closed the menu the hover had just opened. Also applies to QBtnDropdown (#18524)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)rightinset could not be flipped by the RTL stylesheet (#17943).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)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)unmasked-valueand forward filling, a typed "1" over###-##withfill-mask="0"was reported as "10000"; with maskAA-AAandfill-mask="A", "X" became "XAAA" (#18523)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)AA-##rendered "-57", which unmasked back to "57", so what the field displayed was not a value it could read again (#18523)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 DiachenkoOther
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)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 branchesDonations
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:
v2.26.0Compare Source
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)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)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)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)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 goneFixes
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)pointerTypewhether it hovers or toucheschangeonly 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 spuriouschangechangeonly when a user adjustment lands a new value -> mounting, every parent model write and range clamping used to fire it, contradicting its own API descriptionstepdrifted (0.1 + 0.1 + 0.1 = 0.30000000000000004), somarker-labelsrendered the drifted number andmarker-label-*slot lookups misseddisablewhile a Dialog or overlay Drawer held the scroll lock never polled again (#18520)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)aria-labelmatched two elements and broke strict single-element queries (PlaywrightgetByLabel, Testing LibrarygetBy*); the wrapper copy was invalid ARIA as well (#18519)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)aria-placeholderthe component already renders, and the invalidplaceholderattribute is no longer emitted (#18511)roleandaria-*attributes to theasideelement -> they landed on the inner scrolling div, so naming or re-typing the landmark through QDrawer was impossible (#18059).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).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)switch-toggle-side(#18008)Other
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)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 breakpointDonations
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:
v2.25.1Compare Source
Fixes
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)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()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)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)@loadin a loop until the whole list had been fetched (#13257)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)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
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:
v2.25.0Compare Source
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)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)optionsprop and the navigation-min/max limitssliderrole now sits on the focusable element, and the whole family gains Home/Endleft-thumb-aria-labelandright-thumb-aria-labelpropstoggleslot -> renders next to the dropdown arrow, so content like a QTooltip can finally attach to the toggle button in split mode (#16955)toggle-aria-haspopupprop -> names the popup's role on the control that actually opens it, in both the regular and the split designroleprop -> the documented override path (e.g.menuitemcheckbox, orrole="menu"on a QList)$layout-marginal-backgroundand$layout-marginal-colorSass variables for the marginal sections (#10476)escape-keyeventcontrolslot scope gainsariaInvalid,ariaDescribedbyandariaErrormessagecolorPickeranduploaderlang sections plustable.selectAllRows,table.selectRowandpagination.label, translated across all 72 language packsAccessibility
aria-pressedand mark today witharia-current="date"; the view switcher becomes a real button that Space activatesaria-disabledwas set only for radiosseparator; arrows move it by 1% (10px inpxunit) and Home/End jump to the limits (#12466)separator-aria-labelproptabpanelrole lives solely on the panel components (#6560)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)role=toolbarwith a localized name, a single Tab stop with roving tabindex, arrow navigation (wrapping, RTL-mirrored) and Home/End (#15675)aria-pressedinstead of color alone, and the hyperlink editor's URL field gets a namerole=menu(#17162)aria-expanded/aria-controlsstay in sync without apps mirroring the open state by handaria-modaldialog -> menus anchored in a modal QDialog (a QSelect's listbox included) were pruned from the accessibility tree and never announced (#17078)listboxrole wraps only the options, which now carryaria-setsize/aria-posinset(#17344)<q-input error hide-bottom-space>pointedaria-errormessage/aria-describedbyat a missing idaria-hiddencontrol (#17810)carousellang-pack section, translated across all packs (#7423)Performance
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 lookupsduration <= 0short-circuits to an immediate settleuseQuasar()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)formatDatemasks once and cache per mask@scrollpayload assemblyisKeyCode, loop-basedsumSize, regex-freehexToRgband allocation-free mask token testersshouldIgnoreKey()Fixes
@keydown.ctrl.b.preventcould observe the key but not stop QEditor toggling bold<a href="https://">straight away, leaving a broken link behind if you walked away (#18289):classon an open QDialog never reached the portal root, and a dynamicidwent stale on QTooltipposition: fixeddescendant anchored itself to the scroll area and was clipped there (#12109)fill-input(#17763)autogrowis toggled off (#17535)direction="up"andlabelposition="right"label-position="top"/"bottom"laid icon and label out in a row instead of a columnhideSelectionprop from the alpha sliderconfig > screen > bodyClasseskey on SSR, which never emitted its body class into server-rendered HTMLuseQuasar()'sinject()fallback past the no-instance caseOther
[Accessibility]category in the Specs workflowDonations
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:
v2.24.0Compare Source
Changes
No breaking changes, no runtime changes. This release makes quasar more tree-shakable and pairs with the new faster toolchain.
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:
v2.23.5Compare Source
Fixes
Notable behaviour changes
b67ea77,843a8c7)Affects all components using rules (QInput, QSelect, QField, QFile, QDate, QTime, ...). Previously, a string rule that doesn't match any embedded validation pattern (e.g. rules: [ 'emial' ] instead of 'email') was silently skipped — the field validated as if the rule wasn't there. Such a rule now logs a console.error and fails validation (like any message-less rule, with no error message displayed).
Action needed: if a field in your app suddenly refuses to validate and the console shows Unknown validation pattern rule: "...", fix the rule name. The old behavior was accepting any input through the typo.
9101b16)Previously, setting events without also setting event-color rendered no marker at all. Markers now render with the default styling (the secondary brand color), as documented. If you had events set and were (unknowingly) relying on the markers being invisible, days matching events will now show a marker.
e75b65e,db1df05)Passing an explicitly undefined model (e.g. v-model="myDate" before myDate is initialized) no longer triggers a Vue prop-validation warning — it now resolves to null ("no value selected"), matching the documented String | null | undefined type and the pattern QSlider already uses. Omitting the prop entirely still warns as a required prop. No action needed unless you were watching for that console warning.
7a45734)Previously, an invalid/unset url only logged a console error and marked the files as failed — the @failed event never fired, so programmatic error handling couldn't react. The event now fires with the documented { files, xhr } payload (an XHR that was never sent, so xhr.status is 0). If you have a @failed listener, it will now also receive this case.
edfb46a)The public setTicked() method (and tickboxes in uncontrolled usage) previously did nothing unless ticked was bound with v-model. It now updates the internal state, mirroring how setExpanded() already behaved. Controlled usage (with v-model:ticked) is unchanged.
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:
v2.23.4Compare Source
Fixes
Behavior change: date.extractDate() and invalid input
Previously, extractDate() always constructed a valid Date, even when the input didn't
match the mask or contained impossible values. Failures were silently normalized --
extractDate('not a date', 'YYYY-MM-DD') returned Jan 1 1900, 2024-02-30 rolled over
to Mar 1, and out-of-range time components wrapped around (24:00 became 00:00, 13:60 became 13:00).
Now these inputs return an Invalid Date object. The function signature and return type are unchanged, but code that never checked validity will propagate NaN-based dates instead of wrong-but-valid ones. Check results with:
Valid input prefixes still parse — extra text after the masked portion is ignored, so extractDate('2024-02-29T13:05:06Z', 'YYYY-MM-DD') still works.
QDate and QTime are also stricter about model values with out-of-range time components (e.g. 24:00
with an HH:mm mask). QTime now shows its empty --:-- state instead of a silently wrapped time,
and QDate (with a time-bearing custom mask only) treats such values as unparseable -- no day appears
selected and the calendar opens at the default view. Valid model values are unaffected.
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:
v2.23.3Compare Source
Security
Fixes
Other (potential breaking change)
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:
v2.23.2Lots of community fixes included, especially from Evan Chan (@evnchn ). Thanks all for contributing!
Fixes
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:
v2.23.0: /1Compare Source
New
Fixes
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:
v2.22.0Compare Source
Security fixes
Other fixes
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:
v2.21.4Compare Source
Changes
Donations
Quasar Framework is an open-source MIT-licensed project made possible due to the generous contributions by sponsors and backers. If you are interested in supporting this project, please consider the following:
v2.21.3Compare Source
Changes
Donations
Quasar Framework is an open-source MIT-licensed project made possible due to the generous contributions by sponsors and backers. If you are interested in supporting this project, please consider the following:
v2.21.2Compare Source
Changes
Donations
Quasar Framework is an open-source MIT-licensed project made possible due to the generous contributions by sponsors and backers. If you are interested in supporting this project, please consider the following:
v2.21.1Compare Source
Changes
Donations
Quasar Framework is an open-source MIT-licensed project made possible due to the generous contributions by sponsors and backers. If you are interested in supporting this project, please consider the following:
v2.21.0Compare Source
Changes
Donations
Quasar Framework is an open-source MIT-licensed project made possible due to the generous contributions by sponsors and backers. If you are interested in supporting this project, please consider the following:
v2.20.3Compare Source
Changes
Donations
Quasar Framework is an open-source MIT-licensed project made possible due to the generous contributions by sponsors and backers. If you are interested in supporting this project, please consider the following:
v2.20.2Compare Source
Changes
Donations
Quasar Framework is an open-source MIT-licensed project made possible due to the generous contributions by sponsors and backers. If you are interested in supporting this project, please consider the following:
v2.20.1Compare Source
Fixes
Donations
Quasar Framework is an open-source MIT-licensed project made possible due to the generous contributions by sponsors and backers. If you are interested in supporting this project, please consider the following:
v2.20.0Compare Source
Quasar UI is now much smaller in size and runs faster! We are bumping the minor version because this release is significant in many areas.
Changes
Donations
Quasar Framework is an open-source MIT-licensed project made possible due to the generous contributions by sponsors and backers. If you are interested in supporting this project, please consider the following:
v2.19.3Compare Source
Changes
Donations
Quasar Framework is an open-source MIT-licensed project made possible due to the generous contributions by sponsors and backers. If you are interested in supporting this project, please consider the following:
v2.19.2Compare Source
Changes
Donations
Quasar Framework is an open-source MIT-licensed project made possible due to the generous contributions by sponsors and backers. If you are interested in supporting this project, please consider the following:
v2.19.1Compare Source
Changes
Donations
Quasar Framework is an open-source MIT-licensed project made possible due to the generous contributions by sponsors and backers. If you are interested in supporting this project, please consider the following:
v2.19.0Compare Source
We're bumping the minor version without new features to signal our important shift to the Oxc+Rolldown ecosystem for our internal build system (which also generates smaller Quasar UI dist files).
For the standalone/umd version, we're now targetting the "baseline-widely-available" agreed minimum versions (chrome/edge 111, firefox 114, safari/ios 16.4) and Node.js v20 (already required by q/app-vite [v22 for this one] & q/app-webpack).
Changes
Donations
Quasar Framework is an open-source MIT-licensed project made possible due to the generous contributions by sponsors and backers. If you are interested in supporting this project, please consider the following:
v2.18.7Compare Source
Changes
Donations
Quasar Framework is an open-source MIT-licensed project made possible due to the generous contributions by sponsors and backers. If you are interested in supporting this project, please consider the following:
v2.18.6Compare Source
Changes
Donations
Quasar Framework is an open-source MIT-licensed project made possible due to the generous contributions by sponsors and backers. If you are interested in supporting this project, please consider the following:
v2.18.5Compare Source
Changes
Donations
Quasar Framework is an open-source MIT-licensed project made possible due to the generous contributions by sponsors and backers. If you are interested in supporting this project, please consider the following:
v2.18.4Compare Source
New
Donations
Quasar Framework is an open-source MIT-licensed project made possible due to the generous contributions by sponsors and backers. If you are interested in supporting this project, please consider the following:
v2.18.3Compare Source
Changes
Donations
Quasar Framework is an open-source MIT-licensed project made possible due to the generous contributions by sponsors and backers. If you are interested in supporting this project, please consider the following:
v2.18.2Compare Source
New
Changes
Donations
Quasar Framework is an open-source MIT-licensed project made possible due to the generous contributions by sponsors and backers. If you are interested in supporting this project, please consider the following:
v2.18.1Compare Source
Fixes
Donations
Quasar Framework is an open-source MIT-licensed project made possible due to the generous contributions by sponsors and backers. If you are interested in supporting this project, please consider the following:
v2.18.0Compare Source
New
Fixes
Donations
Quasar Framework is an open-source MIT-licensed project made possible due to the generous contributions by sponsors and backers. If you are interested in supporting this project, please consider the following:
v2.17.7Compare Source
Changes
Donations
Quasar Framework is an open-source MIT-licensed project made possible due to the generous contributions by sponsors and backers. If you are interested in supporting this project, please consider the following:
v2.17.6Compare Source
Fixes
Donations
Quasar Framework is an open-source MIT-licensed project made possible due to the generous contributions by sponsors and backers. If you are interested in supporting this project, please consider the following:
v2.17.5Compare Source
Fixes
Donations
Quasar Framework is an open-source MIT-licensed project made possible due to the generous contributions by sponsors and backers. If you are interested in supporting this project, please consider the following:
v2.17.4Compare Source
Fixes
Donations
Quasar Framework is an open-source MIT-licensed project made possible due to the generous contributions by sponsors and backers. If you are interested in supporting this project, please consider the following:
v2.17.3Compare Source
Fixes
Donations
Quasar Framework is an open-source MIT-licensed project made possible due to the generous contributions by sponsors and backers. If you are interested in supporting this project, please consider the following:
v2.17.2Compare Source
Fixes
Donations
Quasar Framework is an open-source MIT-licensed project made possible due to the generous contributions by sponsors and backers. If you are interested in supporting this project, please consider the following:
v2.17.1Compare Source
New
Fixes
Donations
Quasar Framework is an open-source MIT-licensed project made possible due to the generous contributions by sponsors and backers. If you are interested in supporting this project, please consider the following:
v2.17.0Compare Source
Potential upgrade issue
The "Platform" Quasar plugin now explicitly holds all Boolean props in
Platform.isObject. Previously, only the active/"true" ones were contained. So, for example, on a non-Firefox browser, if previouslyPlatform.is.firefoxwould not have been declared, now it will be defined and its value is going to befalse. So, if you were doing'firefox' in Platform.isorPlatform.is.firefox === undefined, change it toPlatform.is.firefox/!Platform.is.firefox.New
Fixes
Donations
Quasar Framework is an open-source MIT-licensed project made possible due to the generous contributions by sponsors and backers. If you are interested in supporting this project, please consider the following:
v2.16.11Compare Source
Fixes
Donations
Quasar Framework is an open-source MIT-licensed project made possible due to the generous contributions by sponsors and backers. If you are interested in supporting this project, please consider the following:
v2.16.10Compare Source
Changes
Donations
Quasar Framework is an open-source MIT-licensed project made possible due to the generous contributions by sponsors and backers. If you are interested in supporting this project, please consider the following:
v2.16.9Compare Source
New
Fixes
Donations
Quasar Framework is an open-source MIT-licensed project made possible due to the generous contributions by sponsors and backers. If you are interested in supporting this project, please consider the following:
v2.16.8Compare Source
Changes
Donations
Quasar Framework is an open-source MIT-licensed project made possible due to the generous contributions by sponsors and backers. If you are interested in supporting this project, please consider the following:
v2.16.7Compare Source
Fixes
Donations
Quasar Framework is an open-source MIT-licensed project made possible due to the generous contributions by sponsors and backers. If you are interested in supporting this project, please consider the following:
v2.16.6Compare Source
Fixes
Donations
Quasar Framework is an open-source MIT-licensed project made possible due to the generous contributions by sponsors and backers. If you are interested in supporting this project, please consider the following:
v2.16.5Compare Source
Fixes
@typescript-eslint/unbound-methoderror on newer utilities types (#17251)Donations
Quasar Framework is an open-source MIT-licensed project made possible due to the generous contributions by sponsors and backers. If you are interested in supporting this project, please consider the following:
v2.16.4Compare Source
Changes
Donations
Quasar Framework is an open-source MIT-licensed project made possible due to the generous contributions by sponsors and backers. If you are interested in supporting this project, please consider the following:
v2.16.3Compare Source
Changes
Donations
Quasar Framework is an open-source MIT-licensed project made possible due to the generous contributions by sponsors and backers. If you are interested in supporting this project, please consider the following:
v2.16.2Compare Source
Fixes
Donations
Quasar Framework is an open-source MIT-licensed project made possible due to the generous contributions by sponsors and backers. If you are interested in supporting this project, please consider the following:
v2.16.1Compare Source
Fixes
Donations
Quasar Framework is an open-source MIT-licensed project made possible due to the generous contributions by sponsors and backers. If you are interested in supporting this project, please consider the following:
v2.16.0Compare Source
New
Converted "quasar" package internal build system to ESM (built dist/*.js are now renamed).
Will require these minimum CLI/plugin versions (if using any of the following):
If you have hard-coded imports from quasar/lang or quasar/icon-set with the extension specified (eg.
quasar/lang/de.mjs) please change the extension to.js.Fixes
JSON fixes
Donations
Quasar Framework is an open-source MIT-licensed project made possible due to the generous contributions by sponsors and backers. If you are interested in supporting this project, please consider the following:
v2.15.4Compare Source
Changes
Donations
Quasar Framework is an open-source MIT-licensed project made possible due to the generous contributions by sponsors and backers. If you are interested in supporting this project, please consider the following:
v2.15.3Compare Source
New
Fixes
Donations
Quasar Framework is an open-source MIT-licensed project made possible due to the generous contributions by sponsors and backers. If you are interested in supporting this project, please consider the following:
v2.15.2Compare Source
Changes
Example of how you can target the teleported content of a QDialog/Qmenu in your testing:
Donations
Quasar Framework is an open-source MIT-licensed project made possible due to the generous contributions by sponsors and backers. If you are interested in supporting this project, please consider the following:
v2.15.1Compare Source
Changes
Donations
Quasar Framework is an open-source MIT-licensed project made possible due to the generous contributions by sponsors and backers. If you are interested in supporting this project, please consider the following:
v2.15.0Compare Source
New
Donations
Quasar Framework is an open-source MIT-licensed project made possible due to the generous contributions by sponsors and backers. If you are interested in supporting this project, please consider the following:
v2.14.7Compare Source
Changes
Donations
Quasar Framework is an open-source MIT-licensed project made possible due to the generous contributions by sponsors and backers. If you are interested in supporting this project, please consider the following:
v2.14.6Compare Source
New
Fixes
Donations
Quasar Framework is an open-source MIT-licensed project made possible due to the generous contributions by sponsors and backers. If you are interested in supporting this project, please consider the following:
v2.14.5Compare Source
Fixes
Donations
Quasar Framework is an open-source MIT-licensed project made possible due to the generous contributions by sponsors and backers. If you are interested in supporting this project, please consider the following:
v2.14.4Compare Source
Fixes
Donations
Quasar Framework is an open-source MIT-licensed project made possible due to the generous contributions by sponsors and backers. If you are interested in supporting this project, please consider the following:
v2.14.3Compare Source
Fixes
Donations
Quasar Framework is an open-source MIT-licensed project made possible due to the generous contributions by sponsors and backers. If you are interested in supporting this project, please consider the following:
v2.14.2Compare Source
Fixes
aria-readonlyfrom labels for QField, QCodeol, QDate, QEditor #16705 (#16708)Donations
Quasar Framework is an open-source MIT-licensed project made possible due to the generous contributions by sponsors and backers. If you are interested in supporting this project, please consider the following:
v2.14.1Compare Source
Fixes
innerMininstead ofminon drag #16614 (#16615)Donations
Quasar Framework is an open-source MIT-licensed project made possible due to the generous contributions by sponsors and backers. If you are interested in supporting this project, please consider the following:
v2.14.0Compare Source
Changes
@errorparam definition #16545Possible breaking changes for Sass users!
When using Quasar UI (this package) with our Quasar CLI or our Vite plugin, it will require the latest Sass v1 (which has breaking changes -- though your Sass code will work albeit with deprecation banners on the console). It will be easy for you to upgrade to the newer Sass requirements for your code (and most might not even need anything changed). The console logs will tell you what lines to change and to what exactly. There is also a sass-migrator tool available (written by the Sass team).
We have postponed this moment as much as possible and we apologize for introducing this change in a minor version, but a major version for something so small is not really feasible nor desired (and again, it is due to Sass introducing changes in one of their minor versions).
If using Quasar CLI
Minimum quasar/app-vite supported version is v1.7.0
Minimum quasar/app-webpack supported version is v3.12.0
If using Vite or Vue CLI
Minimum "sass" version is v1.33.0 (although we recommend installing the very latest v1 available)
Donations
Quasar Framework is an open-source MIT-licensed project made possible due to the generous contributions by sponsors and backers. If you are interested in supporting this project, please consider the following:
v2.13.1Compare Source
New
Fixes
Donations
Quasar Framework is an open-source MIT-licensed project made possible due to the generous contributions by sponsors and backers. If you are interested in supporting this project, please consider the following:
v2.13.0Compare Source
New
Fixes
Donations
Quasar Framework is an open-source MIT-licensed project made possible due to the generous contributions by sponsors and backers. If you are interested in supporting this project, please consider the following:
v2.12.7Compare Source
Fixes
Donations
Quasar Framework is an open-source MIT-licensed project made possible due to the generous contributions by sponsors and backers. If you are interested in supporting this project, please consider the following:
v2.12.6Compare Source
Fixes
Donations
Quasar Framework is an open-source MIT-licensed project made possible due to the generous contributions by sponsors and backers. If you are interested in supporting this project, please consider the following:
v2.12.5Compare Source
Fixes
Donations
Quasar Framework is an open-source MIT-licensed project made possible due to the generous contributions by sponsors and backers. If you are interested in supporting this project, please consider the following:
v2.12.4Compare Source
New
Fixes
Donations
Quasar Framework is an open-source MIT-licensed project made possible due to the generous contributions by sponsors and backers. If you are interested in supporting this project, please consider the following:
v2.12.3Compare Source
Fixes
Donations
Quasar Framework is an open-source MIT-licensed project made possible due to the generous contributions by sponsors and backers. If you are interested in supporting this project, please consider the following:
v2.12.2Compare Source
Fixes
Donations
Quasar Framework is an open-source MIT-licensed project made possible due to the generous contributions by sponsors and backers. If you are interested in supporting this project, please consider the following:
v2.12.1Compare Source
Features
Fixes
Donations
Quasar Framework is an open-source MIT-licensed project made possible due to the generous contributions by sponsors and backers. If you are interested in supporting this project, please consider the following:
v2.12.0Compare Source
New
Fixes
Donations
Quasar Framework is an open-source MIT-licensed project made possible due to the generous contributions by sponsors and backers. If you are interested in supporting this project, please consider the following:
Configuration
📅 Schedule: (in timezone Europe/Berlin)
🚦 Automerge: Disabled by config. Please merge this manually once you are satisfied.
♻ Rebasing: Whenever PR becomes conflicted, or you tick the rebase/retry checkbox.
🔕 Ignore: Close this PR and you won't be reminded about this update again.
This PR has been generated by Mend Renovate CLI.
View command line instructions
Checkout
From your project repository, check out a new branch and test the changes.Merge
Merge the changes and update on Forgejo.Warning: The "Autodetect manual merge" setting is not enabled for this repository, you will have to mark this pull request as manually merged afterwards.