Pagination bar

Caller-owned result context placed beside exactly one typed Pagination.

Source
app/components/nitro_kit/pagination_bar.rb
API
NitroKit::PaginationBar.new { |bar| bar.summary(...); bar.pagination(NitroKit::Pagination.new(...)) { |pagination| ... } }

Page boundaries

Caller-owned summaries pair with typed Pagination at first, middle, and final page boundaries.

First, middle, and final

First page
Middle page
Final page
ViewportFull width
Rubytest/dummy/app/components/gallery/blocks/pagination_bar_page.rb
sample("First page", slug: "first") do
  render_boundary_bar("first", current: 1, total: 12, range: "1–25", previous: nil, following: 2)
end
sample("Middle page", slug: "middle") do
  render_boundary_bar("middle", current: 6, total: 12, range: "126–150", previous: 5, following: 7)
end
sample("Final page", slug: "final") do
  render_boundary_bar("final", current: 12, total: 12, range: "276–287", previous: 11, following: nil)
end

Optional summary

The summary may be omitted; when declared it accepts caller text or direct Phlex content.

Absent and rich summary

No summary
Phlex summary
ViewportFull width
Rubytest/dummy/app/components/gallery/blocks/pagination_bar_page.rb
sample("No summary", slug: "none") do
  render NitroKit::PaginationBar.new(id: "gallery-pagination-bar-no-summary") do |bar|
    bar.pagination(NitroKit::Pagination.new(label: "Compact pages")) do |pagination|
      pagination.prev
      pagination.page(1, current: true)
      pagination.page(2, href: "?page=2")
      pagination.next(href: "?page=2")
    end
  end
end
sample("Phlex summary", slug: "phlex") do
  render NitroKit::PaginationBar.new(id: "gallery-pagination-bar-rich-summary") do |bar|
    bar.summary do
      plain("Showing 26–50 of 418 invoices ")
      render NitroKit::Badge.new(
        "Filtered",
        id: "gallery-pagination-bar-rich-summary-badge",
        size: :sm,
        variant: :outline
      )
    end
    bar.pagination(NitroKit::Pagination.new(label: "Filtered invoice pages")) do |pagination|
      pagination.prev(href: "?status=paid&page=1")
      pagination.page(2, current: true)
      pagination.next(href: "?status=paid&page=3")
    end
  end
end

Query and content pressure

Long summaries, omitted ranges, and preserved filter parameters stay outside the block's responsibilities.

Filtered directory

ViewportFull width
Rubytest/dummy/app/components/gallery/blocks/pagination_bar_page.rb
render NitroKit::PaginationBar.new(id: "gallery-pagination-bar-filtered") do |bar|
  bar.summary(
    "Showing users 201–225 of 4,892 matching “international research and production administrators” " \
      "with active security-key enrollment",
    html: { id: "gallery-pagination-bar-filtered-summary" },
    aria: { live: "polite" }
  )
  bar.pagination(NitroKit::Pagination.new(label: "Filtered workspace user pages")) do |pagination|
    pagination.prev(href: "?query=research&status=active&page=8")
    pagination.page(1, href: "?query=research&status=active&page=1")
    pagination.ellipsis(label: "Pages 2 through 7 omitted")
    pagination.page(8, href: "?query=research&status=active&page=8")
    pagination.page(9, current: true)
    pagination.page(10, href: "?query=research&status=active&page=10")
    pagination.ellipsis(label: "Pages 11 through 195 omitted")
    pagination.page(196, href: "?query=research&status=active&page=196")
    pagination.next(href: "?query=research&status=active&page=10")
  end
end

Twelve visible pages

ViewportFull width
Rubytest/dummy/app/components/gallery/blocks/pagination_bar_page.rb
render NitroKit::PaginationBar.new(id: "gallery-pagination-bar-dense") do |bar|
  bar.summary("Page 6 of 12 · 287 records")
  bar.pagination(NitroKit::Pagination.new(label: "Dense record pages")) do |pagination|
    pagination.prev(href: "?page=5")
    12.times do |index|
      page = index + 1
      pagination.page(page, href: "?page=#{page}", current: page == 6)
    end
    pagination.next(href: "?page=7")
  end
end

Collection composition

Table data, captions, counts, and links remain caller-owned around the placement block.

Invoice history

ViewportFull width
Rubytest/dummy/app/components/gallery/blocks/pagination_bar_page.rb
render NitroKit::Card.new(id: "gallery-pagination-bar-invoices-card") do |card|
  card.title("Invoice history", level: 4)
  card.body do
    render NitroKit::Table.new(id: "gallery-pagination-bar-invoices-table") do |table|
      table.caption("Recent workspace invoices")
      table.thead do
        table.tr do
          table.th("Invoice")
          table.th("Status")
          table.th("Amount", align: :right)
        end
      end
      table.tbody do
        Gallery::Data.invoices.each do |invoice|
          table.tr do
            table.th(invoice.number, scope: :row)
            table.td { render NitroKit::Badge.new(invoice.status.to_s.humanize, size: :sm) }
            table.td("$#{invoice.amount_cents / 100}.00", align: :right)
          end
        end
      end
    end
    render NitroKit::PaginationBar.new(id: "gallery-pagination-bar-invoices") do |bar|
      bar.summary("Showing the three most recent of 36 invoices")
      bar.pagination(NitroKit::Pagination.new(label: "Invoice history pages")) do |pagination|
        pagination.prev(href: "?page=11")
        pagination.page(1, href: "?page=1")
        pagination.ellipsis(label: "Pages 2 through 10 omitted")
        pagination.page(11, href: "?page=11")
        pagination.page(12, current: true)
        pagination.next
      end
    end
  end
end