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

Livewire Tables Laravel Package

timolake/livewire-tables

A Laravel Livewire package for building dynamic, interactive data tables with sorting, searching, pagination, and customizable columns and filters. Drop tables straight into your Livewire components with minimal setup and no extra JavaScript.

View on GitHub
Deep Wiki
Context7

Getting Started

What you're getting: a Livewire 3 trait/component pair that turns an Eloquent query into a table with optional pagination, search, and sort. All state lives server-side; the browser just renders Livewire-rendered HTML. There is no JS surface to learn.

Minimal setup (~10 minutes):

  1. Pin and install. Do not float a caret on a 0-star, NOASSERTION-licensed fork whose composer constraints have historically been loose (release 2.4.3 exists solely to add the Laravel requirement). Pin explicitly:

    composer require "timolake/livewire-tables:^2.8"
    

    Pick the 2.x line. The 1.18.x line and 2.8.x line ship parallel fixes (e.g. session-key fixes in both 1.18.1 and 2.8.1), so choose one and document why. 2.6.0 onwards has the refactored pagination where total count is optional — that is the ergonomic win you want.

  2. Confirm Livewire 3.x is wired up. @livewireStyles / @livewireScripts (or the Vite equivalents) must be in your layout. The package is a thin layer on Livewire, not a renderer — if Livewire is broken, this is broken in the same way.

  3. Read vendor/timolake/livewire-tables/src/ before writing a table. There is no meaningful external documentation for this fork. Treat the base table class and PaginationTrait (added in 1.18.3) as the reference. You will write better tables in 20 minutes of source reading than an hour of guessing.

  4. Publish views/config only when you have a concrete override need. php artisan vendor:publish --tag=livewire-tables freezes an unmaintained snapshot into your repo. Skip it on day one.

First use case — read-only users list. Create a UsersTable component that extends the package's base table, point it at User::query(), declare the columns you want visible/searchable/sortable, and mount it from users/index.blade.php with <livewire:users-table />.

Verify before you scale to a second table: pagination renders, sort toggles on a numeric and a string column, search hits a BelongsToMany relation (added in 2.3.0), and the page survives a back-button press without losing state.

Implementation Patterns

One table class per model screen, mounted from Blade. This is the pattern the package is designed around. Keep the component thin — query construction, column definitions, and formatting — and let the Blade view be a single component tag. Resist the urge to build "one generic table component with a $model prop"; you'll fight Livewire's type-hinted props and lose the type safety that makes column definitions useful.

Session state is the operational contract, not a feature. Since 2.4.0, search, sort, pagination, and the trashed flag persist in the session under a session key. That means: a user refreshes, opens a second tab, or comes back tomorrow and the table remembers. Design for this. Two non-negotiables:

  • Expose a visible "Reset filters" control in every table. Without it, "row X is missing" tickets become your Monday.
  • Namespace the session key per table when two tables can appear on the same page. 2.8.1 fixes a session-key collision; verify your installed version includes it, or two tables on a dashboard will fight over sort state.

Wrapper base class as your exit seam. Do not extend Timolake\* directly in every component. Introduce one App\Support\Tables\BaseTable that extends the package base, and have every screen extend that. This is the single most valuable pattern with this package — it converts "we adopted a package" into "we adopted a convention," and it's how you swap or fork later without touching twenty components.

Formatting belongs in the table class, not Blade. Use the column formatting callbacks for status badges, currency, dates, and action links. Keep the row view dumb. This is what makes the table reusable across an admin index and an embedded dashboard widget.

Search semantics need one decision applied everywhere. The package translates search into Eloquent queries, so LIKE behaviour depends on your DSN — PostgreSQL ILIKE vs MySQL collation vs SQLite. Decide case-sensitivity once, test it once per environment, and then don't think about it again. BelongsToMany search works (2.3.0) but HasManyThrough and nested relations are not free — if a column is "searchable" in the UI it should map to a real indexed column or a join you have an index for.

Pagination: use paginate($pageSize) for normal tables; opt out of total count (2.6.0+) on large tables where the COUNT(*) is the expensive query. Trade-off: users lose "page 47 of 312" but the page loads faster. For internal tools, the count is usually worth it; for anything approaching six figures, drop it.

