yajra/laravel-datatables
Complete Laravel DataTables installer (core + plugins) for DataTables 2.x, including Editor, Buttons, and Select support. Works with Laravel 13 and PHP 8.3+, providing server-side processing integration and tooling for fast, rich table UIs.
Installation:
composer require yajra/laravel-datatables:^13
Publish config and assets (optional but recommended):
php artisan vendor:publish --provider="Yajra\DataTables\DataTablesServiceProvider"
Register Service Providers (if not auto-discovered in Laravel 13+):
Add to config/app.php:
Yajra\DataTables\DataTablesServiceProvider::class,
Yajra\DataTables\ButtonsServiceProvider::class,
Yajra\DataTables\FractalServiceProvider::class,
First Use Case: Create a route and controller method to handle DataTables requests:
// routes/web.php
Route::get('users/datatables', [UserController::class, 'datatables']);
// UserController.php
public function datatables()
{
return DataTables::of(User::query())
->addColumn('action', function($user) {
return '<button class="edit">Edit</button>';
})
->make(true);
}
Frontend Integration: Include DataTables CSS/JS in your Blade template:
<link rel="stylesheet" href="https://cdn.datatables.net/2.0.3/css/dataTables.dataTables.min.css">
<script src="https://cdn.datatables.net/2.0.3/js/dataTables.min.js"></script>
Initialize DataTables on a table:
<table id="users-table" class="display">
<thead>
<tr><th>Name</th><th>Email</th><th>Actions</th></tr>
</thead>
</table>
<script>
$(document).ready(function() {
$('#users-table').DataTable({
processing: true,
serverSide: true,
ajax: '{{ route("users.datatables") }}',
columns: [
{ data: 'name', name: 'name' },
{ data: 'email', name: 'email' },
{ data: 'action', name: 'action', orderable: false, searchable: false }
]
});
});
</script>
config/datatables.php: Published config file for customizing defaults (e.g., response format, pagination settings).vendor/yajra/laravel-datatables/src/DataTables.php: Core class methods for chaining operations (e.g., addColumn, editColumn, exportOptions).// Basic table with Eloquent
DataTables::of(User::query())
->editColumn('name', 'name_edit') // Enable inline editing
->addColumn('status', function($user) {
return '<span class="badge '. $user->status .'">'.$user->status.'</span>';
})
->rawColumns(['status']) // Disable server-side processing for HTML
->make(true);
DataTables::of(
DB::table('users')
->join('roles', 'users.role_id', '=', 'roles.id')
->select('users.*', 'roles.name as role_name')
)
->addColumn('full_info', function($user) {
return $user->name . ' (' . $user->role_name . ')';
})
->make(true);
// Enable buttons for export/print
DataTables::of(User::query())
->addColumn('action', function($user) {
return '<button class="delete-btn" data-id="'.$user->id.'">Delete</button>';
})
->editColumn('email', 'email_edit')
->exportOptions([
'format' => 'xlsx',
'buttons' => [
'copy', 'csv', 'excel', 'pdf', 'print'
]
])
->make(true);
if (auth()->user()->isAdmin()) {
DataTables::of(User::query())
->addColumn('admin_actions', function($user) {
return '<button class="promote-btn">Promote</button>';
});
}
DataTables::of(User::query())
->setCachePath(storage_path('framework/cache/datatables'))
->make(true);
// Enable editing for specific columns
DataTables::of(User::query())
->editColumn('name', 'name_edit')
->editColumn('email', 'email_edit')
->make(true);
$('#users-table').DataTable({
processing: true,
serverSide: true,
ajax: '{{ route("users.datatables") }}',
// Enable editor
dom: '<"top"lf>rt<"bottom"ip><"clear">',
buttons: ['edit', 'remove']
});
draw.dt events to update the UI or trigger backend logic:
$('#users-table').on('draw.dt', function() {
// Reinitialize select2 or other plugins
});
DataTables::of(User::query())
->exportOptions([
'format' => 'xlsx',
'buttons' => [
[
'extend' => 'excelHtml5',
'title' => 'Users Report',
'customize' => function($excel) {
$excel->setSheetName('User Data');
$excel->getActiveSheet()->getStyle('A1:D1')->applyFromArray([
'font' => ['bold' => true]
]);
}
]
]
])
->make(true);
// app/Http/Middleware/HandleTenants.php
public function handle($request, Closure $next) {
$tenant = Tenant::find($request->tenant_id);
$request->merge(['tenant_id' => $tenant->id]);
return $next($request);
}
DataTables::of(
User::where('tenant_id', request('tenant_id'))
)
->make(true);
// UserTable.php (Livewire Component)
public function datatables()
{
return DataTables::of(User::query())
->addColumn('action', function($user) {
return view('livewire.user-actions', ['user' => $user]);
})
->make(true);
}
<livewire:user-table />
<script>
document.addEventListener('livewire:init', () => {
Livewire.on('tableReady', () => {
$('#users-table').DataTable({
processing: true,
serverSide: true,
ajax: '{{ route("livewire.datatables") }}'
});
});
});
</script>
public function datatables()
{
return Inertia::render('Users/Table', [
'data' => DataTables::of(User::query())
->make(true)
->getData()
]);
}
// Users/Table.vue
export default {
props: ['data'],
mounted() {
this.$nextTick(() => {
$(this.$refs.table).DataTable({
data: this.data,
columns: [
{ data: 'name', name: 'name' },
{ data: 'email', name: 'email' }
]
});
});
}
};
DataTables::of(User::query())
->addColumn('action', function($user) {
return Action::make('edit', 'Edit')
->url(route('users.edit',
How can I help you explore Laravel packages today?