New
- feat(ui): useElementSize() composable -> reactive
elementSize({ width, height }) of an element or component ref, with anonResizehook, a debounce window and adisabledswitch; QResizeObserver is now built on it - feat(ui): v-resize directive -> the template-side form of useElementSize(): reports an element's size without adding a node (the initial size, then only on change), debounce as the argument (
v-resize:100),oncemodifier, a handler returningfalsestops it - feat(ui): useScroll() composable -> reactive scroll position, direction, delta and inflection point of the page or of a scrollable container, with an
onScrollhook,axis, debounce anddisabled; QScrollObserver is now built on it - feat(ui): useFilePicker() composable -> opens the native file dialog from setup code without rendering a file input;
openFilePicker()resolves with the accepted files (null when dismissed) and the files get validated by the same rules as QFile (accept,maxFileSize,maxTotalSize,maxFiles,filter...) - feat(ui): useDropZone() composable and v-drop-zone directive -> turn any element or component into a drop target for files, with the QFile validation rules, a reactive
isOverDropZone(the directive sets aq-drop-zone--overclass instead) and rejected-file reporting. QFile and QUploader now handle drops through it - feat(ui): useObjectUrl() composable -> a reactive object URL for a Blob, File or MediaSource, revoked for you when the source changes and when the component is destroyed
- feat(ui): useEventListener() composable -> attaches a listener to an element, window, document or component, following reactive targets, event names and options; removed on unmount
- feat(ui): useMutation() composable -> the setup-code counterpart of v-mutation, with the latest
mutationRecordsas reactive state - feat(ui): useSoftFullscreen() composable -> the in-page fullscreen behind the
fullscreenprop of QTable, QCarousel and QEditor (back button, route-change exit, scroll restore, popups kept on top), now usable on any element or component - feat(ui): useIdle() composable ->
isIdleflips aftertimeoutms with no user activity, pluslastActiveandresetIdle(); hidden-page time counts as inactivity - feat(ui): useKeyboardShortcut() composable -> runs a handler for a "Mod+K" style shortcut (Mod is Meta on macOS, Ctrl elsewhere), matching either the layout-aware key or the physical key code; unmodified printable shortcuts stay quiet while typing in a field
- feat(ui): useWebSocket() composable -> a WebSocket connection kept alive from a component: status, last message, send queue flushed on open, auto reconnect with backoff (paused while offline), optional heartbeat, closed on unmount
- feat(ui): useEventSource() composable -> Server-Sent Events from a component: named events, last event id, and a reconnect where the browser gives up; closed on unmount
- feat(ui): useBroadcastChannel() composable -> message the other tabs, windows, iframes and workers of the same origin; closed on unmount
- feat(ui): useWebWorker() composable -> connects a component to a Web Worker script of your own (a URL, a Worker or a factory such as a Vite
?workerimport): status, last message and error,postWorkerMessage(), aterminateWorker()that frees the thread until the next message, and onCreate/onMessage/onError/onTerminate(reason) hooks - feat(ui): useWebWorkerFn() composable -> runs a function off the main thread:
runWorkerFn(...args)resolves with its result, withtimeout, Transferables, script dependencies, one hook per outcome (onSuccess/onError/onTimeout/onTerminate) and an inline run on the SSR server - feat(ui): useDebounce() and useThrottle() composables -> the debounce()/throttle() utils applied to a function, with the waiting call cancelled on deactivation and unmount;
fn.isPendingis reactive on the useDebounce() one - feat(ui): debounce() and throttle() utils -> debounce() takes
{ leading, trailing, maxWait }as its third param (a boolean still means "immediate") and gainsflush()plus anisPendingproperty; throttle() gainscancel(),flush()and an opt-in trailing call (throttle(fn, limit, true)) so a burst no longer ends on a stale state - feat(ui): useTimeout() and useInterval() -> also return
isTimeoutPending/isIntervalActivereactive flags - feat(ui): useTimeout(), useInterval(), useAnimationFrame() and useTick() -> work outside of a component (they used to warn and then throw when the timer fired); call the remove method when done
- feat(ui): useIntersection() -> returns
refreshIntersection()andstopIntersection(), named after the composable like the new ones;refresh()/stop()keep working - feat(ui): LocalStorage/SessionStorage useStorage() -> binds a stored item to a Vue ref: an assignment persists right away, nested changes of an Object or Array persist too, and the ref follows setItem()/removeItem()/clear(), its other refs and other tabs. Default from a function,
disabled,onError, typed keys through the augmentable LocalStorageItems/SessionStorageItems interfaces, SSR-safe - feat(ui): Cookies useCookie() -> binds a cookie to a Vue ref with the cookie options of set(); follows set()/remove(), its other refs and (where the browser has the Cookie Store API) cookies set by the server, another tab or natively. Default from a function, typed names through the augmentable CookieValues interface; on the server it reads the request cookie and writes a Set-Cookie header
- feat(ui): AppNetwork plugin -> reactive
$q.networkwith the online state and, where the browser has the Network Information API, effectiveType/downlink/rtt/saveData - feat(ui): AppWakeLock plugin ->
$q.wakeLockwraps the Screen Wake Lock API (isCapable, isActive, request/release/toggle) and re-acquires the lock when the page becomes visible again - feat(Screen):
$q.screen.orientation-> reactive{ type, angle, portrait, landscape }of the device screen - feat(QBtnGroup/QBtnToggle):
verticalprop -> stacks the buttons in a column, with the corners and seams drawn for that direction (#7766) - feat(QBtnToggle):
alignprop -> aligns the content of every option button (overridable per option), so the icons of a vertical toggle line up - feat(QInfiniteScroll):
horizontalprop -> loads more when the row is scrolled to its inline end (the left one in RTL),reverseincluded (#6709) - feat(QTable):
body-expandslot -> an expansion row declared after each body row while QTable keeps rendering the row itself (and itsbody-cell-[name]slots); no more taking over the whole row through thebodyslot (#4380) - feat(QTr):
expandableprop -> an expansion row that can slide open and closed with a QSlideTransition inside its cell (#4380) - feat(QTable): a column's
fieldis optional -> a column rendered entirely through itsbody-cell-[name]slot needs none - feat(ui): TypeScript -> Quasar directives are type-checked in templates (value, modifiers and argument) through Vue's GlobalDirectives
Fixes
- fix(QTooltip): a closing QDialog or QMenu returns focus to its opener -> the opener's tooltip no longer shows as if it had been tabbed onto (#18556)
- fix(QMenu/QTooltip): a
targetthat resolves after the model turns on (v-modelwritten before:target) -> the popup is anchored to it instead of rendering at its static position in Chromium (#18559) - fix(QItem): side, overline, caption and header labels -> they follow a dark mode switch and an active item's color in Chrome instead of keeping the previous color
- fix(ui): useIntersection(), QIntersection and v-intersection -> a
onceobservation that fired resumes observing whenoncegoes away - fix(ui): v-intersection -> a
nullvalue disables it instead of throwing; the v-intersection/v-mutation/v-resize/v-drop-zone disable values are typed asfalse | nullinstead of Boolean, which invitedtrue - fix(QScrollObserver): with
axis="both"-> no longer emits an unchanged position (on mount, on an RTL flip);getPosition()returns a snapshot instead of the live internal object - fix(Screen):
setDebounce()-> the pending update of the previous listener is applied right away instead of running late on a target it was removed from - fix(LocalStorage/SessionStorage):
setItem(key, null | undefined)removes the item, so a null read always means a missing item (older versions stored the strings the browser made of them); a stored RegExp keeps its flags (what older versions stored still decodes); an item stored natively as an empty String reads as''instead of null - fix(Cookies):
getAll()decodes and parses the values asget()does; on the server,set()replaces the request cookie sogetAll()no longer returns the previous value;remove()is typed to accept the same attributes asset()(a__Secure-/__Host-cookie needssecure) andset()the Object/Array/Number values it always stored - fix(ui): TypeScript -> template refs to Quasar components carry their instance methods (
useTemplateRef('btn').value.click(),.validate()...) - fix(ui): TypeScript ->
MetaOptionsandnoopare importable from "quasar"
Other
- refactor(ui): QLayout, QHeader, QFooter, QTabs and QScrollArea observe through useElementSize()/useScroll() instead of mounting hidden QResizeObserver/QScrollObserver children, so layout pages carry fewer component instances and re-render less on scroll
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: