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

Wire Table Laravel Package

nyoncode/wire-table

A Livewire-powered data table component for Laravel that makes it easy to render sortable, searchable, paginated tables in your apps with minimal boilerplate and a clean, customizable Blade-based API.

View on GitHub
Deep Wiki
Context7

Getting Started

Read src/ before you write a line against it. The package is a Livewire table primitive — columns, actions, bulk actions, inline editing, optimistic locking — and with zero dependents there is no integration corpus to crib from. The component class and the column/action definition objects are the API. Any README is a secondary source. Check composer.json first for the Livewire major (^2 vs ^3 is a hard break) and the PHP/Laravel minimums; a mismatch ends the evaluation immediately.

Install and pin.

composer require nyoncode/wire-table
php artisan vendor:publish --tag=wire-table-config   # confirm the real tag in src/

Pin an exact version in composer.json ("nyoncode/wire-table": "x.y.z"), not a float. If the package ships uncompiled Blade, add vendor/nyoncode/wire-table to your Tailwind content paths and build once against production config — vendor-path purge is the classic "unstyled in prod, fine in dev" failure for packages like this.

Pilot on a back-office list you don't care about. A tags, notes, or categories index is the right first target: it exercises search, sort, pagination, and one inline-editable field without touching billing or permissions. Do not pilot on your hardest table — you want to learn the API before you stress it with joins, computed columns, and row-level ACLs.

Ship read-only first. Wire up columns, searchable fields, sortable headers, and perPage. That isolates rendering and query problems from the inline-edit and action machinery, which is where the blast radius lives. Add inline editing as a second commit, bulk actions as a third.

Wrap it on day one. Even at prototype stage, keep the package out of Blade and out of your domain code:

namespace App\Tables;

abstract class BaseTable extends \NyonCode\WireTable\TableComponent
{
    // shared perPage, default sort, auth guards
}

At this adoption level you are the de facto maintainer. The wrapper is what turns a future swap to Filament or a hand-rolled component into a single-file change rather than a rewrite.

Class and method names below are illustrative — confirm each against src/ before committing production code.

Implementation Patterns

Declare the table in PHP, not Blade. A table() method or dedicated definition class keeps the contract testable and diffable:

public function table(): Table
{
    return Table::make()
        ->model(Tag::class)
        ->columns([
            Column::make('name')->searchable()->sortable()->editable(),
            Column::make('slug')->searchable(),
            Column::make('posts_count')->label('Posts')->sortable(),
            Column::make('updated_at')->format('Y-m-d H:i'),
        ])
        ->perPage(25);
}

Anything marked ->searchable() or ->sortable() must map to a real SQL column. Accessors and computed attributes are exactly where "clicking the header throws a 500" bugs originate — verify against the actual schema, not the model's $appends.

Eager-load explicitly. The package handles server-side pagination and filtering but it cannot infer your relations. Once a column renders a relation ($row->author->name), add ->with(['author', 'category']) to the base query or the equivalent modifyQueryUsing() hook. N+1 in a cell renderer degrades silently — no exception, just a table that takes four seconds on a warm cache. Run the first render with DB::listen or Debugbar open and count the queries.

Treat each write path as a separate authorization surface. Inline edit, row action, and bulk action are three distinct entry points and each is an IDOR candidate. Enforce policy checks inside the callback, not only in visibility logic:

Action::make('archive')
    ->visible(fn ($row) => auth()->user()->can('archive', $row))
    ->action(function ($row) {
        $this->authorize('archive', $row);   // visibility is a UI hint, not enforcement
        $row->archive();
    });

For bulk actions the selection arrives from the client. Re-resolve every posted ID through an authorized, tenant-scoped query before acting. Never iterate the raw array.

Design the stale-write path as UX, not just mechanism. Optimistic locking protects data only if the conflict reaches the user. Catch the conflict, re-fetch the row, and surface "this record changed since you opened it" with the differing values so the user can re-apply deliberately. A silent retry of the write defeats the entire feature and gives false confidence that you have concurrency covered.

Roll out in tiers and keep the tiers in your git history. Inline editing on tags first; orders/billing only after the conflict path has been exercised by a real human on a real record. Bulk mutations last — biggest blast radius, worst undo story.

Test at the component level. Livewire's test helpers give you table state assertions without a browser, and they are also the fastest way to discover the real method names:

Livewire::test(TagTable::class)
    ->set('search', 'laravel')
    ->assertSee('Laravel')
    ->call('sortBy', 'name')
    ->set('selected', [$tag->id])
    ->call('runBulkAction', 'archive')
    ->assertHasNoErrors();

Wrap mutation paths in your own service methods. Keep the action callback thin — authorize, delegate to a domain service, return. If the package is later replaced or forked, the domain logic never moved.

Gotchas and Tips

Verify the lock is atomic before you enable editing anywhere that matters. The single highest-consequence unknown in the package: does the version predicate live inside the UPDATE ... WHERE version = ? statement, or is it fetch-compare-write in PHP? The latter loses updates under concurrency and — worse — produces confidence you haven't earned. Read that code path first. If it's advisory, add your own conditional update or a DB-level constraint before trusting it.

Tailwind purge will bite you in production. If the package ships uncompiled markup, add the vendor path to content and safelist dynamically constructed class names (status badges, conditional row colors, severity tints). Build locally against production config once before believing it works.

wire:key on every instance. Standard Livewire discipline, but it bites harder here because table state (search, sort, page, selection) is component-scoped. Two tables on a page without distinct stable keys will leak filter state into each other.

Watch the query, not the view. Confirm sorting and filtering compile into SQL and that pagination is LIMIT/OFFSET at the database rather than a hydrated collection sliced in PHP. Test against a realistic worst case — 100k+ rows — on the first screen, before you commit to a second one.

Check for global collisions. A package that registers a Livewire alias, an Alpine plugin, or a global asset bundle can collide with Filament, Rappasoft, or your own components. If you already run Filament Tables, adopting this gives you two table paradigms in one codebase — usually a worse outcome than either choice alone.

Debugging workflow, in order: (1) DB::listen / Debugbar to see the emitted SQL and confirm your where clauses appear; (2) Livewire DevTools for the component payload and event round-trip; (3) the package's own view for that column type — most formatting surprises are a published view you can override rather than an API limitation. Publish views before editing them so future upgrades stay mergeable.

Fork or vendor on day one if you proceed past the spike. With zero adopters, the maintainer-churn scenario is real: plan for the possibility that you become the maintainer within a year. Pin the version, vendor into an internal namespace if your license policy allows, and record a one-paragraph ADR capturing why — otherwise the next developer will re-litigate the decision without the context.

Distrust the description. "Enterprise-grade" is marketing, not evidence. Judge on test coverage, CI status, a changelog, and a security disclosure process. If those are absent, treat every write path as unreviewed third-party code and budget review time proportional to how destructive the action is.

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.
3mdikram/worldmoneywords
snowsoft/config
itmosoft/laravel-subscriptions
larva/laravel-ai-qwen
diephp/sequences
users-au/socialite-provider
twidpay/twid-logger
mrnewport/laravel-plaid
mrnewport/laravel-repo
mrnewport/laravel-docsign
mrnewport/laravel-stow
mrnewport/laravel-flow
mrnewport/laravel-priceable
mrnewport/laravel-nestedterms
fredmeng/laravel-apidoc-generator
itstructure/laravel-multilingual-tools
pdustdar/elasticsearch
markupai/php-sdk
rlacerda83/lumem-microservice-shipment
uni-method/symfony-lib