DXDashboard

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 ascendingType Required Click to sort ascendingDefault Description
navigationNavigationNorequiredNavigation structure with groups and items
currentUrlstringNorequiredCurrent URL path for active state detection
titlestringNo'Dashboard'Dashboard title shown in sidebar brand
pageTitlestringNo''Page title shown in navbar
fluidbooleanNofalseRender page content full-width and left-aligned instead of the default centred, reading-width column. For wide tables / admin pages
contentMaxWidthstringNo'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
contentClassstringNo-Extra class(es) applied to the content container/column
user{ name: string; email: string } | nullNonullUser 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
storageKeystringNo'dashboard-sidebar-hidden'LocalStorage key for sidebar state persistence

Slots

Name Click to sort ascendingDescription Scoped Props
defaultMain page content rendered in the content area-
sidebar-brandCustom brand/logo content for sidebar header-
sidebar-linkCustom link rendering in sidebar navigation-
sidebar-footerUtility links pinned to the bottom of the sidebar (help, changelog, sign-out, …)-
navbar-menu-iconCustom hamburger menu icon for navbar-
navbar-searchCustom search component for navbar-
navbar-actionsPage-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-iconCustom user icon/avatar in navbar dropdown (defaults to DXUserAvatar)-
navbar-user-menuCustom 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"
      >
        &times;
      </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>