Routing & links
How the framework-agnostic library integrates with your router.
The core @adminlte/vue library never imports a router. Instead, LteDashboardLayout takes a small set of props that let you wire it to whatever routing solution your app uses — Nuxt, Vue Router, or plain anchors. This keeps the library framework-agnostic while still giving you active-link highlighting and working navigation in the command palette.
The three integration points
| Prop | Type | Default | What it does |
|---|---|---|---|
currentPath | string | '/' | The current route path. Used for active-link detection in the sidebar — the nav item whose href matches gets the active state. |
linkComponent | string | Component | 'a' | The component used to render sidebar and palette links. Pass your router's link component (e.g. NuxtLink) for client-side navigation. |
navigate | (href: string) => void | — | Callback invoked when a command-palette result is chosen or a sidebar link is clicked. Wire it to your router's programmatic navigation. |
By default the layout renders plain <a> tags and reads currentPath as '/', so it works with zero configuration — links just do full-page navigation.
linkComponent or navigate?
Either one gives you client-side navigation in the sidebar — pick whichever fits your app:
linkComponentrenders your router's own link component, so you get its prefetching,aria-currenthandling and realhrefs for free. Prefer it when you have one.navigatekeeps the plain<a>markup and intercepts clicks, calling your callback with the item'shref. Useful when you have no link component (a custom router, an embedded app, or navigation that runs through your own logic — analytics, unsaved-changes guards).
Passing both is safe: the link component handles the click first, and the sidebar stands down rather than navigating twice.
The interception is deliberately conservative — the browser keeps handling anything that isn't a plain in-app navigation:
| Click | Handled by |
|---|---|
Plain left click on an in-app href | navigate |
| Ctrl / ⌘ / Shift / Alt click, middle click | Browser (new tab / window) |
target: '_blank' | Browser |
Absolute URL (https://…), protocol-relative (//…), mailto: | Browser |
Placeholder / hash-only href ('#', '#section') | Browser |
Nuxt example
In Nuxt, pull the current path from useRoute(), resolve NuxtLink for client-side navigation, and pass navigateTo as the palette's navigate callback.
<script setup lang="ts">
import { resolveComponent } from 'vue'
import type { MenuNode } from '@adminlte/vue'
const route = useRoute()
const NuxtLink = resolveComponent('NuxtLink')
const menuItems: MenuNode[] = [
{ type: 'header', text: 'MAIN' },
{ type: 'item', text: 'Dashboard', href: '/', icon: 'bi-speedometer' },
{
type: 'group',
text: 'Pages',
icon: 'bi-files',
children: [
{ type: 'item', text: 'Profile', href: '/pages/profile' },
{ type: 'item', text: 'Settings', href: '/pages/settings' },
],
},
]
</script>
<template>
<LteDashboardLayout
:menu-items="menuItems"
:current-path="route.path"
:link-component="NuxtLink"
:navigate="navigateTo"
>
<slot />
</LteDashboardLayout>
</template>
The @adminlte/nuxt module auto-registers LteDashboardLayout and auto-imports the MenuNode type, so no manual component import is needed in a Nuxt app.
Vue Router example
The same props work with plain Vue Router — resolve RouterLink, read the path from the current route, and use router.push for the palette.
<script setup lang="ts">
import { resolveComponent } from 'vue'
import { useRoute, useRouter } from 'vue-router'
import { LteDashboardLayout, type MenuNode } from '@adminlte/vue'
const route = useRoute()
const router = useRouter()
const RouterLink = resolveComponent('RouterLink')
const menuItems: MenuNode[] = [
{ type: 'item', text: 'Dashboard', href: '/', icon: 'bi-speedometer' },
]
</script>
<template>
<LteDashboardLayout
:menu-items="menuItems"
:current-path="route.path"
:link-component="RouterLink"
:navigate="(href) => router.push(href)"
>
<RouterView />
</LteDashboardLayout>
</template>
Most router link components (
NuxtLink,RouterLink) accept anhref/toprop and render an anchor, so the sidebar's link rendering stays compatible. With the default'a', links navigate with a full page load.
The menu structure
A single MenuNode[] array drives both the sidebar navigation tree and the ⌘K command palette. MenuNode is a discriminated union of three node types, distinguished by the type field.
MenuHeader
A non-interactive section label.
| Field | Type | Description |
|---|---|---|
type | 'header' | Discriminant. |
text | string | The label text. |
MenuItem
A clickable leaf link.
| Field | Type | Description |
|---|---|---|
type | 'item' | Discriminant. |
text | string | Link label. |
href | string | Link target. Matched against currentPath for the active state. |
icon | string | Bootstrap Icons class, e.g. 'bi-speedometer' (with or without the leading bi). |
iconColor | BootstrapTheme | Icon color variant. |
badge | string | number | Optional badge content. |
badgeColor | BootstrapTheme | Badge color variant. |
target | '_blank' | '_self' | Anchor target. |
attrs | Record<string, string | number | boolean> | Extra attributes spread onto the rendered link — data-* hooks for tests/analytics, aria-*, rel, title. The resolved link target always wins, so attrs cannot overwrite href / to. |
MenuGroup
A collapsible submenu (treeview) that nests further MenuNodes.
| Field | Type | Description |
|---|---|---|
type | 'group' | Discriminant. |
text | string | Group label. |
icon | string | Bootstrap Icons class. |
iconColor | BootstrapTheme | Icon color variant. |
badge | string | number | Optional badge content. |
badgeColor | BootstrapTheme | Badge color variant. |
children | MenuNode[] | Nested nodes — groups can nest other groups for multi-level menus. |
attrs | Record<string, string | number | boolean> | Extra attributes spread onto the group's toggle <button>. |
import type { MenuNode } from '@adminlte/vue'
const menuItems: MenuNode[] = [
{ type: 'header', text: 'NAVIGATION' },
{ type: 'item', text: 'Dashboard', href: '/', icon: 'bi-speedometer' },
{
type: 'group',
text: 'Pages',
icon: 'bi-files',
badge: 4,
badgeColor: 'secondary',
children: [
{
type: 'item',
text: 'Profile',
href: '/pages/profile',
attrs: { 'data-testid': 'nav-profile' },
},
{
type: 'group',
text: 'Auth',
children: [
{ type: 'item', text: 'Login', href: '/login' },
{ type: 'item', text: 'Register', href: '/register' },
],
},
],
},
]
Active-link detection & the treeview
The sidebar compares each MenuItem's href against currentPath to apply the active class. Because currentPath is reactive, the highlighted item updates automatically on navigation when you wire it to route.path.
For nested menus, set accordion on the layout to keep only one group open at a time:
<LteDashboardLayout :menu-items="menuItems" :current-path="route.path" :accordion="true">
<slot />
</LteDashboardLayout>