<nav class="rtds-pagination rtds-flex-wrap rtds-pagination--text rtds-pagination--text" role="navigation" aria-label="Paginazione">
<ul class="rtds-pagination__list">
<li>
<a class="rtds-pagination__link rtds-pagination__link-text rtds-py-1 rtds-px-2" href="">Precedente</a>
</li>
<li>
<a class="rtds-pagination__link rtds-pagination__link-button rtds-pagination__link-text " href="#" aria-label="pagina 1">1</a>
</li>
<li>
<a class="rtds-pagination__link rtds-pagination__link-button rtds-pagination__link-text rtds-background-primary rtds-border-primary rtds-text-white hover:rtds-content-01" href="#" aria-label="Pagina corrente, pagina 2" aria-current="page">2</a>
</li>
<li>
<a class="rtds-pagination__link rtds-pagination__link-button rtds-pagination__link-text " href="#" aria-label="pagina 3">3</a>
</li>
<li>
<a class="rtds-pagination__link rtds-pagination__link-button rtds-pagination__link-text " href="#" aria-label="pagina 4">4</a>
</li>
<li>
<a class="rtds-pagination__link rtds-pagination__link-text rtds-py-1 rtds-px-2" href="">Successiva</a>
</li>
</ul>
</nav>
{% extends "@pagination" %}
{% block classes %}{{ super() }} rtds-pagination--text{% endblock classes %}
{
"items": [
{
"label": 1
},
{
"label": 2,
"isCurrent": true
},
{
"label": 3
},
{
"label": 4
}
],
"isFirstPage": false,
"isLastPage": false,
"classes": "rtds-pagination--text",
"hasLabels": true
}
/**
* PAGINATION
*
*/
.rtds-pagination {
padding: var(--spacing-2);
display: flex;
}
.rtds-pagination__list {
flex-wrap: wrap;
display: flex;
gap: var(--spacing-2);
}
.rtds-pagination__link {
height: var(--spacing-7);
display: flex;
justify-content: center;
align-items: center;
transition-property: all;
transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1);
transition-duration: 150ms;
}
@media (min-width: 768px) {
.rtds-pagination__link {
height: var(--spacing-8);
}
}
.rtds-pagination__link-button {
width: var(--spacing-7);
border-radius: 0.25rem;
--tw-bg-opacity: 1;
background-color: rgb(255 255 255 / var(--tw-bg-opacity, 1));
border-color: var(--color-border-gray-01);
border-width: 1px;
}
.rtds-pagination__link-button:hover {
background-color: var(--color-background-02);
}
@media (min-width: 768px) {
.rtds-pagination__link-button {
width: var(--spacing-8);
}
}
.rtds-pagination__link-text {
font-size: var(--fontsize-text-xs);
font-weight: 500;
}
.rtds-pagination__link-text:hover {
text-decoration-line: underline;
}
@media (min-width: 768px) {
.rtds-pagination__link-text {
font-size: var(--fontsize-text-sm);
}
}
.rtds-pagination--rounded .rtds-pagination__link-button {
border-radius: 9999px;
}
.rtds-pagination-wrapper {
display: flex;
flex-wrap: wrap;
align-items: center;
justify-content: space-between;
gap: var(--spacing-4);
}
.rtds-pagination-wrapper--centered {
justify-content: center;
}
:where(.rtds-pagination__link)[aria-disabled="true"] {
color: var(--color-content-disabled);
background-color: var(--color-background-02);
border-color: var(--color-background-03);
cursor: default;
pointer-events: none;
}
.rtds-pagination__total {
font-size: var(--fontsize-text-sm);
color: var(--color-content-03);
align-self: center;
margin: 0;
padding: var(--spacing-2);
}
.rtds-pagination-per-page {
display: flex;
align-items: center;
gap: var(--spacing-2);
}
/**
* PAGINATION
*
*/
@layer components {
.rtds-pagination {
@apply rtds-flex rtds-p-2;
}
.rtds-pagination__list {
@apply rtds-flex rtds-gap-2 rtds-flex-wrap;
}
.rtds-pagination__link {
@apply rtds-flex rtds-items-center rtds-justify-center rtds-h-7 md:rtds-h-8 rtds-transition-all;
}
.rtds-pagination__link-button {
@apply rtds-w-7 md:rtds-w-8 rtds-border rtds-rounded rtds-border-gray-01 rtds-bg-white hover:rtds-background-02;
}
.rtds-pagination__link-text {
@apply rtds-text-xs md:rtds-text-sm rtds-font-medium hover:rtds-underline;
}
.rtds-pagination--rounded .rtds-pagination__link-button {
@apply rtds-rounded-full;
}
.rtds-pagination-wrapper {
display: flex;
flex-wrap: wrap;
align-items: center;
justify-content: space-between;
gap: var(--spacing-4);
}
.rtds-pagination-wrapper--centered {
justify-content: center;
}
:where(.rtds-pagination__link)[aria-disabled="true"] {
color: var(--color-content-disabled);
background-color: var(--color-background-02);
border-color: var(--color-background-03);
cursor: default;
pointer-events: none;
}
.rtds-pagination__total {
font-size: var(--fontsize-text-sm);
color: var(--color-content-03);
align-self: center;
margin: 0;
padding: var(--spacing-2);
}
.rtds-pagination-per-page {
display: flex;
align-items: center;
gap: var(--spacing-2);
}
}
Il componente Paginazione gestisce la navigazione tra le pagine di un contenuto. Supporta diverse varianti di visualizzazione e offre una navigazione accessibile.
Il componente è sempre renderizzato come <nav role="navigation" aria-label="Paginazione"> contenente un <ul> con un <li> per ogni elemento. I link con sola icona (prima/ultima/precedente/successiva pagina) hanno aria-label descrittivo; i link con testo visibile (“Precedente”, “Successiva”) non usano aria-label — il testo è già il nome accessibile. La pagina corrente ha aria-current="page". Quando il componente si trova alla prima o ultima pagina, i link di navigazione corrispondenti ricevono aria-disabled="true".
pagination--rounded: Versione con bordi arrotondatipagination--text: Versione con etichette testuali (“Precedente”/“Successiva”) invece di iconefirst-page: Prima pagina attiva — link “Prima pagina” e “Pagina precedente” con aria-disabled="true"last-page: Ultima pagina attiva — link “Pagina successiva” e “Ultima pagina” con aria-disabled="true"centered: Paginazione centrata orizzontalmentecon-totale: Testo totale elementi inline nella nav (es. “100-110 di 300 elementi”)con-per-page: Selettore “Risultati per pagina” dentro il <nav>, allineato a destra tramite rtds-ml-autocon-totale-e-per-page: Combinazione totale elementi + selettore per-page, entrambi dentro il <nav>con-totale-e-per-page-centered: Come sopra, con paginazione centrataContesto di sviluppo Fractal/Nunjucks — Questa sezione riguarda esclusivamente i parametri del context
.config.ymlusati durante lo sviluppo nella libreria. Non descrive attributi HTML o proprietà da usare nei temi, CMS o ambienti di implementazione: per quello, fare riferimento alla sezione Esempi di utilizzo.
classes (stringa, opzionale): Classi CSS aggiuntive per il componentepadding (stringa, opzionale): Classi per il paddingcentered (booleano, opzionale): Se true, centra la paginazione orizzontalmentehasLabels (booleano, opzionale): Se true, usa etichette testuali (“Precedente”/“Successiva”) invece di iconelinkClasses (stringa, opzionale): Classi CSS aggiuntive per i linkisFirstPage (booleano, opzionale, default false): Se true, aggiunge aria-disabled="true" sui link di navigazione verso le pagine precedentiisLastPage (booleano, opzionale, default false): Se true, aggiunge aria-disabled="true" sui link di navigazione verso le pagine successivetotalText (stringa, opzionale): Testo totale elementi (es. "100-110 di 300 elementi") mostrato inline nella nav; se assente nessun elemento renderizzatoitems (array, obbligatorio): Elementi della paginazioneisCurrent (booleano, opzionale): Indica se l’elemento è la pagina correntelabel (stringa, obbligatorio): Etichetta dell’elementocon-per-page e con-totale-e-per-pageTutti i parametri base, più:
perPageId (stringa, obbligatorio): ID usato per <label for> e <select id> — deve essere univoco nella paginaperPageOptions (array, obbligatorio): Opzioni del selettore; ogni elemento ha:value (stringa/numero): valore dell’<option>label (stringa): testo visibile dell’<option>perPageSelected (stringa/numero, opzionale): Valore dell’opzione selezionataLivello AA — criteri pertinenti:
<nav> e <ul> semanticamente corretti per la navigazione paginataaria-current="page" sulla pagina corrente comunica la posizione nella paginazionearia-label descrittivo; aria-current identifica la pagina corrente; aria-disabled comunica lo stato disabilitato<nav role="navigation" aria-label="Paginazione"> — identifica la regione di navigazione e la distingue da altri elementi <nav> nella pagina<ul> con <li> per ogni elemento di paginazionearia-label descrittivi (“Prima pagina”, “Pagina precedente”, “Pagina successiva”, “Ultima pagina”)aria-label — il testo è già il nome accessibile| Attributo | Valori | Condizione |
|---|---|---|
aria-label |
"Paginazione" |
sempre presente sul <nav> |
aria-label |
"Prima pagina", "Pagina precedente", "Pagina successiva", "Ultima pagina" |
solo sui link con icona (senza testo visibile) |
aria-current |
"page" |
presente sull’<a> della pagina corrente |
aria-disabled |
"true" |
su prima/prev quando isFirstPage: true; su next/ultima quando isLastPage: true |
| Tasto | Azione |
|---|---|
Tab / Shift+Tab |
Sposta il focus tra i link di paginazione |
Enter |
Attiva il link corrente |
aria-disabled)aria-disabled="true" viene usato invece di disabled perché l’attributo disabled non è valido su elementi <a>. Il link rimane focusabile e annuncia lo stato “disabilitato” agli screen reader. Il consumer deve gestire lato JS il blocco della navigazione quando aria-disabled è presente (es. event.preventDefault() sul click).
:focus-visible è sempre visibile e non viene rimosso via CSSaria-label (es. “Prima pagina”, “Pagina precedente”)aria-label — il testo è già il nome accessibile; aggiungere un aria-label ridondante potrebbe divergere dal testo visibilearia-current="page", che gli screen reader annunciano come “pagina corrente”aria-disabled="true" vengono annunciati come disabilitati ma rimangono nel tab order; il consumer è responsabile di prevenire la navigazione via JS o event.preventDefault()<!-- Esempio base -->
<nav class="rtds-pagination rtds-flex-wrap" role="navigation" aria-label="Paginazione">
<ul class="rtds-pagination__list">
<li>
<a href="#" aria-label="Prima pagina" class="rtds-pagination__link rtds-pagination__link-button">
<svg class="rtds-icon" aria-hidden="true" focusable="false"><use href="#mini--chevron-double-left"></use></svg>
</a>
</li>
<li>
<a href="#" aria-label="Pagina precedente" class="rtds-pagination__link rtds-pagination__link-button">
<svg class="rtds-icon" aria-hidden="true" focusable="false"><use href="#mini--chevron-left"></use></svg>
</a>
</li>
<li>
<a href="#" aria-label="pagina 1" class="rtds-pagination__link rtds-pagination__link-button rtds-pagination__link-text">1</a>
</li>
<li>
<a href="#" aria-label="Pagina corrente, pagina 2" aria-current="page" class="rtds-pagination__link rtds-pagination__link-button rtds-pagination__link-text rtds-background-primary rtds-border-primary rtds-text-white">2</a>
</li>
<li>
<a href="#" aria-label="pagina 3" class="rtds-pagination__link rtds-pagination__link-button rtds-pagination__link-text">3</a>
</li>
<li>
<a href="#" aria-label="Pagina successiva" class="rtds-pagination__link rtds-pagination__link-button">
<svg class="rtds-icon" aria-hidden="true" focusable="false"><use href="#mini--chevron-right"></use></svg>
</a>
</li>
<li>
<a href="#" aria-label="Ultima pagina" class="rtds-pagination__link rtds-pagination__link-button">
<svg class="rtds-icon" aria-hidden="true" focusable="false"><use href="#mini--chevron-double-right"></use></svg>
</a>
</li>
</ul>
</nav>
<!-- Esempio: prima pagina (link prev/first disabilitati) -->
<nav class="rtds-pagination rtds-flex-wrap" role="navigation" aria-label="Paginazione">
<ul class="rtds-pagination__list">
<li>
<a href="#" aria-label="Prima pagina" aria-disabled="true" class="rtds-pagination__link rtds-pagination__link-button">
<svg class="rtds-icon" aria-hidden="true" focusable="false"><use href="#mini--chevron-double-left"></use></svg>
</a>
</li>
<li>
<a href="#" aria-label="Pagina precedente" aria-disabled="true" class="rtds-pagination__link rtds-pagination__link-button">
<svg class="rtds-icon" aria-hidden="true" focusable="false"><use href="#mini--chevron-left"></use></svg>
</a>
</li>
<li>
<a href="#" aria-label="Pagina corrente, pagina 1" aria-current="page" class="rtds-pagination__link rtds-pagination__link-button rtds-pagination__link-text rtds-background-primary rtds-border-primary rtds-text-white">1</a>
</li>
<li>
<a href="#" aria-label="pagina 2" class="rtds-pagination__link rtds-pagination__link-button rtds-pagination__link-text">2</a>
</li>
<!-- ... -->
</ul>
</nav>
<!-- Esempio: variante con totale elementi -->
<nav class="rtds-pagination rtds-flex-wrap" role="navigation" aria-label="Paginazione">
<ul class="rtds-pagination__list">
<!-- ... -->
</ul>
<p class="rtds-pagination__total rtds-px-4">100-110 di 300 elementi</p>
</nav>
<!-- Esempio: variante con selettore per-page (per-page dentro nav, allineato a destra) -->
<nav class="rtds-pagination rtds-flex-wrap" role="navigation" aria-label="Paginazione">
<ul class="rtds-pagination__list">
<!-- ... -->
</ul>
<div class="rtds-pagination-per-page rtds-px-2 rtds-ml-auto">
<label for="per-page-select">Risultati per pagina</label>
<div class="rtds-select rtds-select--sm">
<select id="per-page-select" name="per-page-select">
<option value="10" selected>10</option>
<option value="25">25</option>
<option value="50">50</option>
</select>
</div>
</div>
</nav>
<!-- Esempio: variante con totale + per-page -->
<nav class="rtds-pagination rtds-flex-wrap" role="navigation" aria-label="Paginazione">
<ul class="rtds-pagination__list">
<!-- ... -->
</ul>
<p class="rtds-pagination__total rtds-px-4">100-110 di 300 elementi</p>
<div class="rtds-pagination-per-page rtds-px-2 rtds-ml-auto">
<label for="per-page-select-totale">Risultati per pagina</label>
<div class="rtds-select rtds-select--sm">
<select id="per-page-select-totale" name="per-page-select-totale">
<option value="10" selected>10</option>
<option value="25">25</option>
<option value="50">50</option>
</select>
</div>
</div>
</nav>