jacquestrdx123 / vue-sidebar-menu
A Laravel package providing a database-driven sidebar menu system with Vue 3 components
Package info
github.com/jacquestrdx123/vue-sidebar-menu
pkg:composer/jacquestrdx123/vue-sidebar-menu
Requires
- php: ^8.1
- illuminate/console: ^9.0|^10.0|^11.0|^12.0
- illuminate/database: ^9.0|^10.0|^11.0|^12.0
- illuminate/support: ^9.0|^10.0|^11.0|^12.0
Requires (Dev)
- orchestra/testbench: ^7.0|^8.0|^9.0|^10.0
README
A Laravel Composer package providing a database-driven sidebar menu system with Vue 3 components and Inertia.js integration.
Features
- Database-driven menu structure (MenuGroups and MenuItems)
- Permission-based menu item visibility
- Nested menu items support
- User favorite menu items
- Search functionality
- Collapsible sidebar
- Responsive design
- Inertia.js integration
Requirements
- Laravel 9+ or 10+
- Vue 3
- Inertia.js
- PHP 8.1+
Installation
- Install the package via Composer:
composer require jacquestredoux/vue-sidebar-menu
- Install Heroicons (required dependency):
npm install @heroicons/vue
- Run the install command:
php artisan vue-sidebar-menu:install
This will:
- Publish migrations to
database/migrations/ - Publish Vue components to
resources/js/Components/SidebarMenu/ - Publish icon mapper utility to
resources/js/utils/iconMapper.js - Publish config file to
config/vue-sidebar-menu.php
- Run migrations:
php artisan migrate
- (Optional) Remove Material Icons from your CSS if no longer needed:
Remove the Material Icons import from your resources/css/app.css:
/* Remove this line if you're no longer using Material Icons */ @import url("https://fonts.googleapis.com/css2?family=Material+Icons");
Configuration
The config file is published to config/vue-sidebar-menu.php. You can customize:
cache_time: Cache duration for user permissions (defaults to 5 minutes in debug, 1 hour in production)member_model: Member model class name (if you have a separate Member model)user_model: User model class name (defaults to Laravel auth provider)
Usage
1. Share Menu Data via Inertia Middleware
Update your app/Http/Middleware/HandleInertiaRequests.php:
use JacquesTredoux\VueSidebarMenu\Services\MenuWebService; use Inertia\Inertia; class HandleInertiaRequests extends Middleware { public $menuService; public function __construct(RootTemplateProvider $rootTemplateProvider) { $this->rootTemplateProvider = $rootTemplateProvider; $this->menuService = app(MenuWebService::class); } public function share(Request $request): array { $user = $request->user(); return [ ...parent::share($request), 'ziggy' => fn () => [ ...(new Ziggy)->toArray(), 'location' => $request->url(), ], 'menu' => $this->menuService->getMenu($request->route()?->getName(), $user), 'favoriteMenuItems' => $this->menuService->getFavoriteMenuItems($user), ]; } }
2. Include SidebarMenu Component in Your Layout
In your authenticated layout file (e.g., resources/js/Layouts/Authenticated.vue):
<template> <div class="flex"> <SidebarMenu :logo-url="'/images/logo.png'" :logo-alt="'My Logo'" /> <main :class="[ 'flex-1 transition-all duration-300', isSidebarCollapsed ? 'ml-16' : 'ml-[250px]', ]" > <slot /> </main> </div> </template> <script setup> import { useSidebar } from "@/Components/SidebarMenu/composables/useSidebar.js"; import SidebarMenu from "@/Components/SidebarMenu/SidebarMenu.vue"; const { isCollapsed: isSidebarCollapsed } = useSidebar(); </script>
3. Set Up Menu Groups and Items
You can create menu groups and items via database seeders or directly in the database:
use JacquesTredoux\VueSidebarMenu\Models\MenuGroup; use JacquesTredoux\VueSidebarMenu\Models\MenuItem; // Create a menu group $group = MenuGroup::create([ 'key' => 'dashboard', 'label' => 'Dashboard', 'icon' => 'heroicon-o-home', 'sort_order' => 1, 'is_active' => true, ]); // Create a menu item MenuItem::create([ 'menu_group_id' => $group->id, 'key' => 'main-dashboard', 'label' => 'Main Dashboard', 'icon' => 'heroicon-o-chart-bar', 'route' => 'vue.dashboard', 'permission_name' => 'view_any_dashboard', // Optional: require permission 'sort_order' => 1, 'is_active' => true, ]);
4. (Optional) Add Favorite Menu Items Support
Add the relationship to your User model:
use JacquesTredoux\VueSidebarMenu\Models\UserFavoriteMenuItem; public function favoriteMenuItems() { return $this->hasMany(UserFavoriteMenuItem::class); } public function getFavoriteMenuKeys() { return $this->favoriteMenuItems()->pluck('menu_key')->toArray(); }
Menu Item Structure
MenuGroup Fields
key: Unique identifier (e.g., 'dashboard', 'finance')label: Display nameicon: Icon name (supports both Material Design and Heroicons - see Icon Support below)sort_order: Display orderis_active: Whether the group is active
MenuItem Fields
menu_group_id: Foreign key to menu_groupsparent_id: Foreign key to menu_items (for nested items, nullable)key: Unique identifier within the grouplabel: Display nameicon: Icon name (supports both Material Design and Heroicons - see Icon Support below)url: Direct URL (fallback, nullable)route: Laravel route name (nullable)permission_name: Required permission name (nullable)sort_order: Display orderis_active: Whether the item is active
Icon Support
The package uses Heroicons by default, but includes backward compatibility with Material Design icons through the iconMapper utility.
Supported Icon Formats
-
Heroicons (recommended):
- Simple name:
home,user,settings - Full name:
heroicon-o-home,heroicon-o-user
- Simple name:
-
Material Design Icons (backward compatible):
- Material icon name:
home,dashboard,settings - MDI format:
mdi-home,mdi-dashboard
- Material icon name:
The icon mapper automatically converts Material Design icon names to their Heroicon equivalents. Common mappings include:
home/mdi-home→HomeIcondashboard/mdi-view-dashboard→ChartBarIconsettings/mdi-cog→Cog6ToothIconuser/mdi-account→UserIcon- And many more...
See resources/js/utils/iconMapper.js for the complete mapping list.
Permission System
The package supports permission-based menu item visibility. It works with:
- Spatie Laravel Permission (via
getAllPermissions()method) - Custom permission systems (via
permissions()relationship)
Permission names are automatically generated from route names:
- Route:
vue.roles.index→ Permissions:view_any_role,view_any_role::*
Customization
Logo
Pass the logo URL and alt text as props:
<SidebarMenu logo-url="/images/logo.png" logo-alt="Company Logo" />
Styling
The component uses Tailwind CSS classes. You can customize colors by modifying the classes in the published Vue components.
Icon Customization
The icon mapper utility (resources/js/utils/iconMapper.js) supports both Material Design and Heroicon formats. You can:
- Use Heroicons directly (recommended):
MenuItem::create([ 'icon' => 'home', // or 'heroicon-o-home' // ... ]);
- Continue using Material Design icons (backward compatible):
MenuItem::create([ 'icon' => 'mdi-home', // Automatically converted to HomeIcon // ... ]);
- Extend the icon mapper with custom mappings in your application's
resources/js/utils/iconMapper.jsfile.
License
MIT
Key Features
- Database-Driven Menu: Menu structure is stored in database tables instead of hardcoded arrays
- Permission-Based Filtering: Menu items are filtered based on user permissions
- Favorite Menu Items: Users can favorite menu items for quick access
- Search Functionality: Built-in search to filter menu items
- Collapsible Sidebar: Sidebar can be collapsed/expanded with state persistence in localStorage
- Active Route Highlighting: Current route is automatically highlighted in the menu
- Nested Menu Support: Supports multi-level nested menu items
- Heroicons Integration: All icons use Heroicons (with Material Design backward compatibility)
- Responsive Design: Automatically collapses on mobile devices
Migration from Material Icons
If you're migrating from a Material Icons-based menu system:
- The icon mapper automatically handles conversion of Material Design icon names to Heroicons
- Your existing menu items in the database will continue to work
- No need to update icon names in the database - the package handles the conversion automatically
- You can optionally remove Material Icons from your CSS after migration
Troubleshooting
Icons Not Displaying
- Ensure
@heroicons/vueis installed:npm install @heroicons/vue - Check that the icon mapper utility is published:
resources/js/utils/iconMapper.js - Verify icon names in your database match supported formats
Sidebar Not Showing
- Ensure the
SidebarMenucomponent is imported and included in your layout - Check that menu data is shared via Inertia middleware
- Verify the component path is correct:
@/Components/SidebarMenu/SidebarMenu.vue
Menu Items Not Filtering by Permissions
- Verify user permissions are being loaded correctly
- Check that
permission_nameis set correctly in menu items - Ensure your User model implements
Authorizableinterface (Laravel default)
Support
For issues and questions, please open an issue on GitHub.