1. Go to this page and download the library: Download hdaklue/naptab library. Choose the download type require.
2. Extract the ZIP file and open the index.php.
3. Add this code to the index.php.
<?php
require_once('vendor/autoload.php');
/* Start to develop here. Best regards https://php-download.com/ */
hdaklue / naptab example snippets
namespace App\Livewire;
use Hdaklue\NapTab\Livewire\NapTab;
use Hdaklue\NapTab\UI\Tab;
use Hdaklue\NapTab\Enums\Direction;
class DashboardTabs extends NapTab
{
// Choose your preferred layout direction
protected function direction(): Direction
{
return Direction::Horizontal; // Default: traditional top tabs
// return Direction::Aside; // Modern sidebar layout for dashboard-style interfaces
}
// CONTAINER-LEVEL CONTENT HOOKS (NEW FEATURE!)
public function beforeContent(): string
{
return '<div class="bg-blue-50 border-l-4 border-blue-400 p-4 mb-6">
<p class="text-blue-700">🚀 Welcome to your performance dashboard!</p>
</div>';
}
public function afterContent(): \Closure
{
return fn() => view('partials.dashboard-footer', [
'totalUsers' => \App\Models\User::count(),
'lastUpdate' => now()
]);
}
protected function tabs(): array
{
return [
// Controller method approach (recommended for dynamic content)
Tab::make('overview')
->label('Overview')
->icon('chart-bar')
->beforeContent('<p class="text-sm text-gray-600 mb-4">📊 Real-time overview</p>'),
// Direct content with live data + tab-level hooks
Tab::make('analytics')
->label('Analytics')
->icon('presentation-chart-line')
->badge(fn() => $this->getPendingReports())
->beforeContent('<div class="alert alert-info mb-4">Analytics updated every 5 min</div>')
->afterContent(fn() => '<small class="text-gray-500">Last sync: ' . now()->format('H:i') . '</small>')
->content(fn() => view('dashboard.analytics', [
'data' => $this->getAnalyticsData() // Only loads when clicked!
])),
// Livewire component integration
Tab::make('settings')
->label('Settings')
->icon('cog-6-tooth')
->afterContent('<div class="mt-4 p-3 bg-gray-50 rounded">
<p class="text-xs text-gray-600">Changes are saved automatically</p>
</div>')
->livewire(\App\Livewire\UserSettings::class, ['userId' => auth()->id()]),
];
}
// This method only runs when the Overview tab is clicked
public function overview()
{
$metrics = [
'users' => \App\Models\User::count(),
'orders' => \App\Models\Order::today()->count(),
'revenue' => \App\Models\Order::today()->sum('total'),
];
return view('dashboard.overview', compact('metrics'));
}
private function getAnalyticsData()
{
// Complex analytics only computed when user accesses this tab
return collect([
'pageviews' => 15420,
'conversions' => 342,
'revenue' => 28750
]);
}
private function getPendingReports()
{
return \App\Models\Report::where('status', 'pending')->count();
}
}
namespace App\Livewire;
use Hdaklue\NapTab\Livewire\NapTab;
use Hdaklue\NapTab\UI\Tab;
use Illuminate\View\View;
use Closure;
class DashboardTabs extends NapTab
{
// CONTAINER-LEVEL HOOKS - Applied to entire tabs container
public function beforeContent(): View
{
return view('partials.dashboard-header', [
'user' => auth()->user(),
'lastLogin' => auth()->user()->last_login_at
]);
}
public function afterContent(): Closure
{
return fn() => view('partials.dashboard-stats', [
'totalTabs' => count($this->tabs()),
'activeUsers' => \App\Models\User::online()->count(),
'systemStatus' => $this->getSystemStatus()
]);
}
protected function tabs(): array
{
return [
// TAB-LEVEL HOOKS - Applied to individual tab content
Tab::make('analytics')
->label('Analytics Dashboard')
->beforeContent('<div class="bg-blue-50 border-l-4 border-blue-400 p-4 mb-4">
<p class="text-sm text-blue-700">📊 Analytics data is updated every 5 minutes</p>
</div>')
->afterContent(fn() => '<div class="mt-4 text-sm text-gray-500 text-center">
Last updated: ' . now()->format('M j, Y \a\t g:i A') . '
</div>')
->content(fn() => view('dashboard.analytics', [
'metrics' => $this->calculateAnalytics() // Only loads when clicked!
])),
Tab::make('users')
->label('User Management')
->beforeContent(fn() => $this->renderUserAlert())
->afterContent('<div class="bg-gray-50 p-3 rounded mt-4">
<p class="text-xs text-gray-600">Need help? Contact support</p>
</div>')
->livewire(\App\Livewire\UserManagement::class),
];
}
private function renderUserAlert(): string
{
$pendingUsers = \App\Models\User::where('status', 'pending')->count();
if ($pendingUsers > 0) {
return "<div class='bg-yellow-50 border border-yellow-200 rounded-md p-3 mb-4'>
<p class='text-sm text-yellow-800'>⚠️ {$pendingUsers} users pending approval</p>
</div>";
}
return '';
}
}
// Static HTML content
public function beforeContent(): string
{
return '<div class="alert alert-info">Welcome to your dashboard!</div>';
}
// Dynamic Blade view
public function afterContent(): View
{
return view('partials.footer', [
'timestamp' => now(),
'version' => config('app.version')
]);
}
// Closure for conditional content
public function beforeContent(): Closure
{
return function() {
if (auth()->user()->hasUnreadNotifications()) {
return '<div class="bg-red-100 border border-red-400 text-red-700 px-4 py-3 rounded mb-4">
You have ' . auth()->user()->unreadNotifications()->count() . ' unread notifications.
</div>';
}
return '';
};
}
// Htmlable object
public function afterContent(): \Illuminate\Support\HtmlString
{
return new \Illuminate\Support\HtmlString('<div>Custom HTML content</div>');
}
Tab::make('reports')
->label('Reports')
// Alert header for this tab only
->beforeContent('<div class="bg-green-100 border border-green-400 text-green-700 px-4 py-3 rounded mb-4">
Reports are generated in real-time
</div>')
// Dynamic footer with live data
->afterContent(fn() => view('components.report-footer', [
'totalReports' => \App\Models\Report::count(),
'lastGenerated' => \App\Models\Report::latest()->first()?->created_at
]))
->content(fn() => view('reports.index'));
Tab::make('settings')
->label('Settings')
// Conditional warning
->beforeContent(function() {
if (!auth()->user()->hasVerifiedEmail()) {
return '<div class="bg-yellow-100 border border-yellow-400 text-yellow-700 px-4 py-3 rounded mb-4">
Please verify your email address to access all features.
</div>';
}
return null;
})
// Help link
->afterContent('<div class="mt-6 text-center">
<a href="/help/settings" class="text-blue-600 hover:text-blue-800">Need help with settings?</a>
</div>')
->livewire(\App\Livewire\UserSettings::class);
namespace App\Livewire;
use Hdaklue\NapTab\Livewire\NapTab;
use Hdaklue\NapTab\UI\Tab;
use App\Livewire\UserSettings;
use Illuminate\Support\Facades\Gate;
class ComprehensiveTabs extends NapTab
{
protected function tabs(): array
{
return [
// Method 1: Controller Method (Recommended for complex logic)
Tab::make('dashboard')
->icon('chart-bar')
->badge(fn() => $this->getNotificationCount())
->visible(fn() => auth()->check())
->disabled(fn() => $this->isMaintenanceMode())
->beforeLoad(fn(Tab $tab) => $this->logTabAccess($tab->getId()))
->afterLoad(fn(Tab $tab, string $content) => $this->trackPerformance($tab->getId())),
// Method 2: Direct Content (Simple HTML/Blade)
Tab::make('about')
->icon('information-circle')
->content(fn() => '<div class="p-4">
<h2>About Our Company</h2>
<p>We are a leading provider...</p>
</div>'),
// Method 3: Blade View (Static content)
Tab::make('contact')
->icon('envelope')
->content(fn() => view('pages.contact')),
// Method 4: Livewire Component (Interactive content)
Tab::make('settings')
->icon('cog-6-tooth')
->livewire(UserSettings::class, ['userId' => auth()->id()])
->visible(fn() => auth()->user()->can('manage-settings'))
->onError(fn(Tab $tab, Exception $error) => logger()->error('Settings tab error', [
'tab' => $tab->getId(),
'error' => $error->getMessage()
])),
// Method 5: Advanced Configuration with Authorization
Tab::make('analytics')
->icon('presentation-chart-line')
->badge('Pro')
->onSwitch(fn(Tab $tab, string $from, string $to) => $this->trackTabSwitch($from, $to)),
];
}
// Controller method for Method 1
public function dashboard()
{
// Heavy computation only runs when tab is clicked
$metrics = $this->calculateDashboardMetrics();
$charts = $this->generateChartData();
return view('dashboard.overview', compact('metrics', 'charts'));
}
}
namespace App\Livewire;
use Hdaklue\NapTab\Livewire\NapTab;
use Hdaklue\NapTab\Enums\Direction;
use Hdaklue\NapTab\UI\Tab;
class ResponsiveSettings extends NapTab
{
// Override the direction method to control layout
protected function direction(): Direction
{
return Direction::Aside; // Sidebar layout for dashboard-style interfaces
// return Direction::Horizontal; // Traditional top tabs (default)
}
protected function tabs(): array
{
return [
Tab::make('profile')
->icon('user-circle'),
Tab::make('privacy')
->label('Privacy')
->icon('shield-check'),
Tab::make('billing')
->label('Billing')
->icon('credit-card')
->badge(fn() => $this->hasPendingInvoices() ? 'Action Required' : null),
];
}
}
// Traditional horizontal layout (default)
protected function direction(): Direction
{
return Direction::Horizontal;
}
// Modern aside/sidebar layout
protected function direction(): Direction
{
return Direction::Aside;
}
Tab::make('id') // Creates a new tab instance
->label('Custom Label') // Set tab label (string|Closure)
->icon('heroicon-name') // Set Heroicon name (string|Closure|null)
->badge('New') // Display badge text (string|Closure|null)
->disabled(true) // Disable tab (bool|Closure, default: false)
Tab::make('admin')
->label('Admin Panel')
->visible(fn() => auth()->user()->isAdmin()) // Control visibility (bool|Closure)
// Option 1: Controller method (recommended for dynamic content)
Tab::make('dashboard') // Automatically calls $this->dashboard() method
// Option 2: Direct content with closure
Tab::make('about')
->label('About')
->content(fn() => view('pages.about')) // Returns Htmlable content
// Option 3: Livewire component
Tab::make('settings')
->label('Settings')
->livewire(UserSettings::class, ['userId' => 123]) // Component class and params
Tab::make('analytics')
->label('Analytics')
->beforeLoad(function(Tab $tab) {
// Called before tab content loads
logger()->info("Loading tab: {$tab->getId()}");
})
->afterLoad(function(Tab $tab, string $content) {
// Called after content is loaded
$this->trackTabView($tab->getId());
})
->onError(function(Tab $tab, Exception $error) {
// Called when tab loading fails
$this->logTabError($tab->getId(), $error->getMessage());
})
->onSwitch(function(Tab $tab, string $fromTabId, string $toTabId) {
// Called when switching to this tab
$this->analyzeTabFlow($fromTabId, $toTabId);
});
public function reports()
{
// Database queries only execute when user clicks this tab
$reports = Report::with('author')
->where('status', 'published')
->latest()
->paginate(20);
return view('tabs.reports', compact('reports'));
}
Tab::make('terms')
->label('Terms of Service')
->content('<div class="prose max-w-none">
<h1>Terms of Service</h1>
<p>By using our service...</p>
</div>')
->style(TabStyle::Modern)
// Rich visual experience with shadows, thick borders, large badges
->style(TabStyle::Minimal)
// Clean design with no shadows, thin borders, small badges, compact spacing
->style(TabStyle::Sharp)
// Bold geometric design with no shadows, no borders, no rounded corners
->style(TabStyle::Pills)
// Modern pill-shaped tabs with full borders, rounded corners, and no container underline
// Configuration is cached as singleton in service container
$this->app->singleton('naptab.config', function () {
return NapTabConfig::create()->style(TabStyle::Pills);
});
// In your tab component class
class DashboardTabs extends NapTab
{
protected function isRoutable(): bool
{
return true; // Enable routing for this component
}
// Or disable routing for specific components
protected function isRoutable(): bool
{
return false; // This component won't use URL routing
}
}
// Dashboard with routing (bookmarkable tabs)
class DashboardTabs extends NapTab
{
protected function isRoutable(): bool
{
return true;
}
}
// Modal or sidebar tabs without routing
class UserSettingsTabs extends NapTab
{
protected function isRoutable(): bool
{
return false; // No URL changes for these tabs
}
}
bash
php artisan naptab:install
Loading please wait ...
Before you can download the PHP files, the dependencies should be resolved. This can take some minutes. Please be patient.