developerawam / livewire-datatable
Laravel Livewire DataTable adalah package open-source yang membantu kamu membangun tabel dinamis di Laravel tanpa ribet. Semua sudah terintegrasi dengan Livewire, sehingga kamu bisa mendapatkan fitur pencarian, filter, sorting, dan pagination out-of-the-box tanpa JavaScript tambahan.
Package info
github.com/restu-lomboe/datatable-livewire
Language:Blade
pkg:composer/developerawam/livewire-datatable
Requires
- php: ^8.2
- barryvdh/laravel-dompdf: ^3.1
- illuminate/support: ^12.0||^13.0
- livewire/livewire: ^4.0
- maatwebsite/excel: ^3.1
Requires (Dev)
- orchestra/testbench: ^9.0||^10.0
- phpunit/phpunit: ^11.0
This package is auto-updated.
Last update: 2026-08-06 01:53:52 UTC
README
A powerful and flexible DataTable component for Laravel Livewire that transforms your data into beautiful, interactive tables with zero configuration required.
🎯 Quick Overview
- Zero Configuration: Works out of the box with just your Eloquent model
- Server-Side Rendering: Handles thousands of records efficiently
- Feature-Rich: Search, sort, filter, paginate, and export with ease
- Fully Customizable: Configure every aspect via config or per-component
- Production Ready: Built for real-world applications with proper error handling
📚 Table of Contents
- Features
- Requirements
- Installation
- Quick Start
- Basic Usage
- Advanced Features
- Exporting Data
- Customization
- API Integration
- Troubleshooting
- Support
✨ Features
| Feature | Description |
|---|---|
| ⚡ Server-Side Rendering | Handle thousands of records efficiently |
| 🔍 Smart Search | Live search with intelligent debouncing across multiple columns |
| 📊 Column Sorting | Sort by any column, including relationship data |
| 🔤 Advanced Filtering | Multi-column filtering with intuitive UI |
| 📅 Date Range Filter | Dedicated date range filter with auto-detected date columns |
| 📄 Pagination | Fully customizable pagination with per-page options |
| 📤 Data Export | Export to Excel and PDF with custom column selection and PDF options |
| 🎨 Dynamic Styling | All CSS classes configurable from config file |
| 🌙 Dark Mode | Automatic dark mode support with Tailwind |
| 📱 Responsive Design | Mobile-friendly on all screen sizes |
| 🔗 Relationships | Display and sort by related model data using dot notation |
| 🎯 Custom Templates | Create custom cell content with Blade components |
| 🛠 Event System | Built-in event handling for user interactions |
| 🔧 Zero Config | Works out of the box with sensible defaults |
| 🎨 Multi-Template Support | Tailwind CSS and Bootstrap 5+ templates built-in |
| 📋 Row Numbering | Smart "no" column with consistent sequential numbering |
📋 Requirements
- PHP: ^8.2
- Laravel: ^12.0 || ^13.0
- Livewire: ^4.0
- CSS Framework: Tailwind CSS ^3.0+ OR Bootstrap 5+
Browser Support
All modern browsers (Chrome, Firefox, Safari, Edge)
📦 Installation
1. Install Package
composer require developerawam/livewire-datatable
2. Configure Your CSS Framework
For Tailwind CSS
For Tailwind CSS v3:
Add the package's views to your Tailwind configuration:
// tailwind.config.js module.exports = { content: [ "./resources/**/*.blade.php", "./resources/**/*.js", "./vendor/developerawam/livewire-datatable/resources/views/*.blade.php", ], };
For Tailwind CSS v4+:
Use the @source directive in your resources/css/app.css:
@import "tailwindcss"; @source '../../vendor/developerawam/livewire-datatable/resources/views/*.blade.php';
This allows Tailwind CSS v4+ to automatically scan and generate styles for the datatable components.
For Bootstrap 5+
No additional configuration needed! Bootstrap is automatically detected and used.
3. (Optional) Publish Configuration
php artisan vendor:publish --tag="livewire-datatable-config"
This allows you to customize default settings in config/livewire-datatable.php
4. (Optional) Set Template System
Choose your CSS framework template in .env:
DATATABLE_TEMPLATE=tailwind # Default # or DATATABLE_TEMPLATE=bootstrap
🚀 Quick Start
Create a fully functional DataTable in under 2 minutes.
1. Create Livewire Component
php artisan make:livewire UsersTable
2. Setup Component
<?php namespace App\Livewire; use App\Models\User; use Livewire\Component; class UsersTable extends Component { public function render() { return view('livewire.users-table', [ 'model' => User::class, 'columns' => [ 'id' => 'ID', 'name' => 'Name', 'email' => 'Email', 'created_at' => 'Joined' ], 'searchable' => ['name', 'email'] ]); } }
3. Create View
{{-- resources/views/livewire/users-table.blade.php --}} <div> <livewire:livewire-datatable :model="$model" :columns="$columns" :searchable="$searchable" /> </div>
4. Use in Blade
<livewire:users-table />
Done! You now have a fully functional DataTable with search, sorting, and pagination.
📖 Basic Usage
Columns
Define what data to display and how to label it:
'columns' => [ 'id' => 'ID', 'name' => 'Full Name', 'email' => 'Email Address', 'created_at' => 'Joined Date', 'department.name' => 'Department', // Relationship data ]
Searching
Make columns searchable:
'searchable' => ['name', 'email', 'department.name']
Sorting
Control which columns can be sorted:
// By default, all columns are sortable // Prevent sorting on specific columns: 'unsortable' => ['actions', 'avatar']
Value Formatting
Format column values automatically using formatters.
Simple Formatters
Use simple string formatters for common formats:
'formatters' => [ 'created_at' => 'datetime', // Format as datetime 'updated_at' => 'date', // Format as date 'balance' => 'currency', // Format as currency 'is_active' => 'boolean', // Format as Yes/No ]
Advanced Formatters
For complex formatting, use array syntax:
'formatters' => [ 'description' => [ 'type' => 'words', 'options' => ['words' => 10, 'end' => '...'] ], 'title' => [ 'type' => 'limit', 'options' => ['length' => 50, 'end' => '...'] ], 'price' => [ 'type' => 'money', 'options' => [ 'symbol' => '$', 'decimals' => 2, 'decimal_point' => '.', 'thousand_sep' => ',' ] ], ]
Available Formatters
| Formatter | Usage | Options |
|---|---|---|
date |
Format as date | format: 'Y-m-d' |
datetime |
Format as datetime | format: 'Y-m-d H:i:s' |
time |
Format as time | format: 'H:i:s' |
number |
Add thousands separator | — |
currency |
Format as currency | symbol, decimals, decimal_point, thousand_sep |
boolean |
Convert to Yes/No | true, false |
uppercase |
Uppercase text | — |
lowercase |
Lowercase text | — |
limit |
Limit string length | length, end |
words |
Limit by word count | words, end |
markdown |
Convert markdown to HTML | — |
money |
Advanced currency | symbol, decimals, decimal_point, thousand_sep |
link |
Render value as a link | route, params, url, text, target, class, title |
Link Formatter
Render a column value as a clickable link, either to a named route (with parameters pulled from other columns) or to a custom/static URL.
Route with Column Parameters
'formatters' => [ 'name' => [ 'type' => 'link', 'options' => [ 'route' => 'users.show', // named route 'params' => ['id'], // column names whose values fill the route params 'target' => '_blank', // optional 'text' => 'View Profile', // optional link label (defaults to the cell value) 'class' => 'text-blue-600 hover:underline', ], ], ],
If the route parameter name differs from the column name, use an associative array:
'params' => ['user' => 'id', 'slug' => 'slug'], // route param "user" <- column "id"
Custom / Static URL
'formatters' => [ 'name' => [ 'type' => 'link', 'options' => [ 'url' => 'https://www.google.com/', // static link ], ], ],
You can also inject column values into a URL using {column} placeholders:
'formatters' => [ 'name' => [ 'type' => 'link', 'options' => [ 'url' => '/users/{id}/edit', // {id} replaced with the row's id ], ], ],
Options Reference
| Option | Description |
|---|---|
route |
Named route to link to (e.g. users.show) |
params |
Route parameters as column names; numeric ['id'] or associative ['user' => 'id'] |
url |
Custom/static URL, optionally with {column} placeholders |
text |
Link label (defaults to the cell value) |
target |
_self (default) or _blank |
class |
CSS classes applied to the anchor |
title |
title attribute for the anchor |
When exporting to Excel or PDF, link-formatted columns keep their original value (no URL).
� Advanced Features
Relationships
Display and sort data from related models using dot notation.
1. Setup Model with Relationships
<?php namespace App\Models; use Illuminate\Database\Eloquent\Model; class User extends Model { protected $with = ['department', 'role']; public function department() { return $this->belongsTo(Department::class); } public function role() { return $this->belongsTo(Role::class); } }
2. Use Dot Notation in Columns
'columns' => [ 'id' => 'ID', 'name' => 'Name', 'department.name' => 'Department', 'role.name' => 'Role', 'department.location' => 'Office', ]
DataTable automatically handles relationships and makes them sortable!
Custom Query Scopes
Apply filters and constraints using Eloquent query scopes.
1. Define Scope on Model
<?php namespace App\Models; use Illuminate\Database\Eloquent\Builder; class User extends Model { public function scopeActive(Builder $query): Builder { return $query->where('status', 'active'); } public function scopeFromDepartment(Builder $query, string $department): Builder { return $query->whereHas('department', fn ($q) => $q->where('name', $department)); } }
2. Apply Scope to DataTable
public function render() { return view('livewire.users-table', [ 'model' => User::class, 'scope' => 'active', // Single scope 'columns' => [...], ]); }
3. Apply Scope with Parameters
public function render() { return view('livewire.users-table', [ 'model' => User::class, 'scope' => 'fromDepartment', 'scopeParams' => ['Engineering'], 'columns' => [...], ]); }
Custom Cell Templates
Create rich, interactive cell content with custom Blade templates.
1. Define Custom Columns
public function render() { return view('livewire.users-table', [ 'model' => User::class, 'columns' => [ 'id' => 'ID', 'name' => 'Name', 'status' => 'Status', 'actions' => 'Actions' ], 'customColumns' => [ 'status' => 'components.table.status-badge', 'actions' => 'components.table.user-actions' ], 'unsortable' => ['actions'] ]); }
2. Create Custom Templates
Status Badge (resources/views/components/table/status-badge.blade.php):
@php $statusColors = [ 'active' => 'bg-green-100 text-green-800', 'inactive' => 'bg-red-100 text-red-800', 'pending' => 'bg-yellow-100 text-yellow-800' ]; $colorClass = $statusColors[$value] ?? 'bg-gray-100 text-gray-800'; @endphp <span class="inline-flex px-2 py-1 text-xs font-semibold rounded-full {{ $colorClass }}"> {{ ucfirst($value) }} </span>
Action Buttons (resources/views/components/table/user-actions.blade.php):
<div class="flex items-center space-x-2"> <button wire:click="$dispatch('user-edit', { id: {{ $item->id }} })" class="text-blue-600 hover:text-blue-800"> Edit </button> <button wire:click="$dispatch('user-delete', { id: {{ $item->id }} })" wire:confirm="Delete this user?" class="text-red-600 hover:text-red-800"> Delete </button> </div>
3. Handle Events in Component
<?php namespace App\Livewire; use App\Models\User; use Livewire\Component; use Livewire\Attributes\On; class UsersTable extends Component { #[On('user-edit')] public function editUser($id) { $this->redirect(route('users.edit', $id)); } #[On('user-delete')] public function deleteUser($id) { try { User::findOrFail($id)->delete(); session()->flash('message', 'User deleted successfully!'); // Refresh table after deletion $this->dispatch('reset-table'); } catch (\Exception $e) { session()->flash('error', 'Failed to delete user.'); } } #[On('user-update-status')] public function updateUserStatus($id) { try { $user = User::findOrFail($id); $user->update(['status' => $user->status === 'active' ? 'inactive' : 'active']); session()->flash('message', 'User status updated!'); // Refresh table after status update $this->dispatch('reset-table'); } catch (\Exception $e) { session()->flash('error', 'Failed to update user status.'); } } public function render() { return view('livewire.users-table', [ 'model' => User::class, 'columns' => [...], 'customColumns' => [...], ]); } }
Available Variables in Custom Templates:
$item- Current model instance$value- Current column value
Refresh Table After Actions:
// Dispatch event to refresh the table after modifications $this->dispatch('reset-table');
Default Sort Configuration
Customize the default sort field and direction.
<livewire:livewire-datatable
:model="User::class"
:columns="[...]"
defaultSortField="created_at"
defaultSortDirection="desc" />
Works with relationships using dot notation:
defaultSortField="department.name" defaultSortDirection="asc"
Advanced Dynamic Filtering
Filter data across multiple columns with an intuitive interface.
Enable/Disable Filtering
// config/livewire-datatable.php return [ 'advanced_filter' => true, // Default: true ];
How It Works
Users can:
- Click "Filter.." to add filter conditions
- Select columns to filter by
- Enter filter values
- Add multiple conditions (AND logic)
- Reset all filters at once
Customization
All filter elements have configurable CSS classes:
// config/livewire-datatable.php 'theme' => [ 'filter_panel' => 'p-4 border-r border-gray-200', 'filter_items' => 'space-y-3', 'filter_input' => 'py-2.5 px-4 border-gray-200 rounded-lg', 'filter_add_button' => 'py-2 px-3 text-sm font-medium', 'filter_reset_button' => 'py-2 px-3 text-sm font-medium', 'filter_apply_button' => 'py-2 px-3 text-sm font-medium', ]
Date Range Filter
Filter your data by date ranges with a dedicated modal for date/datetime/timestamp columns.
How It Works
- Click the calendar icon button in the table controls toolbar
- A modal opens with:
- Column selector — auto-populated with all date/datetime/timestamp columns from the main table and relationships
- Start date and End date inputs
- Select a column, pick your date range, and click Apply
- An active filter badge appears showing the current date range
- Click the × on the badge to reset the filter
Features
- Auto-detection: Scans database schema for
date,datetime, andtimestampcolumn types - Relationship support: Date columns on related models are automatically detected (e.g.,
orders.created_at) - Real-time validation: End date must be >= start date; shows inline error messages
- Export integration: Active date filter is applied when exporting to Excel or PDF (filename gets
-date-filteredsuffix) - Compatible with advanced filters: Works alongside the existing advanced filter system
Configuration
// config/livewire-datatable.php 'advanced_filter' => true, // also enables date filter features
Theme Classes (Tailwind)
All date filter elements are configurable in config/livewire-datatable.php under theme:
'theme' => [ 'date_filter_button' => 'inline-flex items-center gap-x-2 px-3 py-2 text-sm font-medium rounded-sm border ...', 'date_filter_button_icon' => 'size-4', 'date_filter_modal' => 'relative max-w-md w-full mx-4 bg-white dark:bg-gray-800 rounded-sm shadow-xl ...', 'date_filter_header' => 'flex items-center justify-between px-6 py-4 border-b ...', 'date_filter_title' => 'text-lg font-semibold text-gray-900 dark:text-white', 'date_filter_close' => 'inline-flex items-center text-sm font-medium ...', 'date_filter_body' => 'px-6 py-4 space-y-4', 'date_filter_column_label' => 'text-xs font-medium text-gray-500 dark:text-gray-400 mb-1 block', 'date_filter_column_select' => 'w-full py-1.5 px-3 block border border-gray-300 ...', 'date_filter_date_row' => 'flex items-end gap-3', 'date_filter_date_group' => 'flex flex-col flex-1', 'date_filter_date_input' => 'py-1.5 px-3 block border border-gray-300 ...', 'date_filter_date_separator' => 'text-sm text-gray-500 dark:text-gray-400 pb-1.5', 'date_filter_footer' => 'flex items-center justify-end gap-2 px-6 py-4 border-t ...', 'date_filter_apply' => 'py-2 px-4 text-sm font-medium text-white bg-blue-600 rounded-sm ...', 'date_filter_reset' => 'py-2 px-4 text-sm font-medium text-gray-700 ...', 'date_filter_cancel' => 'py-2 px-4 text-sm font-medium text-gray-700 ...', 'date_filter_badge' => 'inline-flex items-center gap-1 px-2 py-1 text-xs font-medium bg-blue-100 ...', 'date_filter_badge_remove' => 'text-blue-600 hover:text-blue-800 ...', ]
Bootstrap Configuration
'bootstrap_theme' => [ 'date_filter_button' => 'btn btn-sm btn-outline-secondary', 'date_filter_button_icon' => '', 'date_filter_modal_backdrop' => 'modal-backdrop fade show', 'date_filter_modal_wrapper' => 'modal d-block', 'date_filter_modal_dialog' => 'modal-dialog modal-dialog-centered', 'date_filter_modal_content' => 'modal-content border shadow', 'date_filter_header' => 'modal-header', 'date_filter_title' => 'modal-title', 'date_filter_close' => 'btn-close', 'date_filter_body' => 'modal-body', 'date_filter_column_label' => 'form-label small text-secondary mb-1', 'date_filter_column_select' => 'form-select', 'date_filter_date_row' => 'd-flex align-items-end gap-3', 'date_filter_date_group' => 'd-flex flex-column flex-fill', 'date_filter_date_input' => 'form-control', 'date_filter_date_separator' => 'text-secondary pb-1 small', 'date_filter_footer' => 'modal-footer', 'date_filter_apply' => 'btn btn-sm btn-primary', 'date_filter_reset' => 'btn btn-sm btn-outline-secondary', 'date_filter_cancel' => 'btn btn-sm btn-secondary', 'date_filter_badge' => 'badge bg-primary bg-opacity-10 text-primary d-inline-flex ...', 'date_filter_badge_remove' => 'btn-close btn-close-sm', ]
Row Numbering ("no" Column)
The "no" column provides sequential row numbering that works intelligently with sorting and pagination.
Behavior
- Sequential numbering: Always displays 1, 2, 3... regardless of sort order
- Pagination-aware: Continues numbering across pages (page 2 shows 11, 12, 13...)
- Sort-independent: Doesn't reverse or change based on sort direction
- Consistent: Maintains the same numbering regardless of active filters or searches
Example
Page 1 (perPage: 10):
No | Name | Email
1 | John Doe | john@example.com
2 | Jane Smith | jane@example.com
...
10 | Mike Johnson | mike@example.com
Page 2:
No | Name | Email
11 | Sarah Williams | sarah@example.com
12 | Tom Brown | tom@example.com
Even when sorting by different columns, the "no" column always displays sequential numbering.
🌐 API Integration
The DataTable supports both Eloquent models and API endpoints for flexibility.
Setup API DataTable
<?php namespace App\Livewire; use Livewire\Component; class TodoTableApi extends Component { public function render() { $apiConfig = [ 'url' => url('/api/todos'), 'headers' => ['Accept' => 'application/json'], 'data_key' => 'data', // Where to find items 'total_key' => 'total', // Where to find total count 'search_param' => 'search', 'sort_param' => 'sort', 'sort_direction_param' => 'direction', 'per_page_param' => 'per_page', 'page_param' => 'page', ]; return view('livewire.todo-table-api', [ 'apiConfig' => $apiConfig, 'columns' => ['id' => 'ID', 'title' => 'Title'], 'searchable' => ['title'], ]); } }
API View
<div> <livewire:livewire-datatable :api-config="$apiConfig" :columns="$columns" :searchable="$searchable" /> </div>
Required Response Format
Your API must return:
{
"data": [{ "id": 1, "title": "Task", "created_at": "2025-01-27T10:00:00Z" }],
"total": 100,
"per_page": 10,
"current_page": 1,
"last_page": 10,
"from": 1,
"to": 10
}
API Query Parameters
DataTable sends these parameters:
GET /api/todos?search=keyword&sort=title&direction=asc&per_page=10&page=1
Custom API Configuration
$apiConfig = [ 'url' => url('/api/todos'), 'method' => 'GET', 'headers' => [ 'Authorization' => 'Bearer ' . $token, 'Accept' => 'application/json', ], 'query_params' => ['status' => 'active'], 'response_key' => 'data.todos', // For nested responses ];
📤 Exporting Data
Export your DataTable data to Excel and PDF formats.
Export Features
- Export to Excel (
.xlsx) and PDF - Custom column selection via interactive modal
- Per-export paper size (A4, Letter, Legal) and orientation (Portrait, Landscape)
- Exports all records (respects pagination)
- Respects active search filters
- Respects active date range filter
- Maintains data formatting (dates, currency, etc.)
- Automatically excludes action columns
- Responsive UI with dark mode support
Configuration
// config/livewire-datatable.php 'export' => [ 'enabled' => true, 'types' => ['excel', 'pdf'], 'orientation' => 'portrait', 'paper_size' => 'a4', ];
How to Use
- Click the "Export" dropdown in the controls
- Select "Export Excel" or "Export PDF"
- File downloads automatically
Example with Custom Options
'export' => [ 'enabled' => true, 'types' => ['excel', 'pdf'], 'orientation' => 'landscape', 'paper_size' => 'a4', 'dropdown' => [ 'position' => 'top', 'trigger_text' => 'Download', ], ],
Custom Export (Column Selection)
Choose exactly which columns to export and configure PDF output settings per-export.
How to Use
- Click the Export dropdown in the table controls
- Select Custom Export from the dropdown
- A modal opens showing all available columns grouped by table
- Select/deselect columns using checkboxes or the Select All / Deselect All buttons
- Choose export type: Excel or PDF
- For PDF: optionally choose Paper Size (A4, Letter, Legal) and Orientation (Portrait, Landscape)
- Click Export — file downloads automatically
Smart Column Detection
The custom export modal automatically lists columns from:
- The main table's
$columnsdefinition - All eager-loaded relationships (
$withon the model)
Internal fields are excluded automatically: id, updated_at, deleted_at, password, remember_token.
Configuration
All custom export modal elements are themeable via config/livewire-datatable.php:
'theme' => [ 'custom_export_modal' => 'relative max-w-3xl w-full mx-4 bg-white dark:bg-gray-800 rounded-sm shadow-xl', 'custom_export_header' => 'flex items-center justify-between px-6 py-4 border-b', 'custom_export_title' => 'text-lg font-semibold text-gray-900 dark:text-white', 'custom_export_close' => 'inline-flex items-center text-sm font-medium text-gray-800 cursor-pointer', 'custom_export_body' => 'px-6 py-4 max-h-96 overflow-y-auto', 'custom_export_select_all' => 'flex gap-3 mb-4', 'custom_export_select_all_btn' => 'text-sm font-medium text-blue-600 hover:text-blue-800 cursor-pointer', 'custom_export_deselect_all_btn' => 'text-sm font-medium text-gray-600 hover:text-gray-800 cursor-pointer', 'custom_export_columns' => 'space-y-4', 'custom_export_group' => '', 'custom_export_group_title' => 'text-xs font-semibold text-gray-500 uppercase tracking-wider mb-2', 'custom_export_group_columns' => 'grid grid-cols-2 sm:grid-cols-3 gap-2', 'custom_export_label' => 'inline-flex items-center gap-2 text-sm text-gray-700 cursor-pointer', 'custom_export_checkbox' => 'rounded-sm border-gray-300 text-blue-600 focus:ring-blue-500', 'custom_export_footer' => 'flex items-center justify-between px-6 py-4 border-t', 'custom_export_type_wrapper' => 'flex items-center gap-2', 'custom_export_type_label' => 'text-sm text-gray-600', 'custom_export_type_select' => 'py-1.5 px-3 block border border-gray-300 rounded-sm text-sm w-25', 'custom_export_actions' => 'flex items-center gap-2', 'custom_export_cancel' => 'py-2 px-4 text-sm font-medium text-gray-700 bg-white border border-gray-300 rounded-sm', 'custom_export_submit' => 'py-2 px-4 text-sm font-medium text-white bg-blue-600 rounded-sm hover:bg-blue-700 disabled:opacity-50', ],
All keys have dark mode variants included by default.
🎨 Customization
Template System
The DataTable supports multiple CSS frameworks. Switch between them easily:
Available Templates
- tailwind - Tailwind CSS (default)
- bootstrap - Bootstrap 5+
Switch Template
Set in config/livewire-datatable.php:
'template' => env('DATATABLE_TEMPLATE', 'tailwind'),
Or in .env:
DATATABLE_TEMPLATE=bootstrap
Bootstrap Pagination
If you're using Bootstrap CSS framework instead of Tailwind CSS, you can configure Livewire to use Bootstrap pagination styles. See the Livewire Bootstrap Pagination Documentation for detailed setup instructions.
Bootstrap Configuration
'bootstrap_theme' => [ 'wrapper' => 'container-fluid card', 'table' => 'table table-hover table-sm', 'th' => 'table-light', 'th_sort_button' => 'btn btn-sm btn-ghost', // Custom export modal 'custom_export_backdrop' => 'modal-backdrop fade show', 'custom_export_wrapper' => 'modal d-block', 'custom_export_dialog' => 'modal-dialog modal-lg modal-dialog-centered modal-dialog-scrollable', 'custom_export_content' => 'modal-content border shadow', 'custom_export_header' => 'modal-header', 'custom_export_title' => 'modal-title', 'custom_export_close' => 'btn-close', 'custom_export_body' => 'modal-body', 'custom_export_select_all' => 'd-flex gap-2 mb-3', 'custom_export_select_all_btn' => 'btn btn-sm btn-outline-primary', 'custom_export_deselect_all_btn' => 'btn btn-sm btn-outline-secondary', 'custom_export_group_title' => 'text-muted text-uppercase small fw-bold mb-2', 'custom_export_group_columns' => 'row g-2', 'custom_export_checkbox_col' => 'col-6 col-md-4', 'custom_export_checkbox_wrapper' => 'form-check', 'custom_export_checkbox' => 'form-check-input', 'custom_export_label' => 'form-check-label', 'custom_export_footer' => 'modal-footer d-flex justify-content-between', 'custom_export_type_wrapper' => 'd-flex align-items-center gap-2 flex-wrap', 'custom_export_type_label' => 'form-label mb-0 text-nowrap', 'custom_export_type_select' => 'form-select form-select-sm w-auto', 'custom_export_actions' => 'd-flex gap-2', 'custom_export_cancel' => 'btn btn-sm btn-secondary', 'custom_export_submit' => 'btn btn-sm btn-primary', ]
Theme Configuration
Customize the default appearance via config/livewire-datatable.php.
Quick Example
'theme' => [ 'table' => 'min-w-full divide-y divide-gray-200', 'th' => 'px-6 py-3 bg-gray-50 text-left text-xs font-medium', 'td' => 'px-6 py-4 whitespace-nowrap text-sm', 'tr' => 'hover:bg-gray-50 transition', ]
Per-Column Styling
Style specific columns using column keys:
'theme' => [ 'td_id' => 'font-mono text-gray-500 text-xs', 'td_email' => 'font-medium text-blue-600', 'td_status' => 'text-center font-semibold', 'td_actions' => 'text-right space-x-2', ]
Dynamic CSS Classes
Every element in the DataTable is fully configurable via CSS classes. All elements have data-class attributes for easy debugging.
Component-Level Overrides
Override theme for specific tables:
public function render() { return view('livewire.users-table', [ 'model' => User::class, 'columns' => ['id' => 'ID', 'name' => 'Name'], 'theme' => [ 'table' => 'min-w-full divide-y divide-blue-200', 'tr' => 'hover:bg-blue-50', 'td_id' => 'font-mono text-gray-500', ] ]); }
Use in view:
<livewire:livewire-datatable :model="$model" :columns="$columns" :theme="$theme" />
Dark Mode Support
Automatic dark mode support with Tailwind CSS. Simply add the dark class to your HTML element:
<html class="dark"> <!-- Your app --> </html>
Or use dynamic switching:
document.documentElement.classList.toggle("dark");
Debugging Style Issues
Each element has a data-class attribute showing which config key controls it. Inspect in browser to find the right configuration option.
Pagination Options
Customize pagination behavior and options.
Per-Page Options
Configure available per-page choices:
// config/livewire-datatable.php 'per_page_options' => [10, 25, 50, 100, 'all']
The 'all' option allows users to display all records at once.
Default Per Page
// Set in component public $perPage = 25;
Or let users choose with the per-page selector in the UI.
📝 Complete Example
Here's a comprehensive example with multiple features: 'export_dropdown_arrow' => '-mr-1 ml-2 h-5 w-5', 'export_button' => 'px-4 py-2 text-sm font-medium text-white bg-blue-600 hover:bg-blue-700 dark:bg-blue-500 dark:hover:bg-blue-600 rounded-sm shadow-sm focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-500 dark:focus:ring-offset-gray-800',
// Table structure
'table_wrapper' => 'overflow-x-auto border border-gray-200 dark:border-gray-700 bg-white dark:bg-gray-800 shadow',
'table' => 'min-w-full divide-y divide-gray-200 dark:divide-gray-700',
// Table headers
'thead' => '',
'thead_row' => '',
'th' => 'px-6 py-3 bg-gray-50 dark:bg-gray-700/50 text-left text-xs font-medium text-gray-500 dark:text-gray-400 uppercase tracking-wider',
'th_sort_button' => 'group inline-flex items-center gap-x-2 hover:text-gray-700 dark:hover:text-gray-200',
'th_sort_icon_wrapper' => 'inline-flex rounded p-1 transition',
'th_sort_icon_active' => 'size-4 text-blue-500',
'th_sort_icon_inactive' => 'size-4 text-gray-400 dark:text-gray-500 group-hover:text-gray-700 dark:group-hover:text-gray-200',
'th_text' => 'text-gray-700 dark:text-gray-200 capitalize',
// Table body
'tbody' => 'divide-y divide-gray-200 dark:divide-gray-700',
'tr' => 'hover:bg-gray-50 dark:hover:bg-gray-700/25 transition',
'td' => 'px-6 py-4 whitespace-nowrap text-sm text-gray-700 dark:text-gray-200',
// Empty state
'empty_wrapper' => 'px-6 py-8 text-center',
'empty_content' => 'flex flex-col items-center justify-center',
'empty_icon' => 'size-16 text-gray-400 dark:text-gray-500 mb-2',
'empty_text' => 'text-gray-500 dark:text-gray-400 text-sm font-medium',
// Pagination
'pagination_wrapper' => 'p-4',
// Column-specific styling (optional)
// 'td_id' => 'font-mono text-gray-500 text-xs',
// 'td_email' => 'font-medium text-blue-600',
// 'td_status' => 'text-center font-semibold',
// 'td_actions' => 'text-right space-x-2',
]
];
## 📝 Complete Example
Here's a comprehensive example with multiple features:
```php
<?php
namespace App\Livewire;
use App\Models\User;
use Livewire\Component;
use Livewire\Attributes\On;
class AdvancedUsersTable extends Component
{
#[On('user-edit')]
public function editUser($id)
{
$this->redirect(route('users.edit', $id));
}
#[On('user-delete')]
public function deleteUser($id)
{
try {
User::findOrFail($id)->delete();
session()->flash('message', 'User deleted!');
} catch (\Exception $e) {
session()->flash('error', 'Failed to delete user.');
}
}
public function render()
{
return view('livewire.advanced-users-table', [
'model' => User::class,
'scope' => 'active',
'columns' => [
'id' => 'ID',
'name' => 'Name',
'email' => 'Email',
'department.name' => 'Department',
'role.name' => 'Role',
'status' => 'Status',
'created_at' => 'Joined',
'actions' => 'Actions'
],
'searchable' => ['name', 'email'],
'unsortable' => ['actions'],
'customColumns' => [
'status' => 'components.table.status-badge',
'actions' => 'components.table.user-actions'
],
'defaultSortField' => 'created_at',
'defaultSortDirection' => 'desc',
]);
}
}
✅ API Reference
Quick reference of all available parameters:
| Parameter | Type | Description |
|---|---|---|
model |
string | Eloquent model class |
columns |
array | Field names and labels |
searchable |
array | Searchable field names |
unsortable |
array | Non-sortable field names |
customColumns |
array | Custom template paths |
formatters |
array | Value formatters |
scope |
string | Query scope name |
scopeParams |
array | Query scope parameters |
defaultSortField |
string | Initial sort field |
defaultSortDirection |
string | 'asc' or 'desc' |
theme |
array | CSS class overrides |
apiConfig |
array | API configuration |
❓ Troubleshooting
Common Issues
Search not working on relationships
Ensure the relationship is eager loaded in your model using $with:
protected $with = ['department', 'role'];
Custom columns not displaying
- Verify the view file exists at the specified path
- Check that the view receives
$itemand$valuevariables
Styles not applying
- Verify Tailwind CSS is properly configured
- Check that package views are in
tailwind.config.jscontent array
Export not working
- Verify export is enabled in config
- Check that required packages are installed
Getting Help
- Check GitHub issues
- Review the examples in this documentation
- Inspect browser console for errors
💝 Support
If this package has helped your project, consider supporting its continued development:
🔒 Security
Please report security vulnerabilities to info@developerawam.com instead of using the public issue tracker.
👥 Credits
- Developer Awam - Package Author
- Restu - Lead Developer
📄 License
Licensed under the MIT License - see LICENSE.md for details.
Ready to build amazing DataTables? Get started now and transform your Laravel applications with beautiful, interactive tables!