inengine / tableui
A flexible table ui system for InEngine apps
Fund package maintenance!
Requires
- php: ^8.5
- illuminate/contracts: ^12.0||^13.0
- illuminate/database: ^12.0||^13.0
- laravel/serializable-closure: ^2.0.10
- spatie/laravel-package-tools: ^1.90.0
Requires (Dev)
- larastan/larastan: ^3.0
- laravel/pint: ^1.14
- livewire/livewire: ^4.0
- nunomaduro/collision: ^8.8
- orchestra/testbench: ^11.0.0||^10.0.0||^9.0.0
- pestphp/pest: ^4.0
- pestphp/pest-plugin-arch: ^4.0
- pestphp/pest-plugin-laravel: ^4.0
- phpstan/extension-installer: ^1.4
- phpstan/phpstan-deprecation-rules: ^2.0
- phpstan/phpstan-phpunit: ^2.0
Suggests
- livewire/livewire: Required to use the Table Livewire component (^4.0).
README
TableUI is a one-stop package for Laravel and InEngine-based apps for displaying, filtering, and performing actions on data as an interactive table.
Support us
If you find this package helpful please consider supporting us.
Installation
You can install the package via composer:
composer require inengine/tableui
You can publish the config file with:
php artisan vendor:publish --tag="tableui-config"
Tailwind CSS (v4)
Recommended (host app already uses @tailwindcss/vite): import resources/css/tableui.css only — it pulls in partials/tableui-sources.css (@source scanning for this package’s Blade views and inline literals), shared base [x-cloak], filter-panel view transitions, and components/tableui-*.css (@layer components chunks). It does not @import "tailwindcss" again, so Tailwind is loaded a single time from your app entry (e.g. base.css).
@import "tailwindcss"; /* …your @source / @theme … */ @import "./../../vendor/inengine/tableui/resources/css/tableui.css";
Optional publish (copy into your repo):
php artisan vendor:publish --tag="tableui-css"
@import "./vendor/tableui.css"; /* resources/css/vendor/tableui.css */
Standalone bundle: resources/css/tableui-standalone.css imports Tailwind + tableui.css and is the Vite input
for maintainers. Building produces public/css/tableui.css for environments that link a precompiled stylesheet instead
of merging into the app pipeline:
cd vendor/inengine/tableui # or this package’s root when developing the package npm install npm run build
Release checklist: run npm run build so public/css/tableui.css stays up to date for consumers who use the static
file.
The config includes:
empty_message— default empty-state copy for the Livewire table when noemptyMessageprop is passed.column_types— package defaults grouped by column kind. Forbooleanyou can setshow_false(hide the false-state icon whenfalse), plustrue/falsebranches, each with:icon— Heroicons v2 outline slug (e.g.check,x-mark). Unknown slugs fall back until you extend the icon map.color— Tailwind text colour for the SVG (stroke="currentColor"). Use a shorthand (green-600→text-green-600), full classes (text-green-600 dark:text-green-400), arbitrary values, or your own CSS utility classes.
column_types.id— optionalmono_classwrapper +ulid_suffix_lengthfor shortened ULIDs (see config comments).column_types.number—max_decimalsfor non-integer formatting inNumberColumnRenderer.column_types.money—divisor(default100for cents),decimals,prefix,suffixforMoneyColumnRenderer.columns/renderers— optional FQCN lists for app-defined column types and renderers (see comments in the published file).
Column inference (when building Columns from Schema::getColumnType() maps plus sample data) uses the schema type
first (boolean, id patterns, timestamps, enums, text, string family, numeric family), then upgrades using
key + sample within that family — e.g. string + email + valid address → EmailColumn; numeric + monetary name →
MoneyColumn. Without schema, legacy name/sample heuristics apply. See ColumnInference for the full order.
ColumnTypes/—Column,ColumnFactory, plus subfolders:Primitives/—BooleanColumn,StringColumn,TextColumn,EnumColumn,TimestampColumn,NumberColumn,IdColumnComplex/—EmailColumn(extendsStringColumn),MoneyColumn(extendsNumberColumn),PhoneColumn( extendsStringColumn)
See config/tableui.php in this package for full inline documentation.
Optionally, you can publish the views using
php artisan vendor:publish --tag="tableui-views"
Usage
Create a table from an Eloquent collection and render it with the Livewire component:
use App\Models\User; use InEngine\TableUI\Table; $table = Table::fromCollection(User::query()->latest()->limit(50)->get());
<livewire:tableui.table-view :table="$table" />
Extending TableUI
TableUI supports app-level extension points through config/tableui.php.
Custom column types
- Create a column class that extends
InEngine\TableUI\ColumnTypes\Column. - Implement:
InEngine\TableUI\Contracts\BuildsColumnFromAttributeKeyInEngine\TableUI\Contracts\DefinesColumnRenderers
- Register your column and renderer classes in
tableui.columnsandtableui.renderers.
namespace App\TableUI\Columns; use InEngine\TableUI\ColumnTypes\Column; use InEngine\TableUI\Contracts\BuildsColumnFromAttributeKey; use InEngine\TableUI\Contracts\DefinesColumnRenderers; use InEngine\TableUI\Contracts\ParticipatesInColumnInference; use InEngine\TableUI\Rendering\ColumnRendererInterface; final class SkuColumn extends Column implements BuildsColumnFromAttributeKey, DefinesColumnRenderers, ParticipatesInColumnInference { public static function fromAttributeKey(string $attributeKey): Column { return new self($attributeKey); } public static function matchesSample(string $attributeKey, mixed $sample): bool { return str_contains(strtolower($attributeKey), 'sku'); } /** * @return list<class-string<ColumnRendererInterface>> */ public static function rendererClassNames(): array { return [SkuColumnRenderer::class]; } /** * @return class-string<ColumnRendererInterface> */ public static function defaultRendererClassName(): string { return SkuColumnRenderer::class; } }
// config/tableui.php 'columns' => [ App\TableUI\Columns\SkuColumn::class, ], 'renderers' => [ App\TableUI\Renderers\SkuColumnRenderer::class, ],
Custom default actions
Add extra default actions for model-backed tables by implementing InEngine\TableUI\Contracts\BuildsDefaultTableAction
and registering the class in tableui.actions.
namespace App\TableUI\Actions; use InEngine\TableUI\ActionTypes\Action; use InEngine\TableUI\ActionTypes\UpdateAction; use InEngine\TableUI\Contracts\BuildsDefaultTableAction; use InEngine\TableUI\Table; final class ArchiveActionProvider implements BuildsDefaultTableAction { public static function forTable(Table $table): ?Action { return new UpdateAction(label: 'Archive', target: '/users/{id}/archive'); } }
// config/tableui.php 'actions' => [ App\TableUI\Actions\ArchiveActionProvider::class, ],
Enum filters (multiselect)
When tableui.filters.enum_allow_multiple is true (the package default), enum column filters render as a *
multiselect dropdown* (open to pick one or more values; × clears; selected options use the table primary color).
Rows match if the value is any of the selected options (OR). Set to false for a classic single <select>. You can
also set allowMultiple on a specific FilterDefinition when building filters manually.
Custom filter definitions
Add custom filter mapping for your custom columns by implementing
InEngine\TableUI\Contracts\BuildsFilterDefinitionForColumn and registering in tableui.filter_definitions.
namespace App\TableUI\Filters; use App\TableUI\Columns\SkuColumn; use InEngine\TableUI\ColumnTypes\Column; use InEngine\TableUI\Contracts\BuildsFilterDefinitionForColumn; use InEngine\TableUI\FilterTypes\FilterDefinition; use InEngine\TableUI\FilterTypes\FilterType; final class SkuFilterDefinitionProvider implements BuildsFilterDefinitionForColumn { public static function forColumn(Column $column, ?array $enumOptions = null): ?FilterDefinition { if (! $column instanceof SkuColumn) { return null; } return new FilterDefinition( columnKey: $column->key(), label: 'SKU', type: FilterType::Text, ); } }
// config/tableui.php 'filter_definitions' => [ App\TableUI\Filters\SkuFilterDefinitionProvider::class, ],
Pick a FilterType case that matches how TableUiFilterMatcher should interpret stored filter values (Text,
Email, Phone, Boolean, Enum, Number, Money, Date, Datetime, Time). Use allowMultiple on the
definition when you need OR-style enum/text matching beyond the global tableui.filters.enum_allow_multiple flag.
Custom Blade views and CSS (UI)
Use this path when you need different markup, layout hooks, or styling — without forking the package.
Publish views (copies into resources/views/vendor/tableui/; Laravel resolves these before the package copies):
php artisan vendor:publish --tag="tableui-views"
Typical overrides:
livewire/table.blade.php— outer shell, toolbar includes, scroll wrapper.components/table/*.blade.php— thead, body row, toolbar, bulk toolbar, pagination.components/table/filters/*.blade.php— each filter control (text, enum multiselect, range, etc.).
Keep the same Livewire state ($filterDefinitions, $filterValues, wire:model bindings) when you change layout so the
PHP side of TableUI continues to hydrate correctly.
Cell rendering vs Blade: body cells go through <livewire:tableui.column>, which delegates to your registered ColumnRendererInterface classes from tableui.renderers. Override appearance for a column type there; use Blade overrides when you need structural changes around the table (toolbar, filter row, wrappers).
Publish the CSS entry (optional — snapshot into your repo if you do not want to reference vendor/):
php artisan vendor:publish --tag="tableui-css"
You still normally @import the single published resources/css/vendor/tableui.css after Tailwind in your Vite
entry. That file remains the supported contract; internally it @imports partials/ and components/ so you can
vendor only what you touch (for example copy components/tableui-table.css into your app and layer overrides after
the package import).
Standalone / CDN stylesheet: maintainers run npm run build in this package so public/css/tableui.css stays
in sync for consumers who link the precompiled bundle instead of merging into a Tailwind app pipeline.
Testing
composer test
Changelog
Please see CHANGELOG for more information on what has changed recently.
Contributing
Please see CONTRIBUTING for details.
Security Vulnerabilities
Please review our security policy on how to report security vulnerabilities.
Credits
License
The MIT License (MIT). Please see License File for more information.