Layout     

Layouts are the elements that wrap page content, like a navigational bar or drawer. Multiple pages can share the same Layout, so the code is reusable, which is one of their key points.

Quasar Layouts are not mandatory, but they do help you better structure your website/app. They have a number of features which offer you major benefits in simplifying your app’s layout design, right out of the box.

Basic Usage

Below is an example of a Layout, which contains all possible elements:

<q-layout ref="layout" view="hHr LpR lFf" :right-breakpoint="1100">
<!-- Header -->
<q-toolbar slot="header">
<q-btn flat @click="$refs.layout.toggleLeft()">
<q-icon name="menu" />
</q-btn>
<q-toolbar-title>
Layout Header
<span slot="subtitle">Optional subtitle</span>
</q-toolbar-title>
<q-btn flat @click="$refs.layout.toggleRight()">
<q-icon name="menu" />
</q-btn>
</q-toolbar>

<!-- Navigation -->
<q-tabs slot="navigation">
<q-route-tab slot="title" icon="view_quilt" to="/test-layout/about" replace hide="icon" label="About" />
<q-route-tab slot="title" icon="view_day" to="/test-layout/toolbar" replace hide="icon" label="Toolbar" />
<q-route-tab slot="title" icon="view_day" to="/test-layout/tabs" replace label="Tabs" />
<q-route-tab slot="title" icon="input" to="/test-layout/drawer" replace label="Drawer" />
</q-tabs>

<!-- Left Side Panel -->
<div slot="left">
<q-list no-border link inset-separator>
<q-list-header>Essential Links</q-list-header>
<q-side-link item to="/docs">
<q-item-side icon="school" />
<q-item-main label="Docs" sublabel="quasar-framework.org" />
</q-side-link>
<q-side-link item to="/forum">
<q-item-side icon="record_voice_over" />
<q-item-main label="Forum" sublabel="forum.quasar-framework.org" />
</q-side-link>
<q-side-link item to="/chat">
<q-item-side icon="chat" />
<q-item-main label="Gitter Channel" sublabel="Quasar Lobby" />
</q-side-link>
<q-side-link item to="/twitter">
<q-item-side icon="rss feed" />
<q-item-main label="Twitter" sublabel="@quasarframework" />
</q-side-link>
</q-list>
</div>

<!-- Right Side Panel -->
<div slot="right">
Right Side of Layout
</div>

<!-- sub-routes get injected here: -->
<router-view />

<!-- Footer -->
<q-toolbar slot="footer">
<q-toolbar-title>
Layout Footer
</q-toolbar-title>
</q-toolbar>
</q-layout>

You can also use QScrollArea for the left or right sides of the layout, if you want to control the scrollbar (but it’s not mandatory):

<!-- notice style tag -->
<q-scroll-area
slot="left"
style="width: 100%; height: 100%;"
>
<q-side-link item to="/test-layout/toolbar">Toolbar</q-side-link>
<q-side-link item to="/test-layout/tabs">Tabs</q-side-link>
<q-side-link item to="/test-layout/drawer">Drawer</q-side-link>
</q-scroll-area>

Tips to Understanding QLayout

There are multiple ways to navigate to a route from the drawer panels (left/right side of Layout). Following examples apply only from “left” and “right” Layout slots.

IMPORTANT
Avoid directly using any other means of changing current route, like <router-link>, when on a drawer panel. You also need a way to tell the drawer panel to close itself (if it’s the case, on narrow windows) before navigating away. Notice that the drawer panels can also be closed with the “back” button (both on a desktop or on a mobile device), which means they tamper with window history which must be restored before navigating to another route. Following examples show you how.

Recommended way is through QSideLink:

<q-layout>
....
<div slot="left">
<!-- navigating to "/twitter" route -->
<q-side-link item to="/twitter">
<!-- using it as QItem in this particular example -->
<q-item-side icon="rss feed" />
<q-item-main label="Twitter" sublabel="@quasarframework" />
</q-side-link>

<!--
Wrapping an icon in this example,
but note that it can wrap anything
-->
<q-side-link to="/twitter">
<q-icon name="rss feed" />
</q-side-link>
</div>
</q-layout>

Another approach would be to use a Vue reference on QLayout and call “hideCurrentSide” method:

<template>
<q-layout ref="layout">
...
<div slot="left">
<!-- navigating to "/twitter" route -->
<q-item @click="navigate">
<!-- using it as QItem in this particular example -->
<q-item-side icon="rss feed" />
<q-item-main label="Twitter" sublabel="@quasarframework" />
</q-item>

<!--
Works on any DOM element / component.
In this example we have an icon.
Make sure you understand the difference between @click and @click.native
-->
<q-icon name="rss feed" @click="navigate" />
</div>
</q-layout>
</template>

