composer require eminiarts/nova-tabs in your Nova project (Nova 4+ only).use Eminiarts\Tabs\Traits\HasTabs; to your Nova resource class.tabs() method returning a Tabs collection. Example:
public function tabs()
{
return Tabs::make('User Details', [
Tab::make('Basic Info', [
Text::make('Name'),
Text::make('Email'),
]),
Tab::make('Profile', [
Textarea::make('Bio'),
Select::make('Role'),
]),
]);
}
Problem: A resource with many fields cluttering the UI. Solution: Organize fields into logical tabs (e.g., "Basic Info," "Profile," "Permissions") for cleaner UX.
Field Grouping by Context:
public function fields(Request $request)
{
return [
// ... default fields ...
$this->tabs()->toFields($request),
];
}
Dynamic Tabs:
public function tabs()
{
return Tabs::make('Settings', [
Tab::make('Admin Only', [
// Fields visible only to admins
])->visible(fn () => auth()->user()->isAdmin()),
]);
}
Relationship Tabs:
User resource):
Tab::make('Orders', [
BelongsToMany::make('Orders'),
])->relationship('orders'),
Action Isolation:
Tab::make('Danger Zone', [
Actions::make('Delete User', 'delete'),
]),
nova-impersonate) by overriding the tabs() method in child resources.Tabs::make() in NovaFormRequest to validate tab-specific fields:
public function rules()
{
return array_merge(
parent::rules(),
$this->tabs()->rules()
);
}
Tab class to add custom logic (e.g., API-only fields):
class ApiTab extends Tab
{
public function apiFields()
{
return [...];
}
}
Tab Ordering:
Tabs::make(). Use ->sortBy() or ->sortDesc() for dynamic ordering:
Tabs::make('Settings')->sortBy(fn (Tab $tab) => $tab->name);
Field Duplication:
->onlyOnForms() or ->onlyOnDetail() to scope fields:
Text::make('Name')->onlyOnForms(),
Relationship Caching:
public function fields(Request $request)
{
$resource = $this->newModelInstance()->resolveRelationships();
return $this->tabs()->toFields($request, $resource);
}
CSS Conflicts:
/* resources/css/nova-custom.css */
.tabs-panel .tab-content { /* Adjust padding/margins */ }
Tab Not Rendering?:
HasTabs trait is used and tabs() returns a Tabs collection.storage/logs/nova.log.Field Data Missing:
tabs() method. Use dd($this->tabs()) to inspect the structure.Performance Issues:
->hideFromIndex() for tabs with expensive queries.Custom Tab Classes:
Eminiarts\Tabs\Tab to add metadata or logic:
class CustomTab extends Tab
{
public function isActive()
{
return request()->query('active_tab') === $this->name;
}
}
Global Tab Events:
tab-changed event:
Nova::serving(function () {
Nova::script('nova-tabs-event', function () {
window.addEventListener('tab-changed', (e) => {
console.log('Active tab:', e.detail.tabName);
});
});
});
Override Default Search:
app/Providers/NovaServiceProvider.php:
public function boot()
{
Nova::serving(function () {
Nova::provideToApiRequest(function ($request) {
$request->merge([
'search' => $request->input('search', 'default-search-term'),
]);
});
});
}
Localization:
Tab::make(__('tabs.basic_info'), [
// Fields...
]),
php artisan vendor:publish --provider="Eminiarts\Tabs\TabsServiceProvider" --tag="nova-tabs-lang"
More Than 5 Tabs:
php artisan vendor:publish --provider="Eminiarts\Tabs\TabsServiceProvider" --tag="nova-tabs-config"
config/nova-tabs.php:
'max_tabs' => null, // Remove the limit
How can I help you explore Laravel packages today?