View as Markdown

Pagination

Indicate that related content is split across multiple pages with accessible pagination links.

100%
Loading...
<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 &#039;sm&#039;|&#039;lg&#039;|null The pagination control size. #}
{# @prop align &#039;start&#039;|&#039;center&#039;|&#039;end&#039;|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 = &#039;Pagination&#039;
-%}

{%- set pagination_classes = html_classes(&#039;pagination&#039;, {
    (&#039;pagination-&#039; ~ size): size in [&#039;sm&#039;, &#039;lg&#039;],
    (&#039;justify-content-&#039; ~ align): align in [&#039;start&#039;, &#039;center&#039;, &#039;end&#039;],
}) -%}

&lt;nav {{ attributes.defaults({&#039;aria-label&#039;: ariaLabel}) }}&gt;
    &lt;ul class=&quot;{{ pagination_classes }}&quot;&gt;
        {%- block content -%}{% endblock -%}
    &lt;/ul&gt;
&lt;/nav&gt;
{# @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 = &#039;&#039;,
    ariaLabel = null
-%}

{%- set item_classes = html_classes(&#039;page-item&#039;, {
    active: active,
    disabled: disabled,
}) -%}
&lt;li {{ attributes.defaults({class: item_classes}) }}&gt;
    {%- if href is not null and not disabled -%}
        &lt;a class=&quot;page-link&quot; href=&quot;{{ href }}&quot;{% if ariaLabel is not null %} aria-label=&quot;{{ ariaLabel }}&quot;{% endif %}{% if active %} aria-current=&quot;page&quot;{% endif %}&gt;
            {%- block content -%}{{- label -}}{%- endblock -%}
        &lt;/a&gt;
    {%- else -%}
        &lt;span class=&quot;page-link&quot;{% if ariaLabel is not null %} aria-label=&quot;{{ ariaLabel }}&quot;{% endif %}{% if active %} aria-current=&quot;page&quot;{% endif %}{% if disabled %} aria-disabled=&quot;true&quot;{% endif %}&gt;
            {{- block(&#039;content&#039;) -}}
        &lt;/span&gt;
    {%- endif -%}
&lt;/li&gt;

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.

100%
Loading...
<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.

100%
Loading...
<twig:Pagination ariaLabel="Page navigation example">
    <twig:Pagination:Item href="#" ariaLabel="Previous"><span aria-hidden="true">&laquo;</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">&raquo;</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.

100%
Loading...
<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.

100%
Loading...
<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.

100%
Loading...
<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.

100%
Loading...
<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 
'sm'|'lg'|null null
align 
'start'|'center'|'end'|null null
ariaLabel 
string 'Pagination'
Block Description
content The pagination items, typically Pagination:Item components.

<twig:Pagination:Item>

Prop Type Default
active 
boolean false
disabled 
boolean false
href 
string|null null
label 
string ''
ariaLabel 
string|null null
Block Description
content The page link content.