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

Datatable Laravel Package

steelants/datatable

A Laravel package for building dynamic data tables with server-side processing, column configuration, and search support.

View on GitHub
Deep Wiki
Context7

Getting Started

The package is small enough to read end-to-end before you write a line of code, and you should — with 2 stars and no dependents there is no blog-post ecosystem to fall back on, so src/ and resources/views/ are the documentation.

  1. composer require steelants/datatable
  2. Check for a service provider auto-discovery entry and any publishable config/views: php artisan vendor:publish --provider="Steelants\...\DataTableServiceProvider" (run php artisan vendor:publish with no args and look for the package's tag — it will list the available tags even if you don't publish).
  3. Open three files first, in this order:
    • the main DataTable class or trait in src/ — this defines every method you'll call,
    • the package Blade view — this tells you how columns, search, and pagination are actually rendered,
    • composer.json — check the laravel/framework and livewire/livewire constraints, because a Livewire 2/3 mismatch will be your first real error.

First use case: a paginated, sortable, searchable index of one Eloquent model, wired into an existing page. Create a dedicated Livewire component (don't try to bolt the datatable onto an existing form component), point it at the model's query, declare columns, and render the table in its view. That single vertical slice will expose whether the package's search/sort/pagination assumptions match your app's conventions.

Implementation Patterns

One Livewire component per table. Treat the datatable component as a thin shell: mount() builds the query, the component's public properties hold search/sort/page state, and the Blade view renders the package's table markup. If you find yourself sharing a component across two resources, you almost certainly want two components instead — the query construction is the only thing that differs, and over-generalizing here is where these packages get painful.

Column definitions live in PHP, rendering lives in Blade. Define the column list (key, label, sortable flag) in the component, then use the package's cell rendering hook for anything non-trivial — badges, formatted dates, links, relation names. Keep raw Eloquent attribute output as the default path and only reach for a custom renderer when you need it.

Eager-load aggressively in mount(). Any column that touches a relation ($row->customer->name) must be backed by ->with('customer') on the base query. This is the single biggest performance lever and the package will not warn you about it.

Sorting and searching map to the query builder. The typical shape is a base Builder stored on the component, then the package applies orderBy/where ... like/paginate based on public properties. Validate the sort column against your whitelist before it hits orderBy — see Gotchas.

Actions column as the last column. Row-level edit/delete buttons belong in a dedicated non-sortable column, using wire:click with the record ID and wire:key on the row. Keep the confirm-and-delete logic in the component, not in the view.

Integration with existing pages: mount the component from a Blade page via <livewire:admin.users-table /> rather than trying to embed it in a controller-rendered view. If you need the table state in the URL, push search/sort/page onto the query string via Livewire's #[Url] (v3) or $queryString (v2) on the component's own properties.

Bulk actions and export: if the package supports row selection, wire the selected IDs into a component property and do the work in a component method with a $this->dispatch('...') refresh afterwards. If it doesn't, add selection yourself — it's a checkbox column plus an array property, and it's usually less work than fighting the package.

Gotchas and Tips

  • Sort column injection. If the package takes the sort key straight from the request into orderBy, an attacker controls an identifier position. Always interpose a whitelist: abort_unless(in_array($sort, $allowedColumns), 422). Same for any filter/search parameter that touches column names.
  • Livewire 2 vs 3. The package's Livewire constraint is the compatibility contract. Emit/listen syntax ($emit vs dispatch), query-string attributes, and pagination view names all differ. Pin the package version in composer.json and read the constraint before upgrading Livewire.
  • Pagination resets. When the search term or a filter changes, reset to page 1 explicitly ($this->resetPage() in v3 / resetPage() for the WithPagination trait). Otherwise a user on page 7 searching for something with two results sees an empty table and files a bug.
  • wire:key on rows. Without a stable key on each <tr>, Livewire reuses DOM nodes on delete/sort and you get stale checkboxes and mismatched action buttons.
  • N+1 detection. Run the page with DB::listen or Laravel Debugbar once. If the query count scales with page size, you're missing with() — the datatable makes this easy to miss because the page still works, just slowly.
  • Large datasets. paginate() on a table with LIKE '%term%' search will table-scan. If rows exceed a few hundred thousand, switch the search to a whereFullText or swap the base query for a Scout-backed source rather than tuning the package.
  • Debugging. The package's whole state is public properties on your component — dump($this->all()) in the render method tells you what the table thinks the search/sort/page state is, which resolves most "the table won't update" reports faster than reading package source.
  • Extension points. If the Blade view is publishable, publish it and own a copy — with 2 stars and no dependents, upstream fixes are unlikely, and a local view override is the cheapest way to add responsive classes or a custom empty state. For anything deeper, the DataTable class is small enough to fork into app/Support/ and maintain yourself; treat the package as a starting point rather than a dependency of record.
  • No dependents means no Stack Overflow answers. Budget an hour to read the source on day one. The payoff is that every bug you hit after that is a bug you already know the location of.
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.
elsayed85/laravel-api-exceptions
ouhssini/laravel-demo-mode
daworks/ncloud-outbound-mailer-driver
gp247/cms
ignibyte/aic-gates
nexa-merchant/blog
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