Installation:
composer require hdaklue/naptab
Publish the config (optional):
php artisan vendor:publish --provider="Hdaklue\NapTab\NapTabServiceProvider" --tag="config"
Basic Blade Integration:
@napTab
@napTabItem('Dashboard', route('dashboard'))
<!-- Content loads only when tab is clicked -->
<p>Dashboard content here</p>
@endNapTabItem
@napTabItem('Profile', route('profile'))
<p>Profile content here</p>
@endNapTabItem
@endNapTab
First Use Case:
Replace a traditional tab system (e.g., Alpine.js + manual lazy loading) with @napTab for a dashboard with heavy backend operations (e.g., analytics, user management). Only load the active tab’s data on click.
Lazy-Loaded Tab Content:
@napTabItem directives to wrap content that should load only when activated.Dual-Level Hooks:
@napTab
@napTabContainerHook
<div class="filters">...</div>
@endNapTabContainerHook
@endNapTab
@napTabItem('Settings')
@napTabItemHook
<button class="edit-tab">...</button>
@endNapTabItemHook
@endNapTabItem
Dynamic Tab Generation:
public $tabs = [
['name' => 'Orders', 'route' => 'orders.index'],
['name' => 'Reports', 'route' => 'reports.index'],
];
@foreach($tabs as $tab)
@napTabItem($tab['name'], $tab['route'])
{{ $slot }}
@endNapTabItem
@endforeach
Sidebar/Aside Layouts:
direction="aside" for dashboard-style layouts:
@napTab(direction="aside")
@napTabItem('Projects')
<!-- Content -->
@endNapTabItem
@endNapTab
Livewire Components:
@napTab inside a Livewire component to manage tab state server-side:
<livewire:admin-dashboard>
@napTab
@napTabItem('Users')
<livewire:user-manager />
@endNapTabItem
@endNapTab
</livewire:admin-dashboard>
wire:model to sync active tab state across components.Route-Based Tabs:
@napTabItem('Invoices', route('invoices.index', ['status' => 'pending']))
Conditional Tabs:
@if(auth()->user()->isAdmin())
@napTabItem('Admin Tools', route('admin.tools'))
@endif
Livewire Conflict:
@napTab is outside the Livewire component’s root <div>. Nested Livewire components may cause hydration issues.@napTab to the parent component or use wire:ignore on the tab container.Lazy-Loading Overhead:
@napTabItem) will still render a clickable tab but may cause confusion.<div class="p-4">Loading...</div>) to avoid empty UI.Route Caching:
php artisan route:clear) after adding new routes to avoid stale tab links.CSS/JS Dependencies:
@napTab directive:
@vite(['resources/js/app.js']) <!-- Ensure Alpine is included -->
Tab Not Activating:
@nap-tab:activate).x-data to the @napTab directive to inspect state:
@napTab(x-data="{ debug: true }")
Content Not Loading:
dd() in the controller to test.wire:loading state to the tab content for better UX:
@napTabItem('Data')
<div wire:loading>Loading data...</div>
{{ $slot }}
@endNapTabItem
Default Active Tab:
config('naptab.default_active_tab') (e.g., 'dashboard'). Useful for multi-page forms where the last active tab should persist.active-tab="profile" in the @napTab directive.Transition Effects:
transition="none":@napTab(transition="none")
Custom Events:
<div x-data @nap-tab:activate="console.log('Tab activated')"></div>
Custom Styling:
class attribute:
@napTab(class="bg-gray-100")
.nap-tab--active { /* Custom active tab styles */ }
Server-Side Logic:
public function getTabsProperty() {
return auth()->user()->canAccess('reports')
? [...$this->defaultTabs, ['name' => 'Reports', 'route' => 'reports']]
: $this->defaultTabs;
}
Third-Party Integration:
<nova-layout>
@napTab
@napTabItem('Resources', nova-index)
{{ Nova::resources() }}
@endNapTabItem
@endNapTab
</nova-layout>
How can I help you explore Laravel packages today?