Livewire + Flux UI client
The Livewire client is server-driven: grid state lives in the component, and the protocol request is built and answered on the server during render. It uses Flux UI for chrome and inlines the theme automatically.
Install
composer require elyra/datagrid-livewire
php artisan vendor:publish --tag=elyra-datagrid-lang # optional (translations)
Requires Livewire 3.5+/4 and Flux UI.
Anatomy
Extend the abstract DataGrid component. Implement definition() (server source)
and columns() (display config); optionally aggregates().
<?php
namespace App\Livewire;
use Elyra\DataGrid\Livewire\DataGrid;
use Elyra\DataGrid\Server\Grid;
use Elyra\DataGrid\Server\GridDefinition;
use Livewire\Attributes\Layout;
#[Layout('components.layouts.app')]
class SalesGrid extends DataGrid
{
public string $heading = 'Sales';
// Features (toggle on/off)
public bool $sortable = true;
public bool $filterable = true; // filter row + facet dropdowns
public bool $searchable = true;
public bool $selectable = true;
public bool $groupable = true;
public bool $editable = true;
public string $editMode = 'slideover'; // 'inline' | 'modal' | 'slideover'
public bool $exportable = true;
public bool $masterDetail = false;
public int $perPage = 20;
// Theme
public string $accent = ''; // '' = follow app; or 'emerald', etc.
protected function definition(): GridDefinition
{
return Grid::table('sales')->connection('elyrasql')->key('id')
->columns(['id', 'store_id', 'region', 'category', 'sku'])
->column('status', editable: true, editor: 'select',
rules: 'required|in:pending,paid,shipped,delivered,returned')
->column('qty', type: 'number', editable: true, rules: 'required|integer|min:0')
->column('revenue', type: 'number', editable: true, rules: 'required|numeric')
->column('margin', type: 'number')
->searchable(['sku', 'category']);
}
protected function columns(): array
{
return [
['field' => 'sku', 'header' => 'SKU', 'frozen' => true, 'cell' => ['type' => 'link', 'href' => '/orders/{id}']],
['field' => 'region', 'header' => 'Region'],
['field' => 'category', 'header' => 'Category'],
['field' => 'status', 'header' => 'Status', 'editable' => true, 'editor' => 'select', 'options' => [
['value' => 'pending', 'label' => 'pending'],
['value' => 'paid', 'label' => 'paid'],
], 'badges' => ['pending' => 1, 'paid' => 2, 'shipped' => 3, 'delivered' => 4, 'returned' => 5]],
['field' => 'qty', 'header' => 'Qty', 'type' => 'number', 'editable' => true, 'editor' => 'number'],
['field' => 'revenue', 'header' => 'Revenue', 'type' => 'number', 'editable' => true, 'editor' => 'number', 'cell' => ['type' => 'currency', 'symbol' => 'kr ', 'decimals' => 2]],
['field' => 'margin', 'header' => 'Margin', 'type' => 'number', 'cell' => ['type' => 'bar', 'max' => 1200]],
];
}
protected function aggregates(): array
{
return [
['field' => 'revenue', 'fn' => 'sum', 'as' => 'sum_revenue'],
['field' => 'margin', 'fn' => 'sum', 'as' => 'sum_margin'],
];
}
}
// routes/web.php
Route::get('/sales', App\Livewire\SalesGrid::class);
Feature properties
| Property | Default | Purpose |
|---|---|---|
$sortable |
true | Column sorting |
$filterable |
true | Filter row + operator menus |
$filterRow |
true | Show the discreet filter row |
$searchable |
false | Global search box |
$selectable |
false | Row selection + checkbox column |
$groupable |
false | Grouping + drag-to-group |
$editable |
false | Editing + command column |
$editMode |
inline |
inline | modal | slideover |
$filterBuilder |
false | Advanced AND/OR filter builder |
$assistant |
false | Natural-language "ask the grid" box (needs laravel/ai and ELYRA_DATAGRID_ASSISTANT=true) |
$exportable |
true | Excel toolbar button |
$exportFormat |
csv |
csv | xlsx |
$masterDetail |
false | Expandable detail rows |
$detailView |
null | Blade view for the detail row |
$tree |
false | Tree grid: ['parentField'=>…,'rootValue'=>null,'hasChildrenField'=>null] |
$headerGroups |
[] |
Multi-column headers |
$perPage |
20 | Page size |
$pageSizeOptions |
[20,50,100,200] |
Page-size choices |
$theme |
'' |
'' (app) or a preset like tokyo-night |
$accent |
'' |
'' (app) or a Flux-style accent |
Natural-language filtering
Set public bool $assistant = true; to add an "ask in plain language" box to the
toolbar. Typing a question calls GridDefinition::ask() server-side, which
translates it into an allow-listed filter and applies it to the advanced builder.
Requires the optional laravel/ai package and a provider key; degrades to a
graceful message otherwise.
Two gates, both enforced server-side rather than by hiding the box: this
component flag, and ELYRA_DATAGRID_ASSISTANT=true. Questions are also length-
bounded and rate-limited per caller, because each one is a billed LLM call. See
Natural-language filtering.
Notes
- The theme CSS is inlined once per page via
@include('elyra-datagrid::styles')inside the component view — no build step needed. - Editing, facets, grouping and paging all call the server package directly; totals/aggregates are cached per filter within the component lifecycle.
- Keyboard navigation & cell selection are provided via Alpine (bundled with Livewire/Flux).
See the guides for editing, grouping, filtering, and theming.
Pivot
For a cross-tab over the same source — dimensions on two axes, with subtotals
and margins — this client also ships Elyra\DataGrid\Livewire\DataPivot. See
Pivot.