v1 LiVue v1 is here — server-driven reactivity for Laravel using Vue.js Get Started →

Pagination

A full-featured pagination system that integrates Laravel's paginator with LiVue. Supports both server-rendered Blade links and fully reactive Vue-driven pagination UI.

Overview

LiVue provides the UsePagination trait to add pagination capabilities to any component. It handles page tracking, URL synchronization, navigation methods, and exposes reactive pagination metadata to the Vue template via a composable.

Blade Approach

Server-rendered pagination links with $this->links(). Zero JavaScript required.

Vue Approach

Build custom pagination UI with reactive data and navigation actions from the pagination composable.

URL Sync

Current page is automatically synced with the URL query string, so pagination state is bookmarkable and shareable.

Basic Setup

Add the UsePagination trait to your component and register usePagination in the $composables array:

app/LiVue/UserList.php
<?php

namespace App\LiVue;

use LiVue\Component;
use LiVue\Features\SupportPagination\UsePagination;

class UserList extends Component
{
    use UsePagination;

    protected array $composables = ['usePagination'];

    public function render(): string
    {
        return 'livue.user-list';
    }
}

Blade Template

Use $this->paginate() to paginate an Eloquent query and $this->links() to render the pagination links:

resources/views/livue/user-list.blade.php
<div>
    @php $users = $this->paginate(User::query(), 10) @endphp

    @foreach ($users as $user)
        <div class="p-4 border-b">
            <p>{{ $user->name }}</p>
            <p class="text-sm text-gray-500">{{ $user->email }}</p>
        </div>
    @endforeach

    <div class="mt-4">
        {{ $this->links() }}
    </div>
</div>

Tip — The paginate() method accepts any Eloquent Builder or Relation instance. If you already have a paginator from elsewhere, use $this->setPaginator($paginator) instead.

Vue Pagination

When you register usePagination as a composable, all pagination data and navigation actions become available in your Vue template under the pagination namespace. This lets you build fully custom pagination UI.

resources/views/livue/user-list.blade.php
<div>
    @php $users = $this->paginate(User::query(), 10) @endphp

    @foreach ($users as $user)
        <div class="p-4 border-b">
            <p>{{ $user->name }}</p>
        </div>
    @endforeach

    <!-- Custom Vue pagination UI -->
    <div class="flex items-center justify-between mt-4">
        <button @click="pagination.previousPage()"
                :disabled="pagination.onFirstPage">
            Previous
        </button>

        <span>
            Page {{ pagination.page }} of {{ pagination.lastPage }}
            <small>({{ pagination.total }} items)</small>
        </span>

        <button @click="pagination.nextPage()"
                :disabled="!pagination.hasMorePages">
            Next
        </button>
    </div>
</div>

Reactive Data

The following properties are available on the pagination object and update reactively after every server round-trip:

Property Type Description
pagination.page int Current page number
pagination.total int Total number of items across all pages
pagination.perPage int Number of items per page
pagination.lastPage int Last page number (total pages)
pagination.hasPages bool Whether there are multiple pages (total > perPage)
pagination.onFirstPage bool Whether the current page is the first page
pagination.hasMorePages bool Whether there are more pages after the current one

Navigation Actions

Call these methods from your Vue template to navigate between pages. Each triggers a server round-trip to fetch the new page data:

Action Description
pagination.nextPage() Go to the next page
pagination.previousPage() Go to the previous page
pagination.setPage(n) Jump to a specific page number
pagination.resetPage() Reset to page 1
pagination.firstPage() Go to the first page

Tip — You can mix both approaches: use $this->links() for standard pagination links and pagination.total in Vue to display "Showing X of Y results".

Configuration

The default pagination view is configured globally via the pagination key in config/livue.php:

config/livue.php
'pagination' => 'default',

Supported Values

Value View Description
'default' livue::pagination.tailwind Full pagination with page numbers, styled with Tailwind CSS
'simple' livue::pagination.simple Minimal Previous / Next buttons only
'your.view.path' Custom Any Laravel view path for fully custom pagination markup

Per-Component Override

Override the pagination view for a specific component by defining the paginationView() or paginationSimpleView() method:

class UserList extends Component
{
    use UsePagination;

    public function paginationView(): string
    {
        return 'components.my-pagination';
    }

    public function paginationSimpleView(): string
    {
        return 'components.my-simple-pagination';
    }
}

Note — LiVue automatically overrides Laravel's default pagination views only when rendering components that use UsePagination. After the component finishes rendering, the original Laravel defaults are restored so other parts of your application are not affected.

PHP Methods

The UsePagination trait adds the following methods to your component:

Method Returns Description
paginate($query, $perPage) LengthAwarePaginator Paginates an Eloquent query and stores the paginator internally
setPaginator($paginator) Paginator Stores an existing paginator (useful when you build queries outside the template)
links() Htmlable Renders the pagination view using the internal paginator
setPage($page) void Sets the current page number
resetPage() void Resets to page 1
nextPage() void Advances to the next page
previousPage() void Goes back to the previous page
firstPage() void Jumps to the first page
lastPage($lastPage) void Jumps to the last page (requires total pages count)

Using setPaginator()

When you build your paginator in a PHP method (e.g., mount() or a custom action) instead of in the Blade template, use setPaginator() to make it available to links() and the composable:

class ProductCatalog extends Component
{
    use UsePagination;

    protected array $composables = ['usePagination'];

    public string $category = 'all';

    public function render(): string
    {
        $query = Product::query();

        if ($this->category !== 'all') {
            $query->where('category', $this->category);
        }

        $this->setPaginator(
            $query->paginate(12)
        );

        return 'livue.product-catalog';
    }
}

URL Synchronization

The UsePagination trait automatically syncs the current page with the URL query string using the #[Url] attribute. This means:

  • The URL updates to ?page=2 as users navigate between pages
  • Page 1 uses a clean URL (no ?page=1) thanks to #[Url(except: 1)]
  • Users can bookmark or share specific pages directly
  • Browser back/forward navigation works correctly

SPA Navigation

Blade-rendered pagination links automatically include v-navigate, so clicking page numbers uses LiVue's SPA navigation instead of a full page reload. This provides instant page transitions while keeping the URL updated.

Resetting on Filter Change

When the user changes a filter (e.g., category, search query), you should reset pagination to page 1 to avoid showing an empty page:

public function updatedCategory(): void
{
    $this->resetPage();
}

Tip — The updated{Property} lifecycle hook fires whenever a public property changes. Calling resetPage() there ensures the user always sees page 1 after changing filters.