Pagination
Indicate that related content is split across multiple pages with accessible pagination links.
<twig:Pagination ariaLabel="Article pages">
<twig:Pagination:Item label="Previous" disabled />
<twig:Pagination:Item href="?page=1" label="1" active />
<twig:Pagination:Item href="?page=2" label="2" />
<twig:Pagination:Item href="?page=3" label="3" />
<twig:Pagination:Item href="?page=2" label="Next" />
</twig:Pagination>
Installation
php bin/console ux:install pagination --kit bootstrap
Install the following Composer dependencies:
composer require twig/extra-bundle twig/html-extra:^3.12.0
Install the following front-end dependencies:
npm install bootstrap@^5.3.0
# ...or with Symfony AssetMapper
php bin/console importmap:require bootstrap bootstrap/dist/css/bootstrap.min.css
Copy the following file(s) into your app:
{# @prop size 'sm'|'lg'|null The pagination control size. #}
{# @prop align 'start'|'center'|'end'|null The horizontal alignment of the pagination links. #}
{# @prop ariaLabel string The accessible name of the navigation landmark. #}
{# @block content The pagination items, typically `Pagination:Item` components. #}
{%- props
size = null,
align = null,
ariaLabel = 'Pagination'
-%}
{%- set pagination_classes = html_classes('pagination', {
('pagination-' ~ size): size in ['sm', 'lg'],
('justify-content-' ~ align): align in ['start', 'center', 'end'],
}) -%}
<nav {{ attributes.defaults({'aria-label': ariaLabel}) }}>
<ul class="{{ pagination_classes }}">
{%- block content -%}{% endblock -%}
</ul>
</nav>
{# @prop active boolean Whether the item represents the current page. #}
{# @prop disabled boolean Whether the item is unavailable for interaction. #}
{# @prop href string|null The destination of the page link. #}
{# @prop label string The fallback item label when no content block is provided. #}
{# @prop ariaLabel string|null The accessible label for the page link. #}
{# @block content The page link content. #}
{%- props
active = false,
disabled = false,
href = null,
label = '',
ariaLabel = null
-%}
{%- set item_classes = html_classes('page-item', {
active: active,
disabled: disabled,
}) -%}
<li {{ attributes.defaults({class: item_classes}) }}>
{%- if href is not null and not disabled -%}
<a class="page-link" href="{{ href }}"{% if ariaLabel is not null %} aria-label="{{ ariaLabel }}"{% endif %}{% if active %} aria-current="page"{% endif %}>
{%- block content -%}{{- label -}}{%- endblock -%}
</a>
{%- else -%}
<span class="page-link"{% if ariaLabel is not null %} aria-label="{{ ariaLabel }}"{% endif %}{% if active %} aria-current="page"{% endif %}{% if disabled %} aria-disabled="true"{% endif %}>
{{- block('content') -}}
</span>
{%- endif -%}
</li>
Usage
<twig:Pagination ariaLabel="Search results pages">
<twig:Pagination:Item href="?page=1" label="1" active />
<twig:Pagination:Item href="?page=2" label="2" />
<twig:Pagination:Item href="?page=3" label="3" />
</twig:Pagination>
Accessibility
Give each pagination landmark a descriptive ariaLabel, especially when a page contains more than one pagination control.
The active item exposes aria-current="page". Disabled items render as non-interactive span elements instead of links.
Examples
Overview
Use connected page links to navigate through a series of related pages.
<twig:Pagination ariaLabel="Page navigation example">
<twig:Pagination:Item href="#" label="Previous" />
<twig:Pagination:Item href="#" label="1" />
<twig:Pagination:Item href="#" label="2" />
<twig:Pagination:Item href="#" label="3" />
<twig:Pagination:Item href="#" label="Next" />
</twig:Pagination>
Working with icons
When replacing previous and next labels with symbols, provide an accessible label and hide the symbol from assistive technologies.
<twig:Pagination ariaLabel="Page navigation example">
<twig:Pagination:Item href="#" ariaLabel="Previous"><span aria-hidden="true">«</span></twig:Pagination:Item>
<twig:Pagination:Item href="#" label="1" />
<twig:Pagination:Item href="#" label="2" />
<twig:Pagination:Item href="#" label="3" />
<twig:Pagination:Item href="#" ariaLabel="Next"><span aria-hidden="true">»</span></twig:Pagination:Item>
</twig:Pagination>
Active
Mark the page currently being viewed as active. It can remain a link or render as a non-interactive item.
<div>
<twig:Pagination ariaLabel="Article pages">
<twig:Pagination:Item href="#" label="Previous" />
<twig:Pagination:Item href="#" label="1" />
<twig:Pagination:Item href="#" label="2" active />
<twig:Pagination:Item href="#" label="3" />
<twig:Pagination:Item href="#" label="Next" />
</twig:Pagination>
<twig:Pagination ariaLabel="Article pages with a non-interactive current page" class="mt-3">
<twig:Pagination:Item href="#" label="1" />
<twig:Pagination:Item label="2" active />
<twig:Pagination:Item href="#" label="3" />
</twig:Pagination>
</div>
Disabled
Disable unavailable navigation items without leaving an unusable link in the keyboard tab order.
<twig:Pagination ariaLabel="Article pages">
<twig:Pagination:Item label="Previous" disabled />
<twig:Pagination:Item href="#" label="1" />
<twig:Pagination:Item href="#" label="2" active />
<twig:Pagination:Item href="#" label="3" />
<twig:Pagination:Item href="#" label="Next" />
</twig:Pagination>
Sizing
Use Bootstrap's large and small pagination sizes.
<div class="d-flex flex-column gap-3">
<twig:Pagination size="lg" ariaLabel="Large pagination example">
<twig:Pagination:Item label="1" active />
<twig:Pagination:Item href="#" label="2" />
<twig:Pagination:Item href="#" label="3" />
</twig:Pagination>
<twig:Pagination size="sm" ariaLabel="Small pagination example">
<twig:Pagination:Item label="1" active />
<twig:Pagination:Item href="#" label="2" />
<twig:Pagination:Item href="#" label="3" />
</twig:Pagination>
</div>
Alignment
Align the pagination links with Bootstrap flexbox utilities through the align prop.
<div class="d-flex flex-column gap-3">
<twig:Pagination align="center" ariaLabel="Centered page navigation example">
<twig:Pagination:Item label="Previous" disabled />
<twig:Pagination:Item href="#" label="1" />
<twig:Pagination:Item href="#" label="2" />
<twig:Pagination:Item href="#" label="3" />
<twig:Pagination:Item href="#" label="Next" />
</twig:Pagination>
<twig:Pagination align="end" ariaLabel="End-aligned page navigation example">
<twig:Pagination:Item label="Previous" disabled />
<twig:Pagination:Item href="#" label="1" />
<twig:Pagination:Item href="#" label="2" />
<twig:Pagination:Item href="#" label="3" />
<twig:Pagination:Item href="#" label="Next" />
</twig:Pagination>
</div>
API Reference
<twig:Pagination>
| Prop | Type | Default |
|---|---|---|
size The pagination control size.
|
'sm'|'lg'|null |
null |
align The horizontal alignment of the pagination links.
|
'start'|'center'|'end'|null |
null |
ariaLabel The accessible name of the navigation landmark.
|
string |
'Pagination' |
| Block | Description |
|---|---|
content |
The pagination items, typically Pagination:Item components. |
<twig:Pagination:Item>
| Prop | Type | Default |
|---|---|---|
active Whether the item represents the current page.
|
boolean |
false |
disabled Whether the item is unavailable for interaction.
|
boolean |
false |
href The destination of the page link.
|
string|null |
null |
label The fallback item label when no content block is provided.
|
string |
'' |
ariaLabel The accessible label for the page link.
|
string|null |
null |
| Block | Description |
|---|---|
content |
The page link content. |