Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Tableui Laravel Package

inengine/tableui

inengine/tableui is a Laravel package for building clean, interactive table UIs. It simplifies rendering query results with reusable columns, sorting, filtering, pagination, and Blade-friendly components for admin panels and dashboards.

View on GitHub
Deep Wiki
Context7

Getting Started

TableUI is a Laravel + Livewire package for building data tables (columns, row actions, bulk actions, toolbar) with minimal blade boilerplate. Start here:

  1. composer require inengine/tableui (v1.0.4 is a safe drop-in from 1.0.3 — the release is dependency bumps plus additive UI features).
  2. Publish the package assets/config so you can override views later:
    php artisan vendor:publish --provider="InEngine\TableUI\TableUIServiceProvider"
    
    The service provider is registered via spatie/laravel-package-tools, so there is a single publish group for config, views, and (if present) compiled assets — publish views on day one even if you don't plan to edit them, since the toolbar markup is the most likely thing you'll want to tweak.
  3. Read the README's table-class example first, then the config/tableui.php file that gets published — that config is the source of truth for default toolbar/action styling keys referenced in the new class-mapping feature.
  4. First use case: a Livewire component listing one Eloquent model with search + sort + pagination, then add a single row action ("Edit"). Once that renders, add a bulk action ("Delete selected"). This exercises all the moving parts (query, columns, actions, toolbar) in about 30 minutes.

If you're upgrading, composer update inengine/tableui and re-run your test suite — no breaking changes are documented, but see the Gotchas section on Livewire row sync, which changes observable behavior after actions.

Implementation Patterns

Table definition as a class. Keep the table definition out of the Blade file: define columns, query, and actions in a dedicated class (or a trait on the Livewire component) so it can be unit tested without rendering HTML. Columns are typically declared as an ordered array with a label, a field/closure accessor, and sortable/searchable flags — keep closures pure so they're cheap to run per row.

Row actions that mutate state. The v1.0.4 change "sync table rows in Livewire after row and bulk actions" means actions no longer require you to manually $this->dispatch('$refresh') or re-query the component to see the effect. Pattern:

  • Row action closure mutates the model, returns/flashes a message.
  • The table re-syncs rows automatically.
  • If your action changes something outside the table's query scope (e.g. a related count rendered in a custom column), that column must be part of the table's re-hydration or it will render stale — either make it a computed column in the table definition or explicitly $refresh in the action.

Bulk toolbar and selection UX. v1.0.4 adds a "Deselect All" control and general selection polish. Standard workflow:

  • Bulk actions declared with a label, an optional confirmation, a handler receiving the selected keys, and now a class mapping to control the button's visual weight (e.g. destructive actions red, primary actions indigo) without overriding the toolbar Blade.
  • Prefer array<class-string|string, string> style mapping in config over inline classes so the styling stays consistent across tables.
  • After a bulk action completes, verify selection state is cleared — the new deselect control suggests selection is treated as first-class component state, so test the "select → act → next page of results" flow explicitly.

Row emphasis criteria. New in this release: conditional row styling (e.g. overdue invoices, low stock, soft-deleted records). Use it for small, per-row, already-loaded predicates:

->emphasis(fn ($row) => $row->is_overdue ? 'danger' : null)

Prefer a boolean/enum attribute on the model (or a withCount/selectRaw flag) over calling $row->relation()->exists() inside the criteria — the criteria runs once per rendered row and is the easiest place to accidentally introduce an N+1.

Integration tips.

  • Wire search input and sort state through Livewire properties (with #[Url] where useful) so table state is shareable/deep-linkable.
  • Keep perPage and filters in the query string; the toolbar's selection UX depends on stable component state between renders.
  • Test with Pest + Livewire's Livewire::test(): assert toolbar presence, call('selectAll')-style interactions, and that bulk handlers only touch authorized rows (authorize inside the handler — a bulk action bypasses per-row UI, not policy).
  • Use the package's own dev stack as a guide: it's tested against Livewire 4.x, Pest 4, Larastan 3 + PHPStan 2. Running Larastan at a comparable level on your table classes catches the closure-signature drift that's easy to introduce when overriding columns.

Gotchas and Tips

  • Silent state divergence after actions. The new automatic row sync is convenient but means a bulk delete can remove rows you had selected, and a row action can invalidate the current page (e.g. deleting the last row on page 5). Handle the empty-page case: after a bulk delete, if the current page is now empty, reset to page 1 or the last available page.
  • Selection across pages/filters. Confirm whether selection is keyed by primary key across pages or reset per query. If it persists, a "select all" then "filter" then "bulk delete" flow can act on rows the user can no longer see. The new Deselect All control mitigates this, but the guard belongs in your handler: re-resolve keys through the same scoped query the table uses, never trust a raw ID array for deletes.
  • Emphasis criteria cost. It runs per row, per render. Anything doing I/O there will hammer the DB on wide pages. Cache the predicate result on the model or precompute in the query.
  • Class mapping precedence. Button class mappings should merge into the base classes, not replace them; if a mapped class drops the base styling the button can lose its disabled/loading states. Test the class string in a Pest assertion (assertSee / assertSeeHtml) so a future release doesn't silently change merge order.
  • View overrides are the escape hatch — and the trap. Publishing views lets you fix anything, but overridden files won't receive upstream fixes (this release alone changed the bulk toolbar markup). Keep a short changelog of which published views you've modified, and diff them against the package views after each upgrade.
  • Package-version churn in dev deps. v1.0.4 was almost entirely Dependabot. That's a good sign for stability but means the package's own test matrix moves fast (Livewire 4.3.x, Pest 4.7.x). If your app pins Livewire 3, install with care and run your table tests before merging; don't assume compatibility from a patch bump.
  • Debugging empty or stale tables. Check in this order: the query is constrained by the component's mount state, the column accessor closures don't reference undefined relations (N+1/missing with()), then the config-driven defaults (perPage, toolbar visibility). Most "table is blank" reports are an eager-loading or #[Locked] state issue, not the package.
  • Extension points worth knowing: the table class itself (subclass/wrap it rather than editing vendor files), the published config for defaults and class maps, published Blade views for toolbar/row/action markup, and Livewire events for cross-component reaction to actions (listen for your own dispatched event rather than reaching into the table component).
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
shitoudev/permissionmanager
johannesclimacus/laravel-tui
hocvt/seotools
vitalybaev/sypexgeo
amphibee/themosis-ignition
gito-me/fast-excel
frankyso/laravel-ipaymu
geolize-studio/laravel-chile
boomerangui/chat
jinas/dhivatar
store-doc/laravel-storage-driver
plus-it/laravel-translation-manager
diephp/perhaps
diephp/telegraph
osmaviation/spreadsheet
microsoft/fluentui-system-icons
mmccook/php-json-canonicalization-scheme
middlewares/firewall
qubiqx/montapacking
nyoncode/laravel-package-console