Pagination components for list views in PhoenixKit.
Provides pagination controls and information display following daisyUI design patterns.
Two flavours:
Page-numbered (
<.pagination>,<.pagination_controls>,<.pagination_info>) — URL-param driven, suits standalone admin pages with deep-linkable state.<.page_size_selector>sits next to either and lets the viewer pick the rows per page.Load-more (
<.load_more>) — click-driven LV event that grows the loaded set in place. Suits embeddable LVs (no URL routing), lists with DnD reorder (rows append, don't replace), and lists with client-side bulk-select (selection persists across loads because rows stay in the DOM).
Summary
Functions
Load-more footer for incrementally-loaded lists.
Rows-per-page selector, a sibling of <.pagination>.
Renders complete pagination controls with automatic URL building.
Displays pagination controls with page numbers and navigation buttons.
Displays pagination information showing result range.
Functions
Load-more footer for incrementally-loaded lists.
Renders a centered "Showing N of M %{noun}" line and a "Load more"
button (hidden when loaded >= total). Clicking the button emits
the LV event named in on_load_more.
Suited for embeddable LVs where URL-param pagination isn't an option, lists with DnD reorder (rows append rather than navigate away), and lists with client-side bulk-select (selection persists because the DOM grows, it doesn't get replaced).
Attributes
loaded— number of rows currently rendered (required)total— total rows matching the current filter/sort (required)on_load_more— LV event name pushed on button click (default"load_more")noun_plural— used in the "Showing N of M %{noun}" line (default"items")class— additional classes on the outer wrapperinfinite— whentrue, the footer also auto-loads on scroll via theInfiniteScrollhook (the manual button stays as a fallback). Requiresid. (defaultfalse)id— DOM id, required wheninfinite(the JS hook needs it)cursor— an opaque per-page marker (e.g."items-<offset>") that changes on each load. TheInfiniteScrollhook re-fires only when it changes, so it both keeps firing while still on screen and ignores unrelated diffs. Only used wheninfinite. Defaults to@loaded(which already changes per page), so most callers can omit it; pass an explicit value only when@loadedis not a faithful page marker.
Example
<.load_more
loaded={length(@projects)}
total={@total_count}
on_load_more="load_more"
noun_plural={gettext("projects")}
/>
<%!-- Auto-load on scroll + manual fallback --%>
<.load_more
id="items-load-more"
loaded={length(@items)}
total={@total}
infinite
cursor={"items-#{@offset}"}
/>Attributes
loaded(:integer) (required)total(:integer) (required)on_load_more(:string) - Defaults to"load_more".noun_plural(:string) - Defaults to"items".class(:string) - Defaults to"".id(:string) - Defaults tonil.infinite(:boolean) - Defaults tofalse.cursor(:string) - Defaults to"".- Global attributes are accepted. Forwarded to the button, so a page with more than one load-more list can
tell its handler which one was clicked (
phx-value-*). Without this a caller has to mint a separate event name per list.
Rows-per-page selector, a sibling of <.pagination>.
A daisyUI <select> wrapped in its own <form phx-change>, so a change
reaches the LiveView as %{"per_page" => "25"} under the event named in
on_change. The LiveView is expected to push the value into the URL and
reset the page to 1 — with PhoenixKitWeb.Live.UrlState that is one
push_url_state(socket, per_page: n), which does both.
Attributes
value— the current page size (required)options— selectable sizes (default[10, 25, 50, 100]). Avalueoutside the list is appended so the select never shows a blank.on_change— LV event name (default"change_per_page")class— additional classes on the wrapperid— DOM id of the<select>; the wrapping form getsid <> "-form"(default"pk-page-size-" <> on_change— pass one when a page renders two selectors with the same event)auto_fit— adds an "Auto" option backed by thePageSizeAutoFitJS hook, which measures how many rows oftable_idfit the viewport and pusheson_changewith%{"per_page" => n, "auto" => "1"},nbeing the largest option that fits (defaultfalse)auto— whether Auto is currently selected (defaultfalse)table_id— DOM id of the table the hook measures; required whenauto_fit
Example
<.page_size_selector value={@per_page} />
<%!-- Auto-fit pilot --%>
<.page_size_selector
id="users-per-page"
value={@per_page}
auto_fit
auto={@auto_fit}
table_id="users-table"
/>Attributes
value(:integer) (required)options(:list) - Defaults to[10, 25, 50, 100].on_change(:string) - Defaults to"change_per_page".class(:string) - Defaults to"".id(:string) - Defaults tonil.auto_fit(:boolean) - Defaults tofalse.auto(:boolean) - Defaults tofalse.table_id(:string) - Defaults tonil.
Renders complete pagination controls with automatic URL building.
Simpler alternative to pagination_controls that handles URL building internally. Preserves all query parameters while changing page number.
Attributes
current_page- Current active page number (required)total_pages- Total number of pages available (required)base_path- Base URL path without query params (required)params- Map of query parameters to preserve (default: %{})
Examples
<.pagination
current_page={@page}
total_pages={@total_pages}
base_path="/admin/emails"
params={%{"search" => @filters.search, "status" => @filters.status}}
/>
<%!-- Minimal usage --%>
<.pagination
current_page={1}
total_pages={10}
base_path="/admin/logs"
/>Attributes
current_page(:integer) (required)total_pages(:integer) (required)base_path(:string) (required)params(:map) - Defaults to%{}.
Displays pagination controls with page numbers and navigation buttons.
Attributes
page- Current page number (required)total_pages- Total number of pages (required)build_url- Function that takes page number and returns URL (required)class- Additional CSS classes
Examples
<.pagination_controls
page={@page}
total_pages={@total_pages}
build_url={&build_page_url(&1, assigns)}
/>Attributes
page(:integer) (required)total_pages(:integer) (required)build_url(:any) (required)class(:string) - Defaults to"".
Displays pagination information showing result range.
Attributes
page- Current page number (required)per_page- Items per page (required)total_count- Total number of items (required)class- Additional CSS classes
Examples
<.pagination_info
page={@page}
per_page={@per_page}
total_count={@total_count}
/>
# Renders: "Showing 1 to 25 of 100 results"
# Single-page result drops the redundant " of N" — e.g. with
# total_count=4 and per_page=25: "Showing 1 to 4 results".Every string is translated. noun_plural names what is being counted
(default gettext("results")); pass an already-translated word so the
line reads "… of 40 sessions" in the viewer's language:
<.pagination_info
page={@page}
per_page={@per_page}
total_count={@total_count}
noun_plural={gettext("sessions")}
/>Attributes
page(:integer) (required)per_page(:integer) (required)total_count(:integer) (required)noun_plural(:string) - Defaults tonil.class(:string) - Defaults to"".