Skip to main content

Overview

Laravel Livewire Tables uses Laravel’s built-in pagination system to handle large datasets efficiently. The component leverages Livewire’s WithPagination trait to provide seamless, reactive pagination.

Basic Pagination

Pagination is enabled by default. The component automatically paginates query results:
public function query(): Builder
{
    return Product::query();
}
The Engine processes the query through the pipeline and applies pagination as the final step:
$rows = $engine->process($query, $state);
// Returns Illuminate\Pagination\LengthAwarePaginator

Configuration

Default Per Page

Set the initial number of rows per page:
public function configure(): void
{
    $this->setDefaultPerPage(25);
}
Default: 10 rows per page.

Per Page Options

Customize the available choices in the per-page dropdown:
public function configure(): void
{
    $this->setDefaultPerPage(25);
    $this->setPerPageOptions([10, 25, 50, 100, 250]);
}
Default options: [10, 25, 50, 100].
The per-page dropdown only shows options you define. Ensure defaultPerPage is included in perPageOptions.

Per Page State

The component tracks the current per-page setting:
public int $perPage = 10;

Programmatic Access

Get available options:
$options = $this->getPerPageOptions();
// [10, 25, 50, 100, 250]
Update per-page programmatically:
$this->perPage = 50;

Validation

When the per-page value is updated, it’s automatically validated:
public function updatedPerPage(): void
{
    if (!in_array($this->perPage, $this->perPageOptions, true)) {
        $this->perPage = $this->defaultPerPage;
    }
    $this->resetPage();
}
Invalid values are reset to the default, and the user is returned to page 1.

Pagination View

The pagination view is determined by the active theme:
public function paginationView(): string
{
    return app(ThemeManager::class)->resolve()->paginationView();
}

Theme-Specific Views

  • Tailwind: livewire-tables::pagination.tailwind
  • Bootstrap 5: livewire-tables::pagination.bootstrap-5
  • Bootstrap 4: livewire-tables::pagination.bootstrap-4
The pagination view automatically matches your table’s theme. No additional configuration is needed.

Integration with Laravel Pagination

The component uses Laravel’s LengthAwarePaginator, which provides:
  • Total item count
  • Current page
  • Items per page
  • First/last page links
  • Previous/next links
  • Page number links
Access pagination data in views:
@if ($rows->hasPages())
    <div class="pagination-info">
        Showing {{ $rows->firstItem() }} to {{ $rows->lastItem() }} 
        of {{ $rows->total() }} results
    </div>
@endif

The Pagination Pipeline

Understanding how pagination works internally:
1

Query Building

The base query is built from query().
2

Pipeline Processing

The Engine applies search, filters, and sorting.
3

Pagination

The final step applies pagination:
$query->paginate(
    perPage: $state->perPage(),
    page: $state->page(),
);
4

Results

A LengthAwarePaginator is returned with the current page’s results.

State Management

Pagination state is managed by Livewire’s WithPagination trait:
use Livewire\WithPagination;

trait HasPagination
{
    use WithPagination;

    public function paginationView(): string
    {
        return app(ThemeManager::class)->resolve()->paginationView();
    }
}

Reset Page

The page is automatically reset to 1 when:
  • Search query changes
  • Filters are updated
  • Per-page value changes
  • Sorting changes
public function updatedSearch(): void
{
    $this->deselectAll();
    $this->resetPage(); // Reset to page 1
    $this->dispatchFiltersChanged();
}
Reset manually:
$this->resetPage();

Complete Example

app/Livewire/ProductsTable.php
<?php

namespace App\Livewire;

use App\Models\Product;
use Illuminate\Database\Eloquent\Builder;
use Livewire\Tables\Columns\TextColumn;
use Livewire\Tables\Columns\DateColumn;
use Livewire\Tables\Columns\BooleanColumn;
use Livewire\Tables\Livewire\DataTableComponent;

class ProductsTable extends DataTableComponent
{
    protected string $tableKey = 'products';

    public function configure(): void
    {
        // Set default rows per page
        $this->setDefaultPerPage(25);
        
        // Customize available options
        $this->setPerPageOptions([10, 25, 50, 100, 250]);
        
        $this->setSearchDebounce(300);
        $this->setEmptyMessage('No products found.');
    }

    public function query(): Builder
    {
        return Product::query()
            ->with(['brand', 'category']);
    }

    public function columns(): array
    {
        return [
            TextColumn::make('name')
                ->label('Product')
                ->sortable()
                ->searchable(),

            TextColumn::make('sku')
                ->label('SKU')
                ->sortable()
                ->searchable(),

            TextColumn::make('price')
                ->label('Price')
                ->sortable()
                ->format(fn($value) => '$' . number_format($value, 2)),

            TextColumn::make('stock')
                ->label('Stock')
                ->sortable(),

            BooleanColumn::make('active')
                ->label('Status')
                ->sortable(),

            DateColumn::make('created_at')
                ->label('Created')
                ->sortable()
                ->format('M d, Y'),
        ];
    }
}

Custom Pagination View

If you need to customize the pagination view, publish the views:
php artisan vendor:publish --tag=livewire-tables-views
Then modify the published views in resources/views/vendor/livewire-tables/pagination/.

Performance Considerations

For very large datasets, consider:
  • Adding database indexes on sortable/searchable columns
  • Using cursor pagination for infinite scroll (requires custom implementation)
  • Caching total counts for better performance
public function query(): Builder
{
    return Product::query()
        ->select('id', 'name', 'price', 'stock') // Only select needed columns
        ->with(['brand:id,name']); // Eager load with specific columns
}
Add compound indexes for commonly sorted columns:
Schema::table('products', function (Blueprint $table) {
    $table->index(['active', 'created_at']);
    $table->index(['category', 'price']);
});
Avoid very large per-page values:
// Good
$this->setPerPageOptions([10, 25, 50, 100]);

// Avoid
$this->setPerPageOptions([10, 50, 100, 500, 1000]);
Large page sizes can cause:
  • Slow queries
  • Memory issues
  • Poor UX (too much scrolling)

Pagination Info

Display pagination information in your view:
<div class="flex items-center justify-between px-4 py-3">
    <div class="text-sm text-gray-700">
        @if ($rows->total() > 0)
            Showing 
            <span class="font-medium">{{ $rows->firstItem() }}</span>
            to 
            <span class="font-medium">{{ $rows->lastItem() }}</span>
            of 
            <span class="font-medium">{{ $rows->total() }}</span>
            results
        @else
            No results found
        @endif
    </div>
    
    {{ $rows->links() }}
</div>

Next Steps

Tables

Learn about the DataTableComponent lifecycle

Bulk Actions

Enable bulk operations on selected rows

Build docs developers (and LLMs) love