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>