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 Datatable Laravel Package

developerawam/livewire-datatable

A powerful, flexible DataTable component for Laravel Livewire that turns your Eloquent models into interactive tables with zero configuration. Server-side rendering, search, sorting, filters, pagination, exports, and full customization.

View on GitHub
Deep Wiki
Context7

Getting Started

Install and wire up in four steps.

composer require developerawam/livewire-datatable
php artisan vendor:publish --tag="livewire-datatable-config"   # optional but do it on day one

Then make the package's Blade views visible to your CSS pipeline. This is the single step people forget, and the symptom is a fully functional table that looks like 1998:

// tailwind.config.js (Tailwind v3)
content: [
  "./resources/**/*.blade.php",
  "./vendor/developerawam/livewire-datatable/resources/views/*.blade.php",
],
/* Tailwind v4: resources/css/app.css */
@import "tailwindcss";
@source '../../vendor/developerawam/livewire-datatable/resources/views/*.blade.php';

Bootstrap 5 users skip this — the package auto-detects the framework. You can force it with DATATABLE_TEMPLATE=bootstrap|tailwind in .env.

First use case: point it at a model and walk away.

The idiomatic pattern is a thin Livewire wrapper that supplies config, and the package component nested inside its view:

// app/Livewire/UsersTable.php
public function render()
{
    return view('livewire.users-table', [
        'model'      => User::class,
        'columns'    => [
            'id'             => 'ID',
            'name'           => 'Name',
            'email'          => 'Email',
            'department.name'=> 'Department',
            'created_at'     => 'Joined',
        ],
        'searchable' => ['name', 'email'],
    ]);
}
{{-- resources/views/livewire/users-table.blade.php --}}
<div>
    <livewire:livewire-datatable
        :model="$model"
        :columns="$columns"
        :searchable="$searchable" />
</div>
<livewire:users-table />

Where to look first: config/livewire-datatable.php after publishing. Nearly every styling, pagination, and template decision lives there, and the README's per-component options all mirror config keys. Read the config file once and you've read most of the docs.

Reality check on requirements before you commit: PHP ^8.2, Laravel ^12 or ^13, Livewire ^4. That's a narrow window — if you're on Laravel 11 / Livewire 3 this package is not installable, and 64 stars with zero dependents means you are an early adopter, not a follower. Budget for reading the source when something is ambiguous.

Implementation Patterns

Formatters are the workhorse. Declare intent in config instead of writing Blade partials:

'formatters' => [
    'created_at' => 'datetime',
    'balance'    => ['type' => 'money',   'options' => ['symbol' => '$', 'decimals' => 2]],
    'is_active'  => 'boolean',
    'bio'        => ['type' => 'words',   'options' => ['words' => 12, 'end' => '…']],
    'name'       => ['type' => 'link',    'options' => [
        'route'  => 'users.show',
        'params' => ['user' => 'id'],       // assoc form when param name ≠ column name
        'class'  => 'text-blue-600 hover:underline',
    ]],
],

The link formatter also accepts a static url with {column} interpolation (/users/{id}/edit), which is the cheapest way to add row-level actions without a custom template.

Relationships: declare both sides. Add the relation to $with on the model, then use dot notation in columns, searchable, and formatters. Sorting on department.name is handled for you — but only because the package resolves the join. Keep those relation columns out of unsortable intentionally; adding unsortable there silently removes a feature users expect.

Scopes for authorization-shaped filtering, not for per-request filters. 'scope' => 'active' is great for a fixed dashboard. For anything user-driven (tenant, status dropdown, date range), keep it in the query the wrapper builds or use the package's own filter/date-range API — otherwise you end up re-rendering the component with a new scope string on every keystroke, which defeats the session persistence.

Sensible wrapper split for real apps:

  • Fixed scopes (active, tenantOwned) → scope / model global scopes.
  • Business filters (status, category) → package filter UI.
  • Date windows → package date-range filter, which auto-detects date columns.
  • Row actions / avatars / badges → custom Blade cell templates, not formatters.

