arkhas / livewire-datatable
A powerful datatable component for Laravel Livewire with filters, actions, and export capabilities
Installs: 7
Dependents: 0
Suggesters: 0
Security: 0
Stars: 0
Watchers: 0
Forks: 0
Open Issues: 0
pkg:composer/arkhas/livewire-datatable
Requires
- php: ^8.1
- illuminate/support: ^10.0|^11.0|^12.0
- livewire/flux: ^1.0|^2.0
- livewire/livewire: ^3.0|^4.0
Requires (Dev)
- orchestra/testbench: ^8.0|^9.0
- pestphp/pest: ^2.36
- phpunit/phpunit: ^10.0
This package is auto-updated.
Last update: 2026-01-26 15:00:17 UTC
README
A powerful datatable component for Laravel Livewire with filters, actions, and export capabilities. Built with Flux Pro components.
Requirements
- PHP 8.1+
- Laravel 10.x or 11.x
- Livewire 3.x
- Flux Pro
Installation
composer require arkhas/livewire-datatable
Publish the config file (optional):
php artisan vendor:publish --tag=livewire-datatable-config
Publish the views for customization (optional):
php artisan vendor:publish --tag=livewire-datatable-views
Quick Start
1. Create a Datatable Component
php artisan make:datatable TasksTable
2. Configure Your Datatable
<?php namespace App\Livewire; use Livewire\Component; use Arkhas\LivewireDatatable\Traits\WithDatatable; use Arkhas\LivewireDatatable\Table\EloquentTable; use Arkhas\LivewireDatatable\Columns\Column; use Arkhas\LivewireDatatable\Columns\CheckboxColumn; use Arkhas\LivewireDatatable\Columns\ActionColumn; use Arkhas\LivewireDatatable\Filters\Filter; use Arkhas\LivewireDatatable\Filters\FilterOption; use Arkhas\LivewireDatatable\Filters\DateFilter; use Arkhas\LivewireDatatable\Filters\RangeFilter; use Arkhas\LivewireDatatable\Actions\TableAction; use Arkhas\LivewireDatatable\Actions\ColumnAction; use Arkhas\LivewireDatatable\Actions\ColumnActionGroup; use App\Models\Task; class TasksTable extends Component { use WithDatatable; public function setup(): void { $table = new EloquentTable(Task::with('assignee')); $table ->exportName('tasks-' . date('Y-m-d')) ->searchable(['title', 'description']) ->columns([ CheckboxColumn::make(), Column::make('id') ->html(fn(Task $task) => (string) $task->id), Column::make('title') ->label('Task') ->width('200px') ->toggable(false) ->html(fn(Task $task) => "<a href='/edit/{$task->id}'>{$task->title}</a>"), Column::make('status') ->html(fn(Task $task) => ucfirst(str_replace('_', ' ', $task->status))) ->icon(fn(Task $task) => match($task->status) { 'todo' => 'circle', 'in_progress' => 'timer', 'done' => 'check-circle', 'canceled' => 'circle-x', default => null, }), Column::make('priority') ->html(fn(Task $task) => ucfirst($task->priority)) ->icon(fn(Task $task) => match($task->priority) { 'low' => 'arrow-down', 'medium' => 'arrow-right', 'high' => 'arrow-up', default => null, }), Column::make('assignee.name') ->label('Assignee'), ActionColumn::make() ->action( ColumnActionGroup::make() ->icon('ellipsis-vertical') ->actions([ ColumnAction::make('edit') ->label('Edit') ->icon('pencil') ->url(fn(Task $task) => route('tasks.edit', $task->id)) ->separator(), ColumnAction::make('delete') ->label('Delete') ->icon('trash-2') ->confirm(fn(Task $task) => [ 'title' => 'Delete Task', 'message' => "Are you sure you want to delete '{$task->title}'?", 'confirm' => 'Delete', 'cancel' => 'Cancel', ]) ->handle(function (Task $task) { $task->delete(); return ['success' => true, 'message' => 'Task deleted']; }), ]) ), ]) ->filters([ Filter::make('status') ->multiple() ->label('Status') ->options([ FilterOption::make('todo') ->label('To Do') ->icon('circle') ->count(fn() => Task::where('status', 'todo')->count()) ->query(fn($query, $keyword) => $query->where('status', $keyword)), FilterOption::make('in_progress') ->label('In Progress') ->icon('timer') ->count(fn() => Task::where('status', 'in_progress')->count()) ->query(fn($query, $keyword) => $query->where('status', $keyword)), FilterOption::make('done') ->label('Done') ->icon('check-circle') ->count(fn() => Task::where('status', 'done')->count()) ->query(fn($query, $keyword) => $query->where('status', $keyword)), ]), Filter::make('priority') ->label('Priority') ->options([ FilterOption::make('low')->label('Low')->icon('arrow-down') ->query(fn($query, $keyword) => $query->where('priority', $keyword)), FilterOption::make('medium')->label('Medium')->icon('arrow-right') ->query(fn($query, $keyword) => $query->where('priority', $keyword)), FilterOption::make('high')->label('High')->icon('arrow-up') ->query(fn($query, $keyword) => $query->where('priority', $keyword)), ]), // Example: Date filter (single mode) DateFilter::make('created_at') ->label('Created At') ->column('created_at') ->min('2024-01-01') ->withToday() ->clearable(), // Example: Date range filter // RangeFilter::make('date_range') // ->label('Date Range') // ->column('created_at') // ->withPresets() // ->presets('today yesterday thisWeek last7Days thisMonth yearToDate allTime') // ->minRange(3) // ->maxRange(30), ]) ->actions([ TableAction::make('delete') ->label('Delete') ->icon('trash-2', position: 'right') ->props(['variant' => 'destructive', 'size' => 'sm']) ->confirm(fn($ids) => [ 'title' => 'Delete ' . count($ids) . ' Task(s)', 'message' => 'Are you sure you want to delete the selected tasks?', 'confirm' => 'Delete', 'cancel' => 'Cancel', ]) ->handle(function ($ids) { Task::whereIn('id', $ids)->delete(); return ['success' => true, 'message' => 'Tasks deleted']; }), ]); $this->table($table); } public function render() { return view('livewire-datatable::datatable', [ 'table' => $this->getTable(), 'data' => $this->getData(), ]); } }
3. Use in Your Blade View
<livewire:tasks-table />
Features
Columns
- Column: Standard column with HTML rendering, icons, sorting, filtering
- CheckboxColumn: Row selection column
- ActionColumn: Actions dropdown menu per row
Filters
- Filter: Dropdown filter with multiple options and selection
- DateFilter: Date picker filter for single date selection (using Flux date picker)
- RangeFilter: Date picker filter for date range selection with presets support (using Flux date picker)
Column Options
Column::make('name') ->label('Display Label') // Custom label ->width('200px') // Column width ->sortable(true) // Enable sorting ->sortBy('custom_column') // Custom sort column ->toggable(true) // Can be hidden/shown ->hidden(false) // Initially hidden ->html(fn($model) => ...) // Custom HTML rendering ->icon(fn($model) => ...) // Dynamic icon ->filter(fn($query, $v) => ...) // Column-level filter ->exportAs(fn($model) => ...) // Custom export value
Filters
Dropdown Filters
Filter::make('status') ->label('Status') ->multiple() // Allow multiple selections ->options([ FilterOption::make('active') ->label('Active') ->icon('check-circle') ->count(fn() => Model::where('status', 'active')->count()) ->query(fn($q, $keyword) => $q->where('status', $keyword)), ])
Date Filters
Date filters use the Flux date picker component. There are two types: DateFilter for single date selection and RangeFilter for date ranges.
Single Date Filter:
DateFilter::make('created_at') ->label('Created At') ->column('created_at') // Database column to filter on ->min('2024-01-01') ->max('today') ->withToday() ->selectableHeader() ->clearable()
Date Range Filter:
RangeFilter::make('date_range') ->label('Date Range') ->column('created_at') ->withPresets() // Enable preset date ranges (Last 7 Days, This Month, etc.) ->presets('today yesterday thisWeek last7Days thisMonth yearToDate allTime') ->minRange(3) // Minimum days in range ->maxRange(30) // Maximum days in range ->min('2024-01-01')
Common Options (available for both DateFilter and RangeFilter):
column(string)- Database column to filter on (defaults to filter name)min(string)- Minimum selectable datemax(string)- Maximum selectable datewithToday(bool)- Show "Today" shortcut buttonselectableHeader(bool)- Make month/year selectableclearable(bool)- Show clear buttondisabled(bool)- Disable the date pickerinvalid(bool)- Apply error stylinglocale(string)- Set the locale (e.g., 'fr', 'en-US')placeholder(string)- Placeholder textopenTo(string)- Date to open to if no date is selectedforceOpenTo(bool)- Force open to the open-to datemonths(int)- Number of months to displaystartDay(int)- Day of week to start on (0-6, Sunday-Saturday)weekNumbers(bool)- Display week numberswithInputs(bool)- Display date inputs at the topwithConfirmation(bool)- Require confirmation before applyingunavailable(string)- Comma-separated list of unavailable datesfixedWeeks(bool)- Display consistent number of weeks
RangeFilter Specific Options:
withPresets(bool)- Enable preset date rangespresets(string)- Space-separated list of presets to showminRange(int)- Minimum number of days in rangemaxRange(int)- Maximum number of days in range
Query Handling:
The filters automatically handle query building:
- DateFilter: Uses
whereDate()for exact date matching - RangeFilter: Uses
whereBetween()with start and end dates
You can also provide a custom query callback:
// For DateFilter DateFilter::make('created_at') ->column('created_at') ->query(function ($query, $date) { // Custom query logic $query->whereDate('created_at', $date->format('Y-m-d')); }) // For RangeFilter RangeFilter::make('date_range') ->column('created_at') ->query(function ($query, $dates) { // Custom query logic [$startDate, $endDate] = $dates; $query->whereBetween('created_at', [$startDate, $endDate]); })
Actions
Bulk Actions (TableAction)
TableAction::make('delete') ->label('Delete Selected') ->icon('trash-2', position: 'right') ->props(['variant' => 'danger', 'size' => 'sm']) ->confirm(fn($ids) => [...]) ->handle(fn($ids) => [...])
Row Actions (ColumnAction)
ColumnAction::make('edit') ->label('Edit') ->icon('pencil') ->url(fn($model) => route('edit', $model->id)) // OR ->handle(fn($model) => [...]) ->confirm(fn($model) => [...]) ->separator() // Add separator line after
Export
$table->exportName('filename') ->exportable(true) ->exportFormats(['csv', 'xlsx'])
Note: XLSX export requires
maatwebsite/excelpackage.
Configuration
// config/livewire-datatable.php return [ 'per_page' => 10, 'per_page_options' => [10, 25, 50, 100], 'default_sort_direction' => 'asc', 'search_debounce' => 300, 'export' => [ 'default_format' => 'csv', 'formats' => ['csv', 'xlsx'], 'chunk_size' => 1000, ], ];
Customizing Views
Publish the views:
php artisan vendor:publish --tag=livewire-datatable-views
Views will be published to resources/views/vendor/livewire-datatable/.
Icons
This package uses Lucide icons via Flux Pro. All icon names must be in kebab-case (e.g., check-circle, trash-2, arrow-down).
Make sure to install the icons you need using the Flux icon command:
php artisan flux:icon circle timer check-circle circle-x arrow-down arrow-right arrow-up ellipsis-vertical pencil trash-2 check x-mark arrow-down-tray adjustments-horizontal circle-plus chevron-left chevron-right chevrons-left chevrons-right chevrons-up-down
Icons Used in This Package
The following icons are used throughout the package:
Column Icons:
circle- Default/empty statetimer- In progress statuscheck-circle- Completed/done statuscircle-x- Canceled/removed statusarrow-down- Low priorityarrow-right- Medium priorityarrow-up- High priority
Action Icons:
ellipsis-vertical- Action menu triggerpencil- Edit actiontrash-2- Delete action
Filter Icons:
circle-plus- Add filter buttoncheck- Selected filter option
Toolbar Icons:
x-mark- Reset filters buttonarrow-down-tray- Export buttonadjustments-horizontal- View options button
Pagination Icons:
chevron-left- Previous pagechevron-right- Next pagechevrons-left- First pagechevrons-right- Last page
Sorting Icons:
arrow-up- Ascending sortarrow-down- Descending sortchevrons-up-down- Sortable indicator
You can use any Lucide icon by importing it with php artisan flux:icon <icon-name> and using it in your datatable configuration.
License
MIT License