Pagination
Stablepaged lists and tables
Usage example #
Copy this ERB into a Rails view after installing the component. The snippet below is the same code used by the live preview above.
app/views/.../pagination_example.html.erb
<div class="w-full">
<%= render Senren::PaginationComponent.new(current_page: 3, total_pages: 6, path: "/components?page=:page") %>
</div>
Install this component #
Copy the official component into your app
Use this when you want the Senren-maintained implementation copied into app/components/senren.
Terminal
bin/rails senren:add pagination
Create a custom component with the same conventions
Use this when you need an app-specific static component that follows Senren's ViewComponent structure.
Terminal
bin/rails generate senren:component pagination --no-client
Dependencies are resolved by senren:add:
button, link.
At a glance #
Category
Data
Class name
Senren::PaginationComponent
Stimulus
—
Variants
default
Depends on
button, link
Pairs with
table, data_table
Source #
app/components/senren/pagination_component.html.erb
<nav <%= tag.attributes(**root_attrs("flex items-center justify-center gap-1", aria: { label: label })) %>>
<% prev_page = current_page - 1 %>
<%= link_to "Previous", page_url(prev_page), class: "rounded-md border border-[hsl(var(--senren-border))] px-3 py-2 text-sm #{current_page == 1 ? "pointer-events-none opacity-50" : "hover:bg-[hsl(var(--senren-accent))]"}", aria: { disabled: current_page == 1 } %>
<% (1..total_pages).each do |page| %>
<%= link_to page, page_url(page), class: "inline-flex h-9 min-w-9 items-center justify-center rounded-md px-3 text-sm font-medium #{page == current_page ? "bg-[hsl(var(--senren-primary))] text-[hsl(var(--senren-primary-foreground))]" : "text-[hsl(var(--senren-muted-foreground))] hover:bg-[hsl(var(--senren-accent))] hover:text-[hsl(var(--senren-accent-foreground))]"}", aria: { current: (page == current_page ? "page" : nil) } %>
<% end %>
<% next_page = current_page + 1 %>
<%= link_to "Next", page_url(next_page), class: "rounded-md border border-[hsl(var(--senren-border))] px-3 py-2 text-sm #{current_page == total_pages ? "pointer-events-none opacity-50" : "hover:bg-[hsl(var(--senren-accent))]"}", aria: { disabled: current_page == total_pages } %>
</nav>
app/components/senren/pagination_component.rb
# frozen_string_literal: true
module Senren
class PaginationComponent < BaseComponent
VARIANTS = { default: '' }.freeze
SIZES = { md: '' }.freeze
def initialize(current_page: 1, total_pages: 1, path: nil, label: 'Pagination', class_name: nil, **html)
super(variant: :default, size: :md, class_name: class_name, **html)
@total_pages = [total_pages.to_i, 1].max
@current_page = current_page.to_i.clamp(1, @total_pages)
@path = path
@label = label
end
attr_reader :current_page, :total_pages, :path, :label
def page_url(page)
return '#' unless path
path.respond_to?(:call) ? path.call(page) : path.to_s.gsub(':page', page.to_s)
end
end
end
AI agent rules #
Use for
- +paged lists and tables
Avoid
- -infinite scroll feeds
Accessibility #
- aria-current=page on current; nav landmark with label.