FAQ
Common questions about adminlte-vue.
Answers to the questions that come up most often when adopting adminlte-vue — the framework-agnostic AdminLTE 4 / Bootstrap 5.3 component library for Vue 3 and Nuxt.
Why is the package ESM-only?
The library ships as ESM only — there is no CommonJS build. State is shared through provide/inject using injection keys that are module-singleton Symbols (in src/composables/keys.ts). A dual ESM/CJS build could load those modules twice, duplicate the Symbols, and silently break injection between LteDashboardLayout and its descendants.
The package.json reflects this: "type": "module" with only an import condition per export.
"exports": {
".": { "types": "./dist/index.d.ts", "import": "./dist/index.js" },
"./plugins": { "types": "./dist/plugins.d.ts", "import": "./dist/plugins.js" },
"./css": "./dist/css/adminlte.css",
"./css/rtl": "./dist/css/adminlte.rtl.css"
}
There are two JS entry points: . for the core components/composables and ./plugins for the heavy third-party wrappers. The split keeps the plugin libs out of the default import.
Why no Pinia in the library?
The core library uses composables + provide/inject rather than a store. LteDashboardLayout is the single provider host: in setup() it calls provideSidebar(), provideColorMode(), and provideCommandPalette(), and installs useLteBehaviors() + useAccessibility(). Descendants consume that state with useSidebar(), useColorMode(), and useCommandPalette(), which throw a clear error if used outside the layout.
This keeps the library dependency-free and is the Vue analog of the React port's Context + hooks pattern. Bring your own store (e.g. Pinia) at the app level for domain state — the library doesn't impose one.
Do I need Nuxt to use it?
No. adminlte-vue is framework-agnostic and works in any Vue 3 / Vite app. Register it as a plugin and import the CSS:
import { createApp } from 'vue'
import AdminLte from 'adminlte-vue'
import 'adminlte-vue/css'
import App from './App.vue'
createApp(App).use(AdminLte).mount('#app')
If you do use Nuxt, the @adminlte/nuxt module handles the wiring for you: it auto-registers the components, auto-imports the composables, pushes adminlte-vue/css into nuxt.options.css, initializes Bootstrap's JS client-side, and injects an SSR-safe color-mode head script.
How are the heavy plugins handled?
Heavy third-party libraries are never statically imported. Each wrapper under src/plugins/*.vue does an await import(...) inside onMounted, guards against the element being gone, and destroys the instance in onBeforeUnmount. They are also a separate entry point (adminlte-vue/plugins) so they stay out of the default bundle.
Because they load dynamically and touch the DOM, wrap them in <ClientOnly> under Nuxt:
<template>
<ClientOnly>
<LteApexChart :options="options" :series="series" />
<template #fallback>Loading chart…</template>
</ClientOnly>
</template>
You install only the libs you actually use (and load their CSS yourself) — see the peer dependencies below.
How do I use my own router / link component?
The core is decoupled from any router. The layout takes a currentPath prop for active-link detection and a linkComponent prop (default 'a') for the element to render links with. In Nuxt you'd pass the current route path and NuxtLink:
<script setup lang="ts">
const route = useRoute()
const NuxtLink = resolveComponent('NuxtLink')
</script>
<template>
<LteDashboardLayout :current-path="route.path" :link-component="NuxtLink" :menu="menu">
<!-- page content -->
</LteDashboardLayout>
</template>
The command palette accepts a navigate callback (e.g. navigateTo) for the same reason.
What are the peerDependencies?
vue (^3.5.0) is the only one you'll always need. Everything else is an optional peer dependency — install a lib only if you use the wrapper that depends on it.
| Peer dependency | Version range | Required | Used by |
|---|---|---|---|
vue | ^3.5.0 | Yes | the whole library |
bootstrap | ^5.3.0 | Optional* | dropdowns, modals, offcanvas |
apexcharts | ^4.0.0 || ^5.0.0 | Optional | LteApexChart |
tabulator-tables | ^6.0.0 | Optional | data tables |
quill | ^2.0.0 | Optional | rich-text editor |
flatpickr | ^4.6.0 | Optional | date picker |
tom-select | ^2.0.0 | Optional | select inputs |
sortablejs | ^1.15.0 | Optional | drag-and-drop |
jsvectormap | ^1.5.0 | Optional | vector maps |
overlayscrollbars | ^2.0.0 | Optional | custom scrollbars |
@fullcalendar/core | ^6.0.0 | Optional | calendar |
@fullcalendar/daygrid | ^6.0.0 | Optional | calendar |
@fullcalendar/interaction | ^6.0.0 | Optional | calendar |
* bootstrap is declared optional in peerDependenciesMeta, but in practice you need it for the interactive widgets (dropdowns, modals, offcanvas) to work. The @adminlte/nuxt module imports it for you on the client.
Do I need Bootstrap?
Yes — the design system is Bootstrap 5.3, and AdminLTE 4's CSS builds on top of it. Bootstrap's JavaScript data-API powers the interactive widgets (dropdowns, modals, offcanvas). Under Nuxt, the module loads bootstrap client-side automatically; in a plain Vue app you import it yourself.
Is RTL / i18n supported?
RTL is supported via a prebuilt stylesheet. Import the RTL CSS export instead of (or alongside) the default one:
import 'adminlte-vue/css/rtl'
i18n is not built into the core component library — its strings come from the props and menu data you pass in, so you localize at the app level with your own solution (for example @nuxtjs/i18n): translate your menu/labels and pass them in.