Pagination

Accessible page navigation with explicit boundaries, current state, and ellipses.

Source
app/components/nitro_kit/pagination.rb
API
NitroKit::Pagination.new(label:) { |pagination| pagination.page; pagination.ellipsis }

Boundary states

First, middle, and last pages expose one current item and disabled outer boundaries.

First, middle, last

Viewport640 px · sm
Rubytest/dummy/app/components/gallery/components/pagination_page.rb
Gallery::Data.pagination_boundaries.each do |pagination|
  sample(pagination.label, slug: pagination.slug) do
    render_boundary(pagination)
  end
end

Ranges and ellipses

Compact and long ranges use non-interactive, accessibly labelled ellipses.

Compact range

Viewport640 px · sm
Rubytest/dummy/app/components/gallery/components/pagination_page.rb
render NitroKit::Pagination.new(
  id: "gallery-pagination-compact",
  label: "Compact result pages"
) do |pagination|
  pagination.prev(href: "/gallery/results?page=1", id: "gallery-pagination-compact-previous")
  pagination.page(1, href: "/gallery/results?page=1", id: "gallery-pagination-compact-page-1")
  pagination.page(2, current: true, id: "gallery-pagination-compact-page-2")
  pagination.page(3, href: "/gallery/results?page=3", id: "gallery-pagination-compact-page-3")
  pagination.next(href: "/gallery/results?page=3", id: "gallery-pagination-compact-next")
end

Long range

ViewportFull width
Rubytest/dummy/app/components/gallery/components/pagination_page.rb
render NitroKit::Pagination.new(
  id: "gallery-pagination-long",
  label: "Long audit log pages"
) do |pagination|
  pagination.prev(href: "/gallery/audit?page=6", id: "gallery-pagination-long-previous")
  pagination.page(1, href: "/gallery/audit?page=1", id: "gallery-pagination-long-page-1")
  pagination.ellipsis(label: "Pages 2 through 5 omitted")
  pagination.page(6, href: "/gallery/audit?page=6", id: "gallery-pagination-long-page-6")
  pagination.page(7, current: true, id: "gallery-pagination-long-page-7")
  pagination.page(8, href: "/gallery/audit?page=8", id: "gallery-pagination-long-page-8")
  pagination.ellipsis(label: "Pages 9 through 23 omitted")
  pagination.page(24, href: "/gallery/audit?page=24", id: "gallery-pagination-long-page-24")
  pagination.next(href: "/gallery/audit?page=8", id: "gallery-pagination-long-next")
end

Labels and pressure

Long navigation copy, block page labels, icon-only boundaries, and wide ranges remain semantic.

Long labels

ViewportFull width
Rubytest/dummy/app/components/gallery/components/pagination_page.rb
render NitroKit::Pagination.new(
  id: "gallery-pagination-labels",
  label: "Archived audit record pages"
) do |pagination|
  pagination.prev(
    "Go back to the previous collection of archived audit records",
    href: "/gallery/archive?page=4",
    icon: nil,
    id: "gallery-pagination-labels-previous"
  )
  pagination.page(href: "/gallery/archive?page=5", id: "gallery-pagination-labels-page") do
    "A custom page label"
  end
  pagination.next(
    "Continue through the archived audit record collection",
    href: "/gallery/archive?page=6",
    icon: nil,
    id: "gallery-pagination-labels-next"
  )
end

Horizontal pressure

ViewportFull width
Rubytest/dummy/app/components/gallery/components/pagination_page.rb
render NitroKit::Pagination.new(
  id: "gallery-pagination-pressure",
  label: "Twelve visible pages"
) do |pagination|
  pagination.prev(href: "/gallery/pressure?page=5", id: "gallery-pagination-pressure-previous")
  (1..12).each do |page|
    pagination.page(
      page,
      href: "/gallery/pressure?page=#{page}",
      current: page == 6,
      id: "gallery-pagination-pressure-page-#{page}"
    )
  end
  pagination.next(href: "/gallery/pressure?page=7", id: "gallery-pagination-pressure-next")
end

Paginated results

Field, Input, Table, Badge, Button, and Pagination compose into searchable member results.