Exports: treat column selection as a feature, not a checkbox. The custom export path lets the user pick columns, and link-formatted columns deliberately export their raw value (no URL). Design the export column list to match what finance/ops actually paste into a spreadsheet — that usually means raw dates and unformatted numbers, which the formatter-aware export already gives you.

Theme once, override rarely. Set CSS classes, dark mode, and per-page options globally in config; use per-component overrides only for genuinely different tables (e.g. a compact audit log vs. a spacious customer list). Mixed inline class strings across components is how these codebases rot.

Gotchas and Tips

Schema cache will bite you after migrations. Introspection is cached (DATATABLE_SCHEMA_CACHE_TTL, default 3600s). Add a column, and your table silently doesn't show it for an hour. Wire cache clearing into your deploy/migration flow — the README points at livewire-datatable:schema:* and DataTable::clearSchemaCache(). In local dev, set DATATABLE_SCHEMA_CACHE_TTL=0 and stop thinking about it.

Session-persisted search surprises people. Global search and advanced filters persist per table in the Laravel session (DATATABLE_SESSION). This is usually desirable, but in tests and demos it produces "why is this table pre-filtered?" moments. Know the toggle: false disables persistence and the filter panel close resets state.

Unstyled table = the Tailwind content glob. Almost always the @source / content entry missing, or a cached CSS build. Check that before assuming the template resolution is broken.

Searchable columns must be declared explicitly. The columns array drives display; searchable drives the WHERE … LIKE clauses. A column visible but not searchable is a support ticket waiting to happen. Same for relation columns — search on department.name only works if it's listed.

Export is your first memory risk. Server-side pagination protects the browse experience but not the export path — a 100k-row Excel export is a different beast. Cap it, queue it, or scope it. Also verify which spreadsheet/PDF driver the package expects in composer.json (maatwebsite/excel, a PDF renderer) since the README documents options but doesn't enumerate driver dependencies — don't promise a PDF export in a sprint before running one locally.

Livewire 4 + nested components: watch the render budget. The wrapper → package component nesting is clean, but it means two component lifecycles per table. If you have a dashboard with five tables, prefer separate pages or lazy-load, and pass only scalars/class-strings between them (as the README does) rather than collections.

no column numbering is pagination-aware — good, but it means you shouldn't hand-roll a row index; you'll get off-by-page-number bugs. Use the built-in.

Extension points, in order of safety: formatters → custom cell templates (Blade components) → published views → forking. Everything above "custom templates" is a maintenance liability against a 64-star package with no dependents. If you find yourself patching vendor files, that's the signal to write your own table.

Debugging checklist when a table misbehaves:

  1. php artisan view:clear && npm run build — stale views/CSS cause most "broken" reports.
  2. ->toSql() / DB::listen on the underlying query — confirm the relation join and search clauses look sane.
  3. Check unsortable — a sort click that does nothing is usually a column you excluded.
  4. Clear the schema cache if columns/vanish appear after a migration.
  5. Drop DATATABLE_SCHEMA_CACHE_TTL=0 and DATATABLE_SESSION=false to isolate persistence bugs.

Index for the queries you're enabling. Sorting and searching on email, created_at, and relation foreign keys without indexes turns "handles thousands of records efficiently" into a 3-second page load at 50k rows. The package optimizes the transport, not your schema.

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.
andydefer/laravel-notification
adachsoft/cli-process-tester
jhaskell13/laraflow
sebastienheyd/boilerplate-media-manager
ccast/tagixo-primix
pretendtrue/laravel-builder
sawmainek/laravel-scout-tntsearch-driver
tomshaw/laravel-calendar-table
dibakar/laravel-ownership
steadrun/laravel-monitor
labyrinthe/connect-laravel
elmogy/layan
drewdan/sentinel-client
dskripchenko/laravel-llm
fatryst/nuonuo
stevenay/myanfont
gmostafa/php-graphql-client
xeviant/paystack
snowsoft/faker
meditationsteps/blogetc