v0.17.0
This is big release, introducing SSR support & many new features. Enjoy!
Breaking Changes
Only one, regarding QLayoutDrawer mini-width
prop. It is now a Number (instead of String!) defining width in pixels (default: 60).
SSR (Server-Side Rendering) Support
The long awaited SSR support is here! Quasar code is now isomorphic. It might be a one-liner, but this is where 90% of the development time was spent for this release.
Some things worth mentioning, in order to best benefit from Quasar SSR:
-
Make sure you read the SSR docs in Guide
-
Use Platform and Cookies Quasar plugins only in their
$q.platform
and$q.cookies
form. Do not use this outside of Vue components when building with SSR mode. This restriction is required because of the singleton problem when dealing with SSR. -
The LocalStorage and SessionStorage Quasar plugins cannot be used on server-side. The reasons are obvious since this is a client-side only browser API. DO NOT rely on web storage for your SSR website. You can use Cookies Quasar plugin instead, which does work on server-side too.
-
Make your
QBtn
s SEO-friendly. Quasar offers this functionality out of the box, but you need to know how to enable it:Quasar buttons are usually rendered with a
<button>
HTML tag. But now they can be rendered with<a>
tags too. When you want the user to navigate to another route by clicking a QBtn, you were used to add a@click
Vue event handler. Now you can use<router-link>
-like props on QBtn too. By doing this, Quasar can make your buttons SEO friendly.<!-- old way, still works, but not SEO friendly --> <q-btn @click="$router.push('/some/route')" ... /> <!-- new, equivalent way --> <q-btn to="/some/route" ... /> <!-- old way, still works, but not SEO friendly --> <q-btn @click="$router.replace('/some/route')" ... /> <!-- new, equivalent way --> <q-btn to="/some/route" replace ... /> <!-- old way, still works, but not SEO friendly --> <q-btn @click="$router.push({ name: 'special' })" ... /> <!-- new, equivalent way --> <q-btn :to="{ name: 'special' }" ... />
Quasar Meta plugin
The Meta plugin can change page title, manage meta tags, manage <html>
& <body>
DOM element attributes, add/remove/change <style>
tags in head (useful for CDN stylesheets, for example), or manage <noscript>
tags. Note that this is not a full description of what the Meta plugin can do (that will be available in the final release notes).
Installation:
// quasar.conf.js
framework: {
// ...
plugins: ['Meta']
}
What this does is that it enables the use of a special property in your Vue components called meta
. Example below, with almost all of its features:
// some .vue file
export default {
// ...
meta: {
title: 'Index Page', // sets document title
titleTemplate: title => `${title} - My Website`, // optional; sets final title as "Index Page - My Website", useful for multiple level meta
meta: {
description: { name: 'description', content: 'Page 1' },
keywords: { name: 'keywords', content: 'Quasar website' },
equiv: { 'http-equiv': 'Content-Type' content: 'text/html; charset=UTF-8' }
},
link: {
material: { rel: 'stylesheet', href: 'https://fonts.googleapis.com/icon?family=Material+Icons' }
},
script: {
ldJson: {
type: 'application/ld+json',
innerHTML: `{ "@context": "http://schema.org" }`
}
},
htmlAttr: {
'xmlns:cc': 'http://creativecommons.org/ns#' // generates <html xmlns:cc="http://creativecommons.org/ns#">
},
bodyAttr: {
'action-scope': 'xyz', // generates <body action-scope="xyz">
empty: undefined // generates <body empty>
},
noscript: {
default: 'This is content for browsers with no JS (or disabled JS)'
}
}
}
Metas are computed from .vue files in the order they are activated by Vue Router (let's call this a chain for further explanations). Example: App.vue > SomeLayout.vue > IndexPage.vue > ...?
Notice that all properties (except for title and titleTemplate) are Objects; you can override meta props defined in previous Vue components in the chain by using these keys again. Example:
// first loaded Vue component
meta: {
meta: {
myKey: { name: 'description', content: 'My Website' }
}
}
// a subsequent Vue component in the chain;
// this will override the first definition on "myKey"
meta: {
meta: {
myKey: { name: 'description', content: 'Page 1' }
}
}
The "meta" properties can be dynamic. For example, this is how you can bind to the Vue scope with them. Think of them as a Vue computed property.
export default {
data () {
return {
title: 'Some title' // we define the "title" prop
}
},
meta () {
return {
// this accesses the "title" property in your Vue "data";
// whenever "title" prop changes, your meta will automatically update
title: this.title
}
},
methods: {
setAnotherTitle () {
this.title = 'Another title' // will automatically trigger a Meta update due to the binding
}
}
// ...
}
New
-
QNoSsr component; highly optimized - takes into consideration client takeover so subsequent renders are as fast as possible.
-
QJumbotron component
-
QTable as grid
<q-table
grid
hide-header
:data="data"
:columns="columns"
:filter="filter"
:selection="selection"
:selected.sync="selected"
:visible-columns="visibleColumns"
row-key="name"
>
<template slot="top-right" slot-scope="props">
<q-search hide-underline v-model="filter" />
</template>
<div
slot="item"
slot-scope="props"
class="q-pa-xs col-xs-12 col-sm-6 col-md-4 col-lg-3 transition-generic"
:style="props.selected ? 'transform: scale(0.95);' : ''"
>
<q-card class="transition-generic" :class="props.selected ? 'bg-grey-2' : ''">
<q-card-title class="relative-position">
<q-checkbox v-model="props.selected" :label="props.row.name" />
</q-card-title>
<q-card-separator />
<q-card-main class="q-pa-none">
<q-list no-border>
<q-item v-for="col in props.cols.filter(col => col.name !== 'desc')" :key="col.name">
<q-item-main>
<q-item-tile label>{{ col.label }}</q-item-tile>
</q-item-main>
<q-item-side right>
<q-item-tile>{{ col.value }}</q-item-tile>
</q-item-side>
</q-item>
</q-list>
</q-card-main>
</q-card>
</div>
</q-table>
-
New quasar.conf > framework >
config
Objectframework: { // ... config: { brand: { // this will NOT work on IE 11 primary: '#e46262', // ... or all other brand colors }, notify: {...}, // default set of options for Notify Quasar plugin loading: {...}, // default set of options for Loading Quasar plugin loadingBar: { ... }, // settings for LoadingBar Quasar plugin cordova: { iosStatusBarPadding: true/false, // add the dynamic top padding on iOS mobile devices backButtonExit: true/false // Quasar handles app exit on mobile phone back button } } }
The Quasar UMD version will define the following before including the Quasar script tag:
<script> // optional window.quasarConfig = { .... } </script>
-
Loading & Notify Quasar plugins now support a new method:
setDefaults({...})
-- use this or through quasar.conf > framework > config:{ loading: {...}, notify: {...} }
-
(NEW) LoadingBar Quasar plugin -- adds a loading bar a-la Youtube; no need to do anything else in your app code
It will catch all Ajax calls and even hook into asyncData() automatically, but if you have some custom actions, you can programmatically start/stop it by calling
this.$q.loadingBar.start()
andthis.$q.loadingBar.stop()
in your Vue components. Outside of Vue components, you canimport { LoadingBar } from 'quasar'
then callLoadingBar.start()/stop()/increment(val)
LoadingBar is using QAjaxBar component under the covers, so you can configure it using QAjaxBar props like this:
// quasar.conf framework: { // ... plugins: [ // ... 'LoadingBar' ], config: { // optional: loadingBar: { ... } // QAjaxBar props } }
-
Hook AddressbarColor into cordova-plugin-statusbar when available
-
QLayoutDrawer
- "mini-width" prop is now a Number (instead of String!) defining width in pixels (default: 60)
- new prop:
width
defining width in pixels for non-mini mode (default: 300) - backdrop animation when in mobile mode
-
Many performance enhancements
- layout header/footer animation
- tweaks to make Vue render Quasar components faster by avoiding some children array normalization
-
Ability to cancel frameDebounce() from utils (call
.cancel()
on the debounced function) -
QUploader: added
upload-factory
prop (#2093) -
QInput: added prop
lower-case
(#2117) -
New Quasar language packs: Traditional Chinese, Guarani
-
[Request] Q-Chips-Input: Pass upper-case parameter to underlying q-input #2031
-
[Request] QUploader - new prop:
no-content-type
#1974 -
Q-Page: ability to disable
minHeight
prop. (#2120) -
Allow Dialog and ActionSheet Quasar plugins to receive a resolver token (#1869)
-
Improve out of the box SEO for QItem, QBreadcrumbs, QRouteTab -- allow bots to follow links
-
Improve keyboard navigation (#1936)
- QModal
- fix not emmiting dismiss on ESC
- focus after show
- add back noRefocus
- QPopover
- focus after show
- refocus after hide (noRefocus prop)
- allow toggle by keyboard ENTER
- QDialog
- fix button focus
- find button by class name (q-btn)
- add back noRefocus
- QFab - refocus after hide
- QTab / QRouteTab
- focus with keyboard
- allow select with keyboard ENTER
- QColor and QDatetime
- fix tabindex lost on close
- fix popup not closing on blur
- QColorPicker
- fix incorrect tabindex on disable
- allow to select saturation on click on mobile (was working only on drag)
- QDatetimePicker.mat - allow keyboard adjustment of all values
- QActionsheet
- select option with ENTER/SPACE, navigation with TAB
- trigger selection on keyup to avoid click on original button
- QAutocomplete - use QPopup with noFocus
- QKnob, QSlider, QRange - keyboard updating (UP|RIGHT +, DOWN|LEFT -, CTRL+... 10*)
- QSelect
- remove autofocusFilter - always select filter if present
- move keyboard navigation on QPopover
- delay popover.reposition on filter to allow resize
- v-back-to-top, v-close-overlay, v-go-back, v-ripple - trigger by keyboard ENTER
- QInput - set model on ENTER
- QModal
-
Flex addons -- provide breakpoint aware versions for all flex (and display) related classes -- needs to be enabled from quasar.conf > framework > cssAddon: true
.flex-<bp>-(block|inline) .(row|column|flex)-<bp>(|-inline) .reverse-<bp> .(wrap|no-wrap|reverse-wrap)-<bp> .order-<bp>-(first|last|none) .justify-<bp>-(start|end|center|between|around) .items-<bp>-(start|end|center|baseline|stretch) .content-<bp>-(start|end|center|between|around) .self-<bp>-(start|end|center|baseline|stretch) .flex-<bp>-center .gutter-<bp>(|-x|-y)-(xs|sm|md|lg|xl) .(col|offset)-<bp>(|0..12)
-
QModal: Auto size based on content, can be customized through CSS with (min|max)(Width|Height) passed in :content-css. It's also applied when using QModalLayout.
-
Flex: .col has higher grow priority than .col-auto and .col-grow, add .(col|offset)-0
-
Material ripple - centered on round buttons (as per Material guidelines)
-
[Request] debounce property in QScrollObservable component #2169
-
QTabs - desktop state hover
-
QScrollArea - added hover effect (#2189)
-
Lots of enhancements to QAjaxBar to best accommodate SSR mode
-
Use round/rounded focus helper for radio/checkbox (#2200)
-
QBtnDropdown - popover-anchor & popover-self props (to align its popover) #1665
-
Loading plugin default delay was set to 0
-
feat: add v-scroll horizontal position #2296
-
Finalized helper-json files
-
Set xhr's withCredentials flag in request for QUploader #2305
-
QTabs new prop: "panes-container-class"
Fixes
- QTab's count and alert attributes look bad when QTabs's align is set to justify #2032
- [Bug] QSelect throws an error when container block disappears #2071
- QInput shouldn't have expanding underline animation on focus in iOS theme #2085
- v-scroll-fire get fired when reload the page #2081
- Q-Pagination Direction-Links Broken on Cordova #2088
- v-model on QLayoutDrawer bug #2094 -- example: having an input component breaks the model of QLayoutDrawer
- iPhoneX - avoid toolbar/header top-padding when not in fullscreen #2118
- [Regression] Dialog is not blurring input element in v0.15.15/v0.16 #2137
- QBtnDropdown Popover does not scroll #2136
- QTable: [MS-Edge] Loading indicator not displayed correctly #2122
- QSearch: propagate upper-case and lower-case #2124
- Force QChip pointing zIndex (when in an already positioned context) #1982
- QPullToRefresh causing scroll issues with large tables inside QScrollArea #1884
- QColorPicker - process unset value #1887
- Error when navigating to other page while select component is opened #1980
- Return dismiss function from Notify.create #1913
- Fix material ripples on IE 11
- QAutocomplete: Fix focus after tab, fix loop in normalizeInterval, fix reposition, select options on keyboard navigation #2149 #2155 close #2157
- Override Material Icons CDN default size
- Colors utils: Fix guard for color type in luminosity (#2180)
- Japanese Quasar language pack: 2 words changed for more natural Japanese (#2182)
- Mini layout drawer animates like normal mode when it hides automatically #2080
- Infinite scroll delay after resume #2187
- animScrollTo util - bug if duration < 16 after recursion (#2192)
- Fix dom.ready() util when readyState = "interactive" (#2199)
- QSelect: fix blur when selecting clear (#2202)
- QBreadcrumbs and align mixin - fix align prop value check (#2217)
- className for QSelect, QSearch before|after, QInput focus on marginalia (#2215)
- Screen plugin doesn't updates values after setting new sizes #2221
- QRouterTab: fix double tabindex and hide outline (#2226)
- QPopover: only refocus on anchorEl when anchorClick (solves refocusing on split dropdown) (#2225)
- Fix QAutocomplete when not editable and pass readonly to QInputFrame (#2227)
- Fix internal popups.getPosition corner-case (#2235)
- QDatetime: use a +-50 years interval from current, use precomputed mins (#2234)
- QDatetime: format when type is date and formatModel is string (#2231)
- Fix not caught rejected promises when showing/hiding modals, dialogs, popovers
- fix: QTable - sort by non visible column #1886
- fix: QInfiniteScroll concurrency issue #2241
- fix(QSelect): does not show placeholder text when using chips (fix #2003) #2287
- fix: Corner case in model-toggle where component gets destroyed & not cleans up history on Cordova