Logo Beartropy

Navbar / Sidebar

The x-nav component is a fully featured, highly customizable sidebar navigation built for modern dashboards.
It supports categories, nested submenus, icons, badges, tooltips, dividers, permission filtering, external links, sidebar collapse (with Alpine.js), and much more.
Navigation data can be passed as an array, loaded from a config file, or generated dynamically—making it perfect for any Laravel app.
You can customize this component

Features

  • Multi-category and nested navigation: Organize your menu in multiple categories, each with unlimited levels of children/submenus.
  • Sidebar collapse support: Fully supports collapsing sidebars (with Alpine.js, Livewire, or custom state).
  • Active state detection: Automatically highlights active items by route match, wildcard pattern (match), or if any child is active.
  • Presets for color, style, and highlight mode: Easily switch style using props like color="emerald" or highlight-mode="text" (standard/text).
  • Super-flexible icons:
    • Accepts <i> tags (e.g. FontAwesome), <svg>, or <img> directly for full control.
    • Supports passing a plain icon name (e.g. 'check'): auto-resolves using your preferred icon set via <x-bt-icon name="check" /> as fallback.
    • You can globally set the default icon set in Beartropy presets, making it easy to use Lucide, Heroicons, FontAwesome, or your own SVGs.
  • Badges and tooltips per item: Show counts, statuses, or extra info using badge and tooltip props.
  • Divider support: Add horizontal lines to visually separate groups or sections.
  • Permission filtering: Each item can have a can property, filtered via Laravel policies or Spatie Permission (built-in static method to pre-filter arrays).
  • Config file navigation: Load your menu from files in config/beartropy/ui/navs/*.php for easy management, sharing, and customization.
  • External links & disabled items: Support for opening links in a new tab (external) and for non-clickable items (disabled).
  • Custom classes per item: Override or extend any item’s classes (e.g. for colors, icons, layout, or custom badges).
  • Fully responsive and themeable: Works with Tailwind dark mode and adapts to any layout.

Here’s a minimal working example with a sidebar that can be collapsed using Alpine.js.

Try collapsing the sidebar!

Now the main content moves left as the sidebar collapses.
This layout uses CSS grid with dynamic column widths via Alpine.

blade
            
1<div
2 x-data="{ sidebarCollapsed: false }"
3 :class="sidebarCollapsed ? 'grid-cols-[5rem_1fr]' : 'grid-cols-[16rem_1fr]'"
4 class="grid min-h-[400px] bg-slate-50 dark:bg-gray-900 rounded-xl shadow overflow-hidden border border-gray-200 dark:border-gray-800 transition-all duration-300"
5 >
6 <!-- Sidebar -->
7 <aside class="transition-all duration-300 bg-transparent p-3">
8 <x-nav
9 :items="[
10 [
11 'category' => 'Demo',
12 'items' => [
13 [
14 'label' => 'Dashboard',
15 'icon' => 'window',
16 'route' => '/',
17 'tooltip' => 'Dashboard'
18 ],
19 [
20 'label' => 'Users',
21 'icon' => 'user-group',
22 'route' => '/users',
23 'badge' => 3,
24 'tooltip' => 'Users'
25 ],
26 [
27 'divider' => true
28 ],
29 [
30 'label' => 'Settings',
31 'icon' => 'cog',
32 'children' => [
33 [
34 'label' => 'Monitoring',
35 'route' => '/monitoring',
36 'icon' => 'presentation-chart-line'
37 ],
38 [
39 'label' => 'Advance settings',
40 'route' => '/advance-settings',
41 'icon' => 'wrench-screwdriver'
42 ],
43 ]
44 ],
45 ]
46 ]
47 ]"
48 sidebar-bind="sidebarCollapsed"
49 />
50 </aside>
51 <!-- Main Content -->
52 <main class="p-4 bg-gray-200 dark:bg-gray-800">
53 <h2 class="text-xl font-semibold mb-2">Try collapsing the sidebar!</h2>
54 <p>
55 Now the main content <b>moves left</b> as the sidebar collapses.<br>
56 This layout uses <code>CSS grid</code> with <b>dynamic column widths</b> via Alpine.
57 </p>
58 <x-button
59 @click="sidebarCollapsed = !sidebarCollapsed"
60 outline
61 >
62 <span x-text="sidebarCollapsed ? 'Expand' : 'Collapse'"></span>
63 </x-button>
64 </main>
65 </div>

Custom badge slot per item

You can fully customize any badge by passing a named slot matching the item's id.
Useful for special badges, icons, animations, or even Livewire components.
blade
            
1<x-nav :items="[
2 [
3 'category' => 'App',
4 'items' => [
5 [
6 'id' => 'users',
7 'label' => 'Usuarios',
8 'icon' => 'user-group',
9 'route' => '/users',
10 ],
11 [
12 'id' => 'settings',
13 'label' => 'Configuración',
14 'icon' => 'cog',
15 'route' => '/settings',
16 ],
17 ]
18 ]
19]">
20 <x-slot name="badge-users">
21 <x-badge md color="green">+3</x-badge>
22 </x-slot>
23</x-nav>

Reactive badge with Alpine.js

Update the badge live with Alpine.js. The menu must be inside the x-data to be reactive!
blade
            
1<div x-data="{ usersBadge: 5 }" class="space-y-4">
2 <x-nav
3 :items="[
4 [
5 'category' => 'General',
6 'items' => [
7 [
8 'id' => 'users',
9 'label' => 'Usuarios',
10 'icon' => 'user-group',
11 'route' => '/users',
12 ]
13 ]
14 ]
15 ]"
16 :custom-badges="['users' => 'usersBadge']"
17 />
18 <x-button green outline @click="usersBadge++">
19 +1 Notificación
20 </x-button>
21</div>

Props

  • items: Navigation structure. Array, config name (string), or null (loads default config).
  • sidebar-bind: (string) Alpine/Livewire variable for collapse state (default: sidebarCollapsed).
  • color: (string) Color preset (e.g. green, emerald, primary).
  • highlight-mode: (string) standard or text (changes how active items are styled).
  • highlight-parent-class, highlight-child-class: Classes for active parent/child (override preset).
  • item-class, child-item-class: Classes for menu items (override preset).
  • category-class: Classes for category titles (default: muted uppercase).
  • icon-class: Additional classes for icons.
  • child-border-class: Classes for child submenu container border.
Each navigation item supports the following keys:
  • label: Menu label (string)
  • icon: Icon (FontAwesome class, SVG string, or image string)
  • route: Laravel route or URL
  • badge: Number or string badge
  • tooltip: Tooltip text
  • children: Array of child items (submenu)
  • divider: Boolean, draws a horizontal divider
  • external: Opens link in new tab
  • disabled: Disables the item
  • can: Permission required (policy or Spatie)
  • class: Override item class
  • label_class: Custom class for the label

Children and Badges Example

With children and badges:
blade
            
1<x-nav
2 :items="[
3 [
4 'category' => 'Management',
5 'items' => [
6 [
7 'label' => 'Teams',
8 'icon' => 'user-group',
9 'route' => '/teams',
10 'badge' => 2,
11 ],
12 [
13 'label' => 'Projects',
14 'icon' => 'map',
15 'route' => '/projects',
16 'children' => [
17 [
18 'label' => 'Active',
19 'route' => '/projects/active',
20 'badge' => 5
21 ],
22 [
23 'label' => 'Archived',
24 'route' => '/projects/archived'
25 ]
26 ]
27 ],
28 [
29 'divider' => true
30 ],
31 [
32 'label' => 'External Link',
33 'icon' => 'link',
34 'route' => 'https://beartropy.com',
35 'external' => true,
36 'badge' => 'Docs',
37 'tooltip' => 'View docs'
38 ]
39 ]
40 ]
41 ]"
42/>

Highlight Mode Example

You can set the highlight-mode prop to change how active items are styled:
  • standard (default): Highlights the entire item
  • text: Highlights only the text label
Here is a text highlight mode example:
blade
            
1<x-nav
2 highlight-mode="text"
3 :items="[
4 [
5 'category' => 'Management',
6 'items' => [
7 [
8 'label' => 'Teams',
9 'icon' => 'user-group',
10 'route' => '/teams',
11 'badge' => 2,
12 ],
13 [
14 'label' => 'Projects',
15 'icon' => 'map',
16 'route' => '/projects',
17 'children' => [
18 [
19 'label' => 'Active',
20 'route' => '/projects/active',
21 'badge' => 5
22 ],
23 [
24 'label' => 'Archived',
25 'route' => '/projects/archived'
26 ]
27 ]
28 ],
29 [
30 'divider' => true
31 ],
32 [
33 'label' => 'External Link',
34 'icon' => 'link',
35 'route' => 'https://beartropy.com',
36 'external' => true,
37 'badge' => 'Docs',
38 'tooltip' => 'View docs'
39 ]
40 ]
41 ]
42 ]"
43/>

Loading from config

You can load navigation from a config file, for example: config/beartropy/ui/navs/sidebar.php.
Pass the file name (without .php) as the items prop:
<x-nav items="sidebar" />

Permission-based filtering

Use can for permission filtering. You can pre-filter using:
blade
            
1<?php
2 $items = \Beartropy\Ui\Components\Nav::filterNavItems($yourItemsArray);
3?>
Code highlighting provided by Torchlight