Integration with permissions: don't try to make the package aware of policies. Scope the query in the table class's query builder (User::query()->where(...) or a policy-scoped visibleTo($user) scope) and let the package only handle display. Row-level scoping stays where Livewire developers already expect it.

Testing pattern: Livewire's Livewire::test(UsersTable::class)->set('search', 'alice')->assertSee('alice') works and is the fastest way to catch regressions in sort/search/state. Write at least one test that sets state, refreshes the component (->call('$refresh')), and asserts state survives — because that's the code path the package has shipped the most bugfixes against (1.18.1, 1.18.4, 2.8.1).

Gotchas and Tips

License is the first gotcha, not a technical one. NOASSERTION means there is no declared license. Before this ships in a commercial product, get legal clearance, and check the terms of the two packages this derives from (danielbinsmaier/livewire-tables, coryrose/livewire-tables). If you cannot clear it, stop here — everything below is moot.

Session state is your #1 support ticket generator. Users will report "the table is empty" or "sorting is wrong" and the cause will be session-persisted state from a prior visit or another tab. Mitigations: a visible reset button, a URL-parameter mirror for bookmarkable state (override the mount method to read ?search= and write back), and a one-page runbook for tier-1 support. Do this before the first non-internal user touches the table.

trashed is sticky. If you enable soft-delete filtering, the trashed flag persists alongside search/sort. Users will "lose" rows hours later. Consider defaulting it off explicitly per render and requiring an intentional toggle to retain it.

Pin the minor version, and lock the composer constraint yourself. 2.4.3 is an entire release for "add laravel requirement to composer.json." That is a signal, not a quirk. In your own composer.json, use a narrow constraint and commit composer.lock. Do not trust the package's declared bounds to protect you on a future Laravel or Livewire minor.

Livewire version lock is real. 2.x targets Livewire 3. If you're on Livewire 2 / Laravel 9, this is the 1.18.x line and you are now maintaining a fork of an already-abandoned package for an older stack. That's a bad place to be — do not adopt on Livewire 2.

Performance cliff is indexing, not the package. Search and sort are Eloquent operations. Below ~50K rows with proper indexes, you're fine. Watch SELECT COUNT(*) on paginated queries (use the 2.6.0 optional-count if the count dominates), keep an eye on Livewire's serialized payload when you have many columns, and treat 100K rows as a re-platform trigger rather than a tuning exercise.

Theming will look like default Livewire unless you invest. There's no theming API; you style via Tailwind classes on the published Blade views or by wrapping the component. Budget a design pass if internal tools have a brand system. Do not publish the views "just in case" — publish them when you have a specific override, because a published snapshot from an abandoned repo is dead code you will eventually have to diff against nothing.

Extension points that actually matter: (a) the base table class's column definition array — this is where formatting, searchability, sortability, and visibility live, and it's the cleanest extension point; (b) overriding the query builder method for row-level scoping and joins; (c) overriding the session-key method to namespace per component. Everything else — traits, blade, pagination — is either already wired by PaginationTrait or better handled in your wrapper base class.

Debugging "why isn't my column sorting?" In order: (1) is the column declared sortable and backed by a real DB column or select alias? (2) is the sort state polluted by a previous session value — clear the session key and retry; (3) is the query using select() with a subquery alias but no ->orderByRaw mapping? Sort on aliases is a common source of silent no-ops. Add a dd($this->query->toSql()) at the relevant point and read the actual SQL.

Fork-and-vendor should be your default posture, not your contingency. At 0 stars and 0 dependents, upstream fixes are best-effort. Vendor a fork into a private Composer path repo (or commit it under packages/) before your first merge to main. This is the difference between "we had a package problem" and "we had a bad week."

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.
novasa/laravel-language-center
opencage/geocode
adolfoholzer/parameters
livenetworks/ln-starter
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
cgv/localized-resource
noith/settings
kda/laravel-package
kda/filament-dynamic-navigation
bypersoft/signbox
pairus/product-data
fayne/laravel-filament-cms-core