Tall DataTables
Performant, feature-rich datatables for the TALL stack. Built on Livewire 4 Islands architecture with Alpine.js driven rendering for minimal payloads.
Requirements
- PHP 8.4+
- Laravel 12+
- Livewire 4+
- TallStackUI 3+
- Alpine.js 3+
- Tailwind CSS 3+
Installation
composer require team-nifty-gmbh/tall-datatables:^2.0Add the scripts and styles to your layout:
<datatable:styles />
<datatable:scripts />Publish migrations and run them:
php artisan vendor:publish --tag="tall-datatables-migrations"
php artisan migrateQuick Start
class UserDataTable extends DataTable
{
protected string $model = User::class;
public array $enabledCols = ['name', 'email', 'created_at'];
}<livewire:data-tables.user-data-table />Layouts
Three built-in layouts: table (default), grid, and kanban.
View-Mode Switcher
Let users switch between layouts at runtime:
protected function availableLayouts(): array
{
return ['table', 'grid', 'kanban'];
}When more than one layout is configured, a switcher appears in the toolbar. The active layout is persisted in saved filters.
Grid Layout
Cards in a responsive CSS grid. Image columns get hero treatment.
protected function availableLayouts(): array
{
return ['table', 'grid'];
}Kanban Layout
Cards grouped into lanes by a column value. Drag & drop between lanes.
protected function availableLayouts(): array
{
return ['table', 'kanban'];
}
// Which column determines the lanes
protected function kanbanColumn(): string
{
return 'state';
}
// Optional: explicit lane config (order, labels, colors)
protected function kanbanLanes(): ?array
{
return [
'open' => ['label' => 'Open', 'color' => 'emerald'],
'in_progress' => ['label' => 'In Progress', 'color' => 'amber'],
'done' => ['label' => 'Done', 'color' => 'indigo'],
];
}
// Handle drag & drop
public function kanbanMoveItem(int|string $id, string $targetLane): void
{
MyModel::findOrFail($id)->update(['state' => $targetLane]);
}
// Optional: custom card blade view
protected function kanbanCardView(): ?string
{
return 'components.my-kanban-card';
}If kanbanLanes() returns null, lanes are auto-generated from the column's enum/state values.
Filtering
Sidebar Filters
Enable filtering with the sidebar:
public bool $isFilterable = true;Available operators: =, !=, >, >=, <, <=, like, not like, starts with, ends with, contains, does not contain, in, not in, is null, is not null, between.
The in and not in operators accept comma-separated values.
Date Presets
Date columns automatically show a preset dropdown: Today, Yesterday, This Week/Month/Quarter/Year, Last 7/30 Days, Last Week/Month/Quarter/Year. A "Custom" option opens inline fields for building custom relative date calculations.
Saved Filters
Users can save their current filter/column/sort configuration and reload it later. Supports shared filters across team members:
protected function canShareFilters(): bool
{
return true;
}Sorting
Click a column header to sort. Shift+Click for multi-sort on additional columns.
// Restrict sortable columns (default: all)
public array $sortable = ['name', 'created_at'];Selection
public bool $isSelectable = true;Select individual rows or use "select all" (wildcard). The wildcard stays compact (['*']) regardless of record count. Use getSelectedValues() or getSelectedModels() in your actions to resolve the actual records.
Relation Columns
Display columns from related models using dot notation:
public array $enabledCols = [
'name',
'email',
'department.name',
'department.manager.email',
];Relation Count Columns
Show relation counts by adding _count suffix in the column configuration. Counts are filterable and sortable:
public array $enabledCols = ['name', 'orders_count', 'comments_count'];Export
Export data in three formats: Excel (.xlsx), CSV, and JSON. Users select the format from a dropdown in the export tab.
// Disable export (enabled by default)
public bool $isExportable = false;CSV uses semicolon delimiter with UTF-8 BOM for Excel compatibility. JSON exports relations as nested objects.
Row Actions
Define actions using DataTableButton:
protected function getRowActions(): array
{
return [
DataTableButton::make('edit')
->label(__('Edit'))
->icon('pencil')
->wireClick('edit(record.id)'),
];
}Row Drag & Drop
Enable manual row reordering:
protected function getRowDragDropConfig(): ?array
{
return [
'column' => 'sort_order',
];
}Custom Formatters
Register formatters for custom display logic:
use TeamNiftyGmbH\DataTable\Formatters\FormatterRegistry;
app(FormatterRegistry::class)->register(MyCast::class, new MyFormatter());Built-in formatters: boolean, date, datetime, money, percentage, image, link, badge, float, string, array.
Custom Column Transformation
Use augmentItemArray() to add computed columns before formatters are applied:
protected function augmentItemArray(array &$itemArray, Model $item): void
{
$itemArray['full_name'] = $item->first_name . ' ' . $item->last_name;
}Sidebar Tabs
Extend the sidebar with custom tabs:
public function getSidebarTabs(): array
{
$tabs = parent::getSidebarTabs();
$tabs[] = [
'id' => 'my-tab',
'label' => __('My Tab'),
'view' => 'components.my-custom-tab',
];
return $tabs;
}Positive Empty State
Show a friendly message when a table is expected to be empty:
public bool $positiveEmptyState = true;Default Columns
Allow users to save their column layout as the default:
protected function canSaveDefaultColumns(): bool
{
return true;
}Testing
vendor/bin/pestCredits
License
MIT. See LICENSE.