Skip to content

useLayout ​

Resolves which of the six shells wraps the page: what the route asked for, then what the config says, then classic.

Open in demo

Import ​

ts
import { useLayout } from '@/layouts/useLayout'

Signature ​

ts
function useLayout(): {
  resolvedLayout: ComputedRef<Component>
  setLayout: (name: 'classic' | 'modern' | 'minimal' | 'horizontal') => void
}

Returns ​

MemberTypeDescription
resolvedLayoutComputedRef<Component>The layout component to render.
setLayout(name) => voidWrites config.ui.layout, so the choice persists.

The six layouts ​

NameSettable from configWhat it is
classicYesSidebar and navbar.
modernYesThe default: a floating card shell.
minimalYesReduced chrome.
horizontalYesTop navigation, no sidebar.
authRoute meta onlyThe sign-in shell.
blankRoute meta onlyNo chrome at all, for print views and embedded widgets.

auth and blank are route-meta only, which is why setLayout will not take them — a config that could switch the whole app to blank would leave no way back.

Example ​

vue
<script setup lang="ts">
import { useLayout } from '@/layouts/useLayout'

const { resolvedLayout, setLayout } = useLayout()
</script>

<template>
  <component :is="resolvedLayout">
    <RouterView />
  </component>

  <button type="button" @click="setLayout('horizontal')">
    Top navigation
  </button>
</template>

Asking for one from a route:

vue
<route lang="json">
{
  "path": "/invoices/:id/print",
  "meta": { "layout": "blank" }
}
</route>

Notes ​

  • The layouts are imported eagerly, not lazily. A switchable layout has to change instantly from Settings, and a suspense flash on every switch would make the setting feel broken.
  • blank is a two-line passthrough component defined inline — it renders its default slot and nothing else.
  • The resolution order is route.meta.layout, then config.ui.layout, then 'classic'. A route that names a layout always wins, which is how the sign-in pages stay on auth whatever the reader has chosen.
  • setLayout goes through useConfig().setUi, so it is persisted like every other UI preference.