Current section
Files
Jump to
Current section
Files
priv/templates/components/pagination.ex.eex
defmodule <%= @module_name %>.Components.UI.Pagination do
@moduledoc """
Pagination navigation component.
Ejected from PhiaUI — you own this copy. Customise freely.
## Example
<.pagination>
<.pagination_content>
<.pagination_item>
<.pagination_previous current_page={@page} total_pages={@total} on_change="go" />
</.pagination_item>
<%= for p <- 1..@total do %>
<.pagination_item>
<.pagination_link page={p} current_page={@page} on_change="go">
<%= p %>
</.pagination_link>
</.pagination_item>
<% end %>
<.pagination_item>
<.pagination_next current_page={@page} total_pages={@total} on_change="go" />
</.pagination_item>
</.pagination_content>
</.pagination>
In your LiveView:
def handle_event("go", %{"page" => page}, socket) do
{:noreply, assign(socket, page: String.to_integer(page))}
end
"""
use Phoenix.Component
import <%= @module_name %>.ClassMerger, only: [cn: 1]
import <%= @module_name %>.Components.UI.Icon, only: [icon: 1]
attr :class, :string, default: nil, doc: "Additional CSS classes"
attr :rest, :global
slot :inner_block, required: true
def pagination(assigns) do
~H"""
<nav aria-label="pagination" role="navigation" class={cn(["mx-auto flex w-full justify-center", @class])} {@rest}>
<%%= render_slot(@inner_block) %>
</nav>
"""
end
attr :class, :string, default: nil
attr :rest, :global
slot :inner_block, required: true
def pagination_content(assigns) do
~H"""
<ul class={cn(["flex flex-row items-center gap-1", @class])} {@rest}>
<%%= render_slot(@inner_block) %>
</ul>
"""
end
attr :class, :string, default: nil
attr :rest, :global
slot :inner_block, required: true
def pagination_item(assigns) do
~H"""
<li class={cn([@class])} {@rest}>
<%%= render_slot(@inner_block) %>
</li>
"""
end
attr :page, :integer, required: true, doc: "The page number this link represents"
attr :current_page, :integer, required: true, doc: "The currently active page"
attr :on_change, :string, default: "page-changed", doc: "phx-click event name"
attr :class, :string, default: nil
attr :rest, :global
slot :inner_block, required: true
def pagination_link(assigns) do
~H"""
<button
phx-click={@on_change}
phx-value-page={@page}
aria-current={if @page == @current_page, do: "page", else: nil}
class={cn([
"inline-flex h-9 w-9 items-center justify-center rounded-md border text-sm transition-colors",
"hover:bg-accent hover:text-accent-foreground",
if(@page == @current_page,
do: "bg-primary text-primary-foreground border-primary hover:bg-primary/90",
else: "border-transparent bg-transparent"
),
@class
])}
{@rest}
>
<%%= render_slot(@inner_block) %>
</button>
"""
end
attr :current_page, :integer, required: true
attr :total_pages, :integer, required: true
attr :on_change, :string, default: "page-changed"
attr :class, :string, default: nil
attr :rest, :global
def pagination_previous(assigns) do
~H"""
<button
phx-click={if @current_page > 1, do: @on_change}
phx-value-page={@current_page - 1}
aria-label="Go to previous page"
disabled={@current_page == 1}
class={cn([
"inline-flex h-9 items-center justify-center gap-1 rounded-md border border-transparent px-3 text-sm transition-colors",
"hover:bg-accent hover:text-accent-foreground",
if(@current_page == 1, do: "pointer-events-none opacity-50", else: nil),
@class
])}
{@rest}
>
<.icon name="chevron-left" size={:sm} />
<span class="sr-only">Previous</span>
</button>
"""
end
attr :current_page, :integer, required: true
attr :total_pages, :integer, required: true
attr :on_change, :string, default: "page-changed"
attr :class, :string, default: nil
attr :rest, :global
def pagination_next(assigns) do
~H"""
<button
phx-click={if @current_page < @total_pages, do: @on_change}
phx-value-page={@current_page + 1}
aria-label="Go to next page"
disabled={@current_page == @total_pages}
class={cn([
"inline-flex h-9 items-center justify-center gap-1 rounded-md border border-transparent px-3 text-sm transition-colors",
"hover:bg-accent hover:text-accent-foreground",
if(@current_page == @total_pages, do: "pointer-events-none opacity-50", else: nil),
@class
])}
{@rest}
>
<span class="sr-only">Next</span>
<.icon name="chevron-right" size={:sm} />
</button>
"""
end
attr :class, :string, default: nil
attr :rest, :global
def pagination_ellipsis(assigns) do
~H"""
<span
aria-hidden="true"
class={cn(["flex h-9 w-9 items-center justify-center text-sm", @class])}
{@rest}
>
…
</span>
"""
end
end