Diagnosing Layout Shift and Component Mounting in Quasar Applications
If your Quasar application visibly jumps after page load, the cause is usually a mismatch between server-rendered HTML and client-side layout recalculation. Learn to diagnose and fix q-page layout shifts using the view prop, skeleton loaders, and DevTools.
08 Oct 2025, 21:05 UTC

If your Quasar application visibly jumps or shifts the moment the page finishes loading, the problem is usually a mismatch between the server-rendered HTML and the client-side layout recalculation. The useful takeaway is that q-page relies on the Quasar Layout engine to compute its min-height from surrounding headers, footers, and drawers. When that calculation is delayed or wrong, the browser repaints the content at a new position, producing a jarring layout shift.
The Symptom: A Visible Jump After Hydration
You see the main content area snap to a different vertical position immediately after the initial paint. In Chrome DevTools, enabling Layout Shift Regions under the Rendering tab highlights the affected region in blue. The DOM structure of .q-layout and .q-page may also change between the server response and the fully interactive client.
This condition is common in applications using Server-Side Rendering (SSR), where Vue renders the component tree on the server, sends HTML to the browser, and then hydrates it by attaching event listeners and recalculating layout metrics on the client.
Why Quasar Layouts Shift After Mount
Quasar's q-layout component manages a grid of regions: headers, footers, left and right drawers, and the central q-page. To position q-page correctly, the layout engine reads the view prop on each q-page instance. That prop declares which layout regions the page must respect—for example, view="h1 v1" tells the engine to reserve space for the first header and the first vertical boundary.
If the view prop is missing or incomplete, the engine cannot determine the correct min-height during the initial render cycle. The server may emit a container with one height, and the client may recalculate a different height once JavaScript runs. That discrepancy is the layout shift.
A second cause is asynchronous work inside onMounted. If a component fetches data and then renders a list or image, the q-page content grows after hydration, pushing subsequent elements downward.
Quick Diagnostic Table
| Condition | Likely Cause | How to Confirm |
|---|---|---|
| Jump occurs only after JS loads, not on raw HTML | Missing or wrong view prop on q-page | Compare computed min-height of .q-page before and after hydration in DevTools |
| Jump happens when data appears | Async state change in onMounted altering content size | Throttle network to Slow 3G and watch the shift timing |
| Jump only on mobile viewports | Responsive drawer or header height not accounted for by view | Toggle device toolbar and inspect .q-page padding |
Ordered Checks
- Inspect the
viewprop. Open the component containingq-page. Confirm thatviewlists every layout region the page should avoid. A typical value for a page under a header and above a footer isview="h1 f1"; if the page also sits beside a left drawer, addl1. - Measure the container. In Chrome DevTools, select the
.q-pageelement. Note its computedmin-heightduring the initial render, then compare it after hydration. A difference larger than a few pixels indicates the layout engine recalculated boundaries. - Audit
onMountedhooks. Search foronMountedin the page component and its children. Flag any API calls, store dispatches, or ref mutations that change the number or size of rendered elements. - Check for hard-coded heights. Look for inline styles or CSS rules setting a fixed pixel height on
.q-pageor its direct children. These override the responsive layout system and often cause shifts on different screen sizes.
Fixes Tied to Findings
Finding 1: Missing or Incorrect view Property
When the diagnostic table points to a view mismatch, declare the layout regions explicitly so the engine reserves space on both the server and the client.
<q-layout view="hHh lpR fFf">
<q-header>...</q-header>
<q-page-container>
<q-page view="h1 v1">
<!-- page content -->
</q-page>
</q-page-container>
</q-layout>
In this example, view="h1 v1" tells the layout to respect the first header and the first vertical boundary. Adjust the tokens to match your actual layout configuration. Avoid replacing this with a fixed pixel min-height, because hard-coded values break the responsive behavior of the layout system.
Finding 2: Async Content Injection in onMounted
If the shift occurs when data arrives, stabilize the initial container size or mask the growth with a placeholder.
<script setup>
import { ref, onMounted } from 'vue'
const items = ref(null)
onMounted(async () => {
items.value = await fetchItems()
})
</script>
<template>
<q-page view="h1 v1">
<div v-if="items === null" class="skeleton-block"></div>
<div v-else>
<div v-for="item in items" :key="item.id">{{ item.label }}</div>
</div>
</q-page>
</template>
<style scoped>
.skeleton-block {
min-height: 300px; /* illustrative only; match your content's expected height */
}
</style>
The skeleton block reserves vertical space so the page does not collapse and then expand. Replace the illustrative min-height with a value derived from your actual content, or use a CSS aspect-ratio container if the content is media-driven. A transition wrapper can also smooth the swap, but it does not remove the underlying reflow.
Verifying the Fix
Open Chrome DevTools, press Ctrl+Shift+P (or Cmd+Shift+P on macOS), type Show Rendering, and enable Layout Shift Regions. Reload the page with the network throttled to Slow 3G. If the blue highlight no longer appears during hydration, the initial container size is stable.
As a second check, compare the DOM subtree of .q-layout in the server response against the live DOM after hydration. The style attribute on .q-page should not change its min-height after JavaScript executes.
Limitations and Escalation Criteria
These fixes address layout shifts caused by Quasar's layout engine and Vue hydration. They do not solve shifts originating from late-loading web fonts, third-party scripts, or images without explicit dimensions. If the jump persists after correcting the view prop and stabilizing async content, audit those external resources next.
Escalate to a framework issue only when you can reproduce the shift in a minimal Quasar v2 / Vue 3 project with no custom CSS, no async data, and a correctly declared view prop. In that case, capture the computed min-height values before and after hydration and include them in your report. Do not assume the behavior is a bug until the minimal reproduction confirms it.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.