Skip to main content
Logo USWDS + Tailwind

Pagination

Pagination is navigation for paginated content.

Examples

Bounded

Breakpoints

Mobile

320px

Mobile Lg

480px

Tablet

640px

Desktop

1024px
Twig
{% macro button(page_number, href = '#', is_active = false, is_last = false) %}
<li class="h-10 min-w-10 inline-flex">
<a href="#" class="p-2 w-full flex rounded border border-gray-90/20 text-blue-60v justify-center items-center hover:text-blue-warm-70v hover:border-blue-warm-70v focus:text-blue-warm-70v focus:border-blue-warm-70v focus:outline focus:outline-offset-0 focus:outline-4 focus:outline-blue-40v aria-[current=page]:bg-gray-90 aria-[current=page]:text-white" aria-label="{{ is_last ? 'Last page, page #{page_number}' : 'Page #{page_number}' }}" {{ is_active ? "aria-current='page'" }}>
{{- page_number -}}
</a>
</li>
{% endmacro %}
{% macro ellipsis() %}
<li aria-label="ellipsis indicating non-visible pages" class="h-10 min-w-10 p-2 select-none flex items-center justify-center">
<span>...</span>
</li>
{% endmacro %}
{% import _self as self %}
<nav aria-label="Pagination" class="@container flex justify-center">
<ul class="flex space-x-2">
{% if pagination.current_page != 1 %}
<li class="h-10 min-w-10 hidden @tablet:inline-flex">
<a href="#" class="pr-2 mr-3 inline-flex items-center text-blue-60v hover:underline hover:text-blue-warm-70v focus:underline focus:text-blue-warm-70v focus:outline focus:outline-4 focus:outline-blue-40v">
<span aria-hidden="true" class="icon-[material-symbols--chevron-left] align-middle size-4"></span>
Previous
</a>
</li>
{% endif %}
{% if pagination.page_count <= 7 %}
{% for i in range(1, pagination.page_count) %}
{{ self.button(i, '', i == pagination.current_page, i == pagination.page_count) }}
{% endfor %}
{% else %}
{% if pagination.current_page <= 4 %}
{% for i in range(1, 4) %}
{{ self.button(i,'', i == pagination.current_page, i == pagination.page_count) }}
{% endfor %}
{{ self.ellipsis() }}
{{ self.button(pagination.page_count, '') }}
{% elseif pagination.current_page >= pagination.page_count - 3 %}
{{ self.button(1, '') }}
{{ self.ellipsis() }}
{% for i in range(pagination.page_count - 4, pagination.page_count) %}
{{ self.button(i,'', i == pagination.current_page, i == pagination.page_count) }}
{% endfor %}
{% else %}
{{ self.button(1, '') }}
{{ self.ellipsis() }}
{% for i in range(pagination.current_page - 1, pagination.current_page + 1) %}
{{ self.button(i, '', i == pagination.current_page, i == pagination.page_count) }}
{% endfor %}
{{ self.ellipsis() }}
{{ self.button(pagination.page_count, '') }}
{% endif %}
{% endif %}
{% if pagination.current_page != pagination.page_count %}
<li class="h-10 min-w-10 hidden @tablet:inline-flex">
<a href="#" class="pl-2 ml-3 inline-flex items-center text-blue-60v hover:underline hover:text-blue-warm-70v focus:underline focus:text-blue-warm-70v focus:outline focus:outline-4 focus:outline-blue-40v">
Next
<span aria-hidden="true" class="icon-[material-symbols--chevron-right] align-middle size-4"></span>
</a>
</li>
{% endif %}
</ul>
</nav>

Unbounded

Breakpoints

Mobile

320px

Mobile Lg

480px

Tablet

640px

Desktop

1024px
Twig
{% macro button(page_number, href = '#', is_active = false, is_last = false) %}
<li class="h-10 min-w-10 inline-flex">
<a href="#" class="p-2 w-full flex rounded border border-gray-90/20 text-blue-60v justify-center items-center hover:text-blue-warm-70v hover:border-blue-warm-70v focus:text-blue-warm-70v focus:border-blue-warm-70v focus:outline focus:outline-offset-0 focus:outline-4 focus:outline-blue-40v aria-[current=page]:bg-gray-90 aria-[current=page]:text-white" aria-label="{{ is_last ? 'Last page, page #{page_number}' : 'Page #{page_number}' }}" {{ is_active ? "aria-current='page'" }}>
{{- page_number -}}
</a>
</li>
{% endmacro %}
{% macro ellipsis() %}
<li aria-label="ellipsis indicating non-visible pages" class="h-10 min-w-10 p-2 select-none flex items-center justify-center">
<span>...</span>
</li>
{% endmacro %}
{% import _self as self %}
<nav aria-label="Pagination" class="@container flex justify-center">
<ul class="flex space-x-2">
{% if pagination.current_page != 1 %}
<li class="h-10 min-w-10 hidden @tablet:inline-flex">
<a href="#" class="pr-2 mr-3 inline-flex items-center text-blue-60v hover:underline hover:text-blue-warm-70v focus:underline focus:text-blue-warm-70v focus:outline focus:outline-4 focus:outline-blue-40v">
<span aria-hidden="true" class="icon-[material-symbols--chevron-left] align-middle size-4"></span>
Previous
</a>
</li>
{% endif %}
{% if pagination.current_page <= 5 %}
{% for i in range(1, 6) %}
{{ self.button(i,'', i == pagination.current_page, i == pagination.page_count) }}
{% endfor %}
{{ self.ellipsis() }}
{% else %}
{{ self.button(1, '') }}
{{ self.ellipsis() }}
{% for i in range(pagination.current_page - 1, pagination.current_page + 2) %}
{{ self.button(i,'', i == pagination.current_page, i == pagination.page_count) }}
{% endfor %}
{{ self.ellipsis() }}
{% endif %}
<li class="h-10 min-w-10 hidden @tablet:inline-flex">
<a href="#" class="pl-2 ml-3 inline-flex items-center text-blue-60v hover:underline hover:text-blue-warm-70v focus:underline focus:text-blue-warm-70v focus:outline focus:outline-4 focus:outline-blue-40v">
Next
<span aria-hidden="true" class="icon-[material-symbols--chevron-right] align-middle size-4"></span>
</a>
</li>
</ul>
</nav>

Component API

Pagination is made up of the following elements:

Root

  • This element is automatically appended to the document body, ensuring that this element always properly overlays page contents when opened.

  • aria-label

    Default: 'Breadcrumb'

    Provide a label that describes the type of navigation provided in the nav element.

List

  • <ul>

    Use an <ul> for Pagination Lists. This allows assistive technology to enumerate the items in the pagination and allows shortcuts between list items.

List Items

  • <li>

    Use an <li> for Pagination List Items. This allows assistive technology to enumerate the items in the pagination and allows shortcuts between list items.

  • aria-label

    Default: 'ellipsis indicating non-visible pages'

    When a Pagination List Item contains an Ellipsis, use an aria-label to describe to assistive technology the meaning of the ellipsis item.

  • <a> or <span>

    Use an <a> element when Pagination List Items are clickable. Every item, except Ellipsis elements, should use an <a> element.

    Use a <span> element for Ellipsis elements.

  • aria-current="page"

    Allows screen readers to communicate that the element represents a link to the current page.

    Only use the aria-current attribute on the link element describing the current page.