Laravel Datatable is a package to build dynamic tables with search, filters, sorting, pagination, and row actions in a simple interface.
- PHP ^8.2
- Laravel 11, 12 or 13
- Livewire ^3.4 or ^4.0
- A
tk:Blade component library registered in the host application (e.g. Tallkit), since the bundled views (<tk:table.*>,<tk:input>,<tk:select>,<tk:button>,<tk:avatar.profile>,<tk:badge>, ...) are not shipped with this package.
You can install the package via composer:
composer require datalogix/laravel-datatableOptionally publish the config file:
php artisan vendor:publish --tag=datatable-configAdd InteractsWithDataTable to a Livewire component and expose a method that builds and returns a DataTableBuilder. The method's name becomes the table's key, which the Blade views use to call back into the component (search, sort, pagination, actions, ...), so keep it defined as a regular named method rather than a closure:
use App\Models\Post;
use Datalogix\DataTable\Actions\Action;
use Datalogix\DataTable\Actions\BulkAction;
use Datalogix\DataTable\Columns\BadgeColumn;
use Datalogix\DataTable\Columns\DateColumn;
use Datalogix\DataTable\Columns\TextColumn;
use Datalogix\DataTable\DataTableBuilder;
use Datalogix\DataTable\Livewire\Concerns\InteractsWithDataTable;
use Livewire\Component;
class PostsTable extends Component
{
use InteractsWithDataTable;
public function table(): DataTableBuilder
{
return DataTableBuilder::make()
->for(Post::class)
->column(TextColumn::make('title')->sortable()->searchable())
->column(BadgeColumn::make('status')->colors(['draft' => 'gray', 'published' => 'green']))
->column(DateColumn::make('created_at')->sortable())
->action(Action::edit()->route('posts.edit'))
->action(Action::delete()->call('deletePost')->confirm('Are you sure?')->visible(fn (Post $post) => auth()->user()->can('delete', $post)))
->bulkAction(BulkAction::delete()->call('deleteSelectedPosts'));
}
public function deletePost(Post $post): void
{
$this->authorize('delete', $post);
$post->delete();
}
public function render()
{
return view('livewire.posts-table');
}
}Render it in the component's view with the <x-datatable> component:
<x-datatable :builder="$this->table()" />
Action::visible()/->hidden()only control whether an action is rendered — always re-check authorization inside the handler (call()/handleUsing()) itself, sincerunAction()also verifiesisVisible()server-side but any custom Gate/Policy logic is still the developer's responsibility.
Built-in column types: TextColumn, NumberColumn, DateColumn, BooleanColumn, BadgeColumn, ImageColumn, UserColumn. Every column supports:
TextColumn::make('name', label: 'Full name')
->sortable() // or ->sortable('other_column')
->searchable() // or ->searchable(mode: LikeMode::Start)
->filterable() // adds a matching filter input
->formatUsing(fn ($value, $row) => strtoupper($value))
->hide();Filters can be attached directly to a column via ->filterable(), or added independently with InputFilter/SelectFilter:
use Datalogix\DataTable\Filters\SelectFilter;
$builder->filter(
SelectFilter::make('status')->options(['draft' => 'Draft', 'published' => 'Published'])
);For fully custom filtering logic, use ->query():
use Datalogix\DataTable\Filters\InputFilter;
$builder->filter(
InputFilter::make('min_price')->query(fn ($query, $value) => $query->where('price', '>=', $value))
);By default, search runs over every column marked ->searchable(). Override it explicitly, or delegate to Laravel Scout:
$builder->searchUsing(['title', 'body']);
// or
$builder->searchUsingScout(fn ($scoutBuilder) => $scoutBuilder->where('published', true));$builder->expandable(fn (Post $post) => view('posts.expanded-row', ['post' => $post]));Pass a name to make() to render more than one independent table in the same Livewire component — each keeps its own search/sort/filter/pagination state:
public function postsTable(): DataTableBuilder
{
return DataTableBuilder::make(name: 'posts')->for(Post::class)->column(TextColumn::make('title'));
}
public function commentsTable(): DataTableBuilder
{
return DataTableBuilder::make(name: 'comments')->for(Comment::class)->column(TextColumn::make('body'));
}Text search/filters use a like-based match by default. Install datalogix/laravel-builder-macros to get the whereLike query builder macro (accent/case-insensitive matching where supported); without it, the package falls back to a plain LIKE query.