In this post I will try to explain the setup where you can configure shadcn-vue pagination component.
First lets publish shadcn-vue pagination component
npx shadcn-vue@latest add pagination
Next, lets setup controller to render inertia component PostController.php
<?php
namespace App\Http\Controllers;
use App\Http\Resources\PostResource;
use App\Models\Post;
class PostController extends Controller
{
/**
* Display a listing of the resource.
*/
public function index()
{
return inertia('Posts/Index', ['posts' => PostResource::collection(Post::query()->paginate(10))]);
}
}
My Post Resource looks like this but you can omit post resource altogether if you prefer
<?php
namespace App\Http\Resources;
use Illuminate\Http\Request;
use Illuminate\Http\Resources\Json\JsonResource;
class PostResource extends JsonResource
{
/**
* Transform the resource into an array.
*
* @return array<string, mixed>
*/
public function toArray(Request $request): array
{
return [
'id' => $this->id,
'user' => $this->whenLoaded('user', function () {
UserResource::make($this->user);
}),
'title' => $this->title,
'body' => $this->body,
'created_at' => $this->created_at,
'updated_at' => $this->updated_at,
];
}
}
I am using type script so here is the type definition of Laravel pagination response (you can omit this if you are not using typescript)
export interface PaginationMeta {
current_page: number
last_page: number
per_page: number
total: number
links: T[]
}
export interface PaginationLinks {
first: string | null
last: string | null
prev: string | null
next: string | null
}
export interface LaravelPaginator<T> {
data: T[]
meta: PaginationMeta
links: PaginationLinks
}
interface Post {
id: number
user: User
title: string
body: string
created_at: string;
updated_at: string;
}
Finally Post/Index.vue file where we glue together everything and create the pagination for out posts
<script setup lang="ts">
import {
Pagination,
PaginationContent,
PaginationItem,
} from '@/components/ui/pagination';
import AppLayout from '@/layouts/AppLayout.vue';
import { dashboard } from '@/routes';
import { LaravelPaginator, Post, type BreadcrumbItem } from '@/types';
import { Head, Link } from '@inertiajs/vue3';
const breadcrumbs: BreadcrumbItem[] = [
{
title: 'Posts',
href: dashboard().url,
},
];
defineProps<{
posts: LaravelPaginator<Post>;
}>();
</script>
<template>
<Head title="Posts" />
<AppLayout :breadcrumbs="breadcrumbs">
<div
class="flex h-full flex-1 flex-col gap-4 overflow-x-auto rounded-xl p-4"
>
<ul class="divide-y">
<li class="px-2 py-4" v-for="post in posts.data" :key="post.id">
#({{ post.id }})
<span class="text-lg font-bold">{{ post.title }}</span>
</li>
</ul>
<div class="flex flex-col gap-6">
<Pagination
:total="posts.meta.total"
:items-per-page="posts.meta.per_page"
:default-page="posts.meta.current_page"
:page="posts.meta.current_page"
>
<PaginationContent>
<template
v-for="(link, index) in posts.meta.links"
:key="index"
>
<PaginationItem :value="link.page" v-if="link.url">
<!-- Use Inertia's Link component for seamless navigation -->
<Link
:href="link.url"
:is-active="link.active"
preserve-scroll
>
<span v-html="link.label"></span>
</Link>
</PaginationItem>
</template>
</PaginationContent>
</Pagination>
</div>
</div>
</AppLayout>
</template>
