DXDashboard
Complete dashboard layout component that combines sidebar navigation, top navbar, and content area. Handles all state management and provides extensive customisation through slots.
Live Examples
Props
| Name Click to sort ascending | Type | Required Click to sort ascending | Default | Description |
|---|---|---|---|---|
navigation | Navigation | No | required | Navigation structure with groups and items |
currentUrl | string | No | required | Current URL path for active state detection |
title | string | No | 'Dashboard' | Dashboard title shown in sidebar brand |
pageTitle | string | No | '' | Page title shown in navbar |
fluid | boolean | No | false | Render page content full-width and left-aligned instead of the default centred, reading-width column. For wide tables / admin pages |
contentMaxWidth | string | No | '1140px' | Max width of the centred content column (any CSS length) — a genuine cap so pages don’t stretch to ~2000px on a wide display. Ignored when fluid |
contentClass | string | No | - | Extra class(es) applied to the content container/column |
user | { name: string; email: string } | null | No | null | User object for navbar dropdown |
searchAlign | 'start' | 'center' | No | 'start' | Horizontal alignment of the navbar search slot content (start = flush left, center = centred), forwarded to DXDashboardNavbar |
actionsOnMobile | 'wrap' | 'hide' | No | 'wrap' | What the navbar actions slot does below md: wrap moves it to its own full-width row, hide removes it (relocate actions into the page on phones). Forwarded to DXDashboardNavbar |
storageKey | string | No | 'dashboard-sidebar-hidden' | LocalStorage key for sidebar state persistence |
Slots
| Name Click to sort ascending | Description | Scoped Props |
|---|---|---|
default | Main page content rendered in the content area | - |
sidebar-brand | Custom brand/logo content for sidebar header | - |
sidebar-link | Custom link rendering in sidebar navigation | - |
sidebar-footer | Utility links pinned to the bottom of the sidebar (help, changelog, sign-out, …) | - |
navbar-menu-icon | Custom hamburger menu icon for navbar | - |
navbar-search | Custom search component for navbar | - |
navbar-actions | Page-level primary actions (e.g. a Create button). Right-aligned next to the user menu from md up; below, wraps to its own full-width row or is hidden entirely per actionsOnMobile | - |
navbar-user-icon | Custom user icon/avatar in navbar dropdown (defaults to DXUserAvatar) | - |
navbar-user-menu | Custom user dropdown menu content | - |
Every forwarded sidebar-* and navbar-* slot also receives toggleSidebar
and sidebarHidden on top of the underlying slot’s own bindings — see
Controlling the sidebar.
Features
- Combined Layout - Integrates DXDashboardSidebar and DXDashboardNavbar
- State Management - Handles sidebar toggle and localStorage persistence
- Responsive - Works on mobile and desktop
- Customisable - Extensive slot system for customisation
- Type-Safe - Full TypeScript support with proper types
Usage Example
Basic Usage
<template>
<DXDashboard
:navigation="navigation"
:current-url="route.path"
title="My Application"
:page-title="pageTitle"
:user="authUser"
>
<!-- Your page content here -->
<h1>Welcome to the Dashboard</h1>
</DXDashboard>
</template>
<script setup lang="ts">
import { DXDashboard } from '@omnitend/dashboard-for-laravel';
const navigation = [
{
label: 'Main',
items: [
{ label: 'Dashboard', url: '/dashboard' },
{ label: 'Customers', url: '/customers' },
],
},
];
const authUser = { name: 'John Doe', email: 'john@example.com' };
const pageTitle = 'Dashboard';
</script>
With Icons
Navigation items can include icons using unplugin-icons or any Vue component:
<script setup lang="ts">
import { DXDashboard } from '@omnitend/dashboard-for-laravel';
import IconHome from '~icons/lucide/home';
import IconUsers from '~icons/lucide/users';
import IconSettings from '~icons/lucide/settings';
const navigation = [
{
items: [
{ label: 'Dashboard', url: '/dashboard', icon: IconHome },
{ label: 'Customers', url: '/customers', icon: IconUsers },
],
},
{
label: 'Settings',
items: [
{ label: 'Preferences', url: '/settings', icon: IconSettings },
],
},
];
</script>
Icon Setup (unplugin-icons):
Install packages:
npm install --save-dev unplugin-icons @iconify-json/lucide
Configure in vite.config.ts:
import Icons from 'unplugin-icons/vite';
export default defineConfig({
plugins: [
Icons({
compiler: 'vue3',
}),
],
});
Then import icons using the ~icons/ prefix:
import IconName from '~icons/lucide/icon-name';
Custom Branding
<DXDashboard :navigation="navigation" current-url="/dashboard">
<template #sidebar-brand="{ collapsed }">
<div class="d-flex align-items-center">
<img v-if="!collapsed" src="/logo.svg" alt="Logo" />
<span v-else>L</span>
</div>
</template>
<!-- content -->
</DXDashboard>
Controlling the sidebar
DXDashboard owns the sidebar’s visibility state (and persists it to localStorage), so it exposes that state rather than leaving you to click the navbar’s hamburger from script.
Every forwarded sidebar-* and navbar-* slot receives two extra bindings:
toggleSidebar— shows/hides the sidebar (the same action as the navbar’s hamburger).sidebarHidden— whether the sidebar is currently hidden.
Use them to put a close affordance in the sidebar itself, or a toggle among the navbar actions:
<DXDashboard :navigation="navigation" current-url="/dashboard">
<template #sidebar-brand="{ collapsed, toggleSidebar }">
<div class="d-flex align-items-center justify-content-between w-100">
<img v-if="!collapsed" src="/logo.svg" alt="Logo" />
<DButton
variant="link"
aria-label="Close sidebar"
@click="toggleSidebar"
>
×
</DButton>
</div>
</template>
<template #navbar-actions="{ toggleSidebar, sidebarHidden }">
<DButton size="sm" variant="outline-secondary" @click="toggleSidebar">
{{ sidebarHidden ? 'Show menu' : 'Hide menu' }}
</DButton>
</template>
</DXDashboard>
The same API is available on a template ref, for page content or a keyboard
shortcut that sits outside those slots:
<script setup lang="ts">
import { ref } from 'vue';
import { DButton, DXDashboard } from '@omnitend/dashboard-for-laravel';
const dashboard = ref(null);
const toggle = () => dashboard.value?.toggleSidebar();
</script>
<template>
<DXDashboard ref="dashboard" :navigation="navigation" current-url="/dashboard">
<DButton @click="toggle">
{{ dashboard?.sidebarHidden ? 'Show menu' : 'Hide menu' }}
</DButton>
</DXDashboard>
</template>
Notes
This component requires CSS for sidebar visibility control. Add this to your global styles or layout:
.dashboard-sidebar {
display: none !important;
}
html.sidebar-visible .dashboard-sidebar {
display: block !important;
}
For Astro projects with SSR, add an inline script to prevent flicker:
<script is:inline>
(function() {
try {
const hidden = localStorage.getItem('dashboard-sidebar-hidden');
if (hidden === 'false') {
document.documentElement.classList.add('sidebar-visible');
}
} catch (e) {}
})();
</script>