Pagination

Pagination with page navigation, next and previous links.

No JavaScript Required

Installation

Add the component to your project:

rails generate shadcn:component pagination

Usage

There are three ways to use the Pagination component:

1. Slot-based API (Full Control)

<%= render Shadcn::PaginationComponent.new do |pagination| %>
  <% pagination.with_pagination_content do |content| %>
    <% content.with_previous(href: "/page/1") %>
    <% content.with_item(href: "/page/1") { "1" } %>
    <% content.with_item(href: "/page/2", active: true) { "2" } %>
    <% content.with_item(href: "/page/3") { "3" } %>
    <% content.with_ellipse %>
    <% content.with_item(href: "/page/10") { "10" } %>
    <% content.with_next_page(href: "/page/3") %>
  <% end %>
<% end %>

2. Collection-based API (Kaminari/will_paginate)

<%= render Shadcn::PaginationComponent.new(collection: @posts) %>

3. Pagy-based API

<%= render Shadcn::PaginationComponent.new(pagy: @pagy) %>

Examples

With Ellipsis

<% content.with_ellipse %>

Disabled Navigation

On the first or last page, disable the previous/next buttons:

<% content.with_previous(disabled: true) %>
<% content.with_next_page(disabled: true) %>

Gem Integration

The pagination component works seamlessly with popular pagination gems. Just pass your paginated collection or Pagy object directly.

Kaminari

Kaminari is the most popular pagination gem for Rails.

Controller
class PostsController < ApplicationController
  def index
    @posts = Post.page(params[:page]).per(10)
  end
end
View
<%= render Shadcn::PaginationComponent.new(
  collection: @posts,
  url_builder: ->(page) { posts_path(page: page) }
) %>

will_paginate

will_paginate is a classic pagination library.

Controller
class PostsController < ApplicationController
  def index
    @posts = Post.paginate(page: params[:page], per_page: 10)
  end
end
View
<%= render Shadcn::PaginationComponent.new(
  collection: @posts,
  url_builder: ->(page) { posts_path(page: page) }
) %>

Pagy

Pagy is the fastest pagination gem with the smallest memory footprint.

Controller
class PostsController < ApplicationController
  include Pagy::Backend

  def index
    @pagy, @posts = pagy(Post.all, items: 10)
  end
end
View
<%= render Shadcn::PaginationComponent.new(
  pagy: @pagy,
  url_builder: ->(page) { posts_path(page: page) }
) %>

Custom URL Builder

The url_builder lambda receives the page number and should return the URL for that page. This gives you full control over URL generation.

<%# With additional query params %>
<%= render Shadcn::PaginationComponent.new(
  collection: @posts,
  url_builder: ->(page) { posts_path(page: page, sort: params[:sort], filter: params[:filter]) }
) %>

<%# With URL helpers %>
<%= render Shadcn::PaginationComponent.new(
  collection: @posts,
  url_builder: ->(page) { url_for(page: page) }
) %>

<%# With namespaced routes %>
<%= render Shadcn::PaginationComponent.new(
  collection: @posts,
  url_builder: ->(page) { admin_posts_path(page: page) }
) %>

Window Size

Control how many pages are shown around the current page with the window option.

<%# Show 1 page on each side of current (default is 2) %>
<%= render Shadcn::PaginationComponent.new(
  collection: @posts,
  window: 1,
  url_builder: ->(page) { posts_path(page: page) }
) %>

<%# Show 3 pages on each side of current %>
<%= render Shadcn::PaginationComponent.new(
  collection: @posts,
  window: 3,
  url_builder: ->(page) { posts_path(page: page) }
) %>

API Reference

PaginationComponent

API Reference

Prop Type Default Description
collection Object nil Kaminari or will_paginate collection
pagy Pagy nil Pagy pagination object
url_builder Proc ->(page) { "?page=#{page}" } Lambda to generate page URLs, receives page number
window Integer 2 Number of pages to show around current page

PaginationContentComponent Slots

Slot Props Description
with_previous href:, disabled: Previous page link
with_next_page href:, disabled: Next page link
with_item href:, active: Page number link (yields page number)
with_ellipse - Ellipsis indicator for skipped pages

Accessibility

  • Uses <nav> element with role="navigation"
  • Has aria-label="pagination" for screen readers
  • Current page marked with aria-current="page"
  • Disabled links have aria-disabled="true"