<script>
export default {
...,
methods: {
navigate () {
this.$refs.layout.hideCurrentSide(() => {
this.$router.push('/twitter')
})
}
}
}

Routing

If your layout uses Vue Router sub-routes (recommended), then it makes sense to use Vue’s <router-view> component, which is just a placeholder where sub-routes are injected.

Available Slots

QLayout uses the following Vue slots: header, footer, navigation, left and right. You can specify your content for these slots with the slot HTML attribute: slot="footer".

IMPORTANT
The slots must be direct children of <q-layout> (do not wrap them with any DOM elements / components) otherwise Vue won’t pick them up. Read about Vue content distribution with slots to understand why.

<q-layout>
...
<!--
direct child of <q-layout>
(<q-layout> is direct parent of the slot)
-->
<div slot="footer">
...Your Content...
</div>
...
</q-layout>

You can specify your own components as content for these slots too.

<q-layout>
<my-left-panel slot="left" />
</q-layout>

You can also use multiple headers, footers and navigation elements. Specify slot="header" or slot="footer" on multiple elements, when the need arises. Please note though, the order in which you specify these DOM elements / components does matter.

The Navigation Slot and Positioning

The best way to use the navigation slot is to place some QTabs, configured to use routes, within it. Those routes can be sub-routes of the route being used for the layout.

Note
Depending on the theme used, the navigation slot will be placed in different places. With the Material Design theme, the navigation slot will be after header and before the page view (but part of header). With the iOS theme, the navigation slot will be added after page view and before the footer (but part of footer).

Toolbar Placement

A great place to use the Toolbars component is within the header and footer slots.

<q-toolbar slot="header" color="green">
... toolbar content ...
</q-toolbar>

Search example

Below is an example of placing a Search bar in the header:

<q-layout>
...
<!-- We place it on header, so slot="header" -->
<q-toolbar slot="header" color="primary">
<q-search inverted v-model="search" color="none" />
</q-toolbar>
...
</q-layout>

Fixed Positioning & FABs

Also, read about the smart Fixed Positioning on Layout and learn how you can use it to also place a Floating Action Button on your Layout.

Vue Properties

Vue PropertyTypeDescription
viewStringConfiguration string which defines how different parts of the layout get displayed on screen.
revealBooleanMakes the header slide up out of view when scrolling page down and reappear, when scrolling up a bit.
left-breakpointNumberBreakpoint (in pixels, defining window width) at which point the left side will be placed directly over the layout and won’t act as a drawer anymore. Default is 992 (up to “sm”, including). Set to 0 to disable breakpoint.
right-breakpointNumberBreakpoint (in pixels, defining window width) at which point the right side will be placed directly over the layout and won’t act as a drawer anymore. Default is 992 (up to “sm”, including). Set to 0 to disable breakpoint.
header-styleObjectStyle applied to header.
header-classObjectCSS classes applied to header.
left-styleObjectStyle applied to layout left side / drawer.
left-classObjectCSS classes applied to layout left side / drawer.
right-styleObjectStyle applied to layout right side / drawer.
right-classObjectCSS classes applied to layout right side / drawer.
page-styleObjectStyle applied to content/page (between header and footer).
page-classObjectCSS classes applied to content/page (between header and footer).
footer-styleObjectStyle applied to footer.
footer-classObjectCSS classes applied to footer.

Styling

Use *-style and *-class properties (notice they need Objects) to style the containers of the layout. For example, you can set background on left side / drawer like this:

<q-layout
:left-class="{'bg-primary': true}"
...
</q-layout>

The Vue Object notation for style and class attributes is mandatory.

Configuring the “view” prop

Quasar introduces a unique and excellent layout concept, which allows you to easily structure layouts to work in certain ways, by simply changing a short string notation.

To explain how this works, imagine your Layout is a 3x3 matrix of containers. The first row of containers would be the header and the last row would be the footer. The first column of containers would be the “left” and last column would be the “right”. The center of the matrix, below the header and above the footer, would be the page or main content container.

Now think about this. This matrix of containers or “QLayout View” can be represented by a string. This string contains only 11 characters:

The picture below offers a visual representation of the QLayout View, to help you understand how to configure its 3x3 matrix.

Layout "view" prop

The letters shown above are also case sensitive. For example, using at least one “L” (uppercase character instead of lowercase) will make your layout left side (drawer) be in a fixed position. Same applies for “H” (header), “F” (footer) and finally “R” (right side / drawer).

For example, if you want your layout’s right side / drawer to be placed on the right of the header, page and footer, you’d use hhr lpr ffr. If you’d like to also make it fixed, just transform one r character to uppercase, like this: hhR lpr ffr, or hhr lpR ffr or hhr lpr ffR.

These settings are completely up to you to use as you’d like. You could even go wild with a setup like this: Lhh lpR ffr. Try it out! Make sure you also go to the desktop view, to see it work properly.

NOTE
It is important that you specify all sections of a layout, even if you don’t use them. For example, even if you don’t use footer or right side drawer, specify them within your layout’s view prop.

The “reveal” prop

You’ll notice in playing with the view configuration, if you set the header to “hhh” (all small letters), the header will be set to a static position at the top of the page. This in turn means, the header will move off the screen as the user scrolls down the page. If the user then needs to use the navigation in the header, he/she must scroll completely up to top of the page to get to it and this is bad UX.

One way to help the user, is to add a back-to-top button on the page.

Another way is to use the reveal prop.

The reveal prop overrides “H”, by fixing the header to the top of the screen. As the user scrolls down more than 100 pixels, the header rolls up it’s own height above the top of the screen. As soon as the user scrolls back up (just 1 pixel), the header comes into view again immediately.

The Breakpoints

If you’ve played with the layout in desktop mode, you might notice how the left and right sides/ drawers magically hide, as you decrease the screen width. This is part of the smart responsiveness designed into Quasar’s layout component.

If you’d like to control how the left and right side /drawers work, you have two props called left-breakpoint and right-breakpoint. These values are the minimum size of the screen in pixels, before the left and right drawers are forced to float above the layout. This is a fantastic and important function in maximizing screen real estate, for smaller devices.

Tip
If you want to also be able to toggle the left drawer with larger screen sizes, use a large value for left-breakpoint, so that basically the left drawer always works as a drawer on larger screens.

Vue Methods

Like QModal and QPopover, the drawer methods can also take callbacks which should be used if, for example, you want to hide the drawer and then emit an event, or do some other navigation (see also QSideLink). To ensure the proper sequencing of events, use code like this. Note the left drawer item hides the drawer and then emits an event to the app via the global event bus:

<q-layout ref="layout" view="lHr lpr lFr" :left-breakpoint="0" :right-breakpoint="3200">

<q-toolbar>
<q-btn flat @click="$refs.layout.toggleLeft()">
<q-icon name="menu" />
</q-btn>
</q-toolbar>

<div slot="left">
<q-item @click="$refs.layout.hideLeft(() => $q.events.$emit('editPage'))">
<q-item-side>
<q-icon name="edit" />
</q-item-side>
<q-item-main>
Edit Page
</q-item-main>
</q-item>
</div>

</q-layout>

MethodDescription
toggleLeft(Fn callback)Toggle left side state (show / hide). Takes one optional Function parameter to trigger after drawer is toggled.
showLeft(Fn callback)Show left side. Takes one optional Function parameter to trigger after drawer is shown.
hideLeft(Fn callback)Hide left side. Takes one optional Function parameter to trigger after drawer is hidden.
toggleRight(Fn callback)Toggle right side state (show / hide). Takes one optional Function parameter to trigger after drawer is toggled.
showRight(Fn callback)Show right side. Takes one optional Function parameter to trigger after drawer is shown.
hideRight(Fn callback)Hide right side. Takes one optional Function parameter to trigger after drawer is hidden.
hideCurrentSide(Fn callback)Hide currently opened layout side (right or left). Takes one optional Function parameter to trigger after drawer is hidden.

IMPORTANT
Use the callbacks to navigate to a new route or run some code logic after showing/hiding the left/right layout side.

Example of placing a button on a toolbar in the header, which will toggle the left side / drawer:

<!--
Notice we're using a Vue Reference
("ref") on QLayout
-->
<q-layout ref="layout">
<q-toolbar slot="header" color="primary">
<q-btn flat @click="$refs.layout.toggleLeft()">
<q-icon name="menu" />
</q-btn>
...
</q-toolbar>
...
</q-layout>

There’s also the possibility to use v-model to control the left/right sides toggling. Note this is only when the viewport is above the threshold (so on desktop), and won’t work on small mobile screens. For now, use the showLeft() / hideLeft() / toggleLeft() methods (see above):

<template>
<q-layout v-model="sides">
<q-toolbar slot="header" color="primary">
<q-btn flat @click="sides.left = !sides.left">
<q-icon name="menu" />
</q-btn>
...
</q-toolbar>
...
</q-layout>
</template>

<script>
export default {
data () {
return {
sides: {
// "false" means hidden
// "true" means visible
left: false,
right: true
}
}
}
}
</script>

Vue Events

Event NameDescription
@resizeEvent emitted on window resize.
@scrollEvent emitted on page scroll.
@left-breakpointEvent emitted when window width toggles above/below left side breakpoint (see left-breakpoint prop)
@right-breakpointEvent emitted when window width toggles above/below right side breakpoint (see right-breakpoint prop)

Vue Injections

Property NameDescription
layoutThis whole component. Usefull for accessing closing/opening methods from deep descendants.

New to Vue Provide/Inject? Read this!