<nav class="rtds-steps" aria-label="Avanzamento procedura">
<ol class="rtds-steps__list">
<li class="rtds-steps__item rtds-steps__item--completed">
<a href="/step1" class="rtds-steps__link">
<span class="rtds-steps__indicator" aria-hidden="true">
<svg class="rtds-icon rtds-fill-current rtds-w-4 rtds-h-4" aria-hidden="true" focusable="false" role="img">
<use href="../../icons.svg#check-solid" />
</svg>
</span>
<span class="rtds-sr-only">Completato: </span>
<span class="rtds-steps__label">Dati anagrafici</span>
</a>
</li>
<li class="rtds-steps__item rtds-steps__item--completed">
<span class="rtds-steps__link">
<span class="rtds-steps__indicator" aria-hidden="true">
<svg class="rtds-icon rtds-fill-current rtds-w-4 rtds-h-4" aria-hidden="true" focusable="false" role="img">
<use href="../../icons.svg#check-solid" />
</svg>
</span>
<span class="rtds-sr-only">Completato: </span>
<span class="rtds-steps__label">Contatti</span>
</span>
</li>
<li class="rtds-steps__item rtds-steps__item--active">
<span class="rtds-steps__link" aria-current="step">
<span class="rtds-steps__indicator" aria-hidden="true"></span>
<span class="rtds-sr-only">Corrente: </span>
<span class="rtds-steps__label">Documenti</span>
</span>
</li>
<li class="rtds-steps__item">
<span class="rtds-steps__link">
<span class="rtds-steps__indicator" aria-hidden="true"></span>
<span class="rtds-steps__label">Riepilogo</span>
</span>
</li>
<li class="rtds-steps__item">
<span class="rtds-steps__link">
<span class="rtds-steps__indicator" aria-hidden="true"></span>
<span class="rtds-steps__label">Conferma</span>
</span>
</li>
</ol>
<span class="rtds-steps__counter" aria-hidden="true">3 / 5</span>
</nav>
{%- set activeIndex = 0 -%}
{%- for step in steps -%}
{%- if step.active -%}{%- set activeIndex = loop.index -%}{%- endif -%}
{%- endfor -%}
{%- set total = steps | length -%}
<nav class="rtds-steps{%- block modifierClass %}{% endblock %}{% if classes %} {{ classes }}{% endif %}" aria-label="{{ ariaLabel | default('Avanzamento procedura') }}">
<ol class="rtds-steps__list">
{%- for step in steps %}
<li class="rtds-steps__item{% if step.completed %} rtds-steps__item--completed{% elif step.active %} rtds-steps__item--active{% endif %}">
{%- if step.completed and step.href %}
<a href="{{ step.href }}" class="rtds-steps__link"{% if step.active %} aria-current="step"{% endif %}>
{%- else %}
<span class="rtds-steps__link"{% if step.active %} aria-current="step"{% endif %}>
{%- endif %}
{%- if numbered %}
<span class="rtds-steps__indicator" aria-hidden="true">
{{ loop.index }}
</span>
{%- elif step.completed %}
<span class="rtds-steps__indicator" aria-hidden="true">
{% render '@icon', { id: step.icon | default('check-solid'), size: 'rtds-w-4 rtds-h-4' }, true %}
</span>
{%- elif step.active %}
<span class="rtds-steps__indicator" aria-hidden="true"></span>
{%- else %}
<span class="rtds-steps__indicator" aria-hidden="true"></span>
{%- endif %}
{%- if step.completed %}
<span class="rtds-sr-only">{{ completedLabel | default('Completato: ') }}</span>
{%- elif step.active %}
<span class="rtds-sr-only">{{ currentLabel | default('Corrente: ') }}</span>
{%- endif %}
<span class="rtds-steps__label">{{ step.label }}</span>
{%- if step.completed and step.href %}
</a>
{%- else %}
</span>
{%- endif %}
</li>
{%- endfor %}
</ol>
<span class="rtds-steps__counter" aria-hidden="true">{{ activeIndex }} / {{ total }}</span>
</nav>
{
"ariaLabel": "Avanzamento procedura",
"completedLabel": "Completato: ",
"currentLabel": "Corrente: ",
"srStepLabel": "Step",
"srOfLabel": "di",
"steps": [
{
"label": "Dati anagrafici",
"completed": true,
"href": "/step1"
},
{
"label": "Contatti",
"completed": true
},
{
"label": "Documenti",
"active": true
},
{
"label": "Riepilogo"
},
{
"label": "Conferma"
}
]
}
.rtds-steps {
--_steps-color-default: var(--steps-color-default, var(--color-content-03, var(--color-neutral-900)));
--_steps-color-active: var(--steps-color-active, var(--color-content-secondary, var(--color-secondary-500)));
--_steps-color-completed: var(--steps-color-completed, var(--color-content-secondary, var(--color-secondary-500)));
--_steps-label-color: var(--steps-label-color, var(--color-content-01, var(--color-neutral-900)));
--_steps-indicator-size: var(--steps-indicator-size, var(--spacing-6, 1.5rem));
--_steps-indicator-bg: var(--steps-indicator-bg, var(--color-background-01, var(--color-neutral-50)));
--_steps-indicator-border: var(--steps-indicator-border, var(--color-border-gray-03, var(--color-neutral-600)));
--_steps-bar-color: var(--steps-bar-color, var(--color-border-gray-03, var(--color-neutral-600)));
--_steps-bar-height: var(--steps-bar-height, var(--spacing-1, 0.25rem));
display: flex;
align-items: center;
gap: var(--spacing-2);
}
.rtds-steps__list {
flex: 1;
min-width: 0;
display: flex;
list-style: none;
padding: 0;
margin: 0;
}
.rtds-steps__item {
flex: 1;
display: flex;
flex-direction: column;
}
/* Nasconde visualmente gli step non attivi su mobile, lasciandoli accessibili agli screen reader */
:where(.rtds-steps__item):not(.rtds-steps__item--active) {
position: absolute;
width: 1px;
height: 1px;
overflow: hidden;
clip-path: inset(50%);
white-space: nowrap;
}
.rtds-steps__link {
display: flex;
flex-direction: row;
align-items: center;
gap: var(--spacing-2);
text-decoration: none;
color: var(--_steps-color-default);
font-size: var(--fontsize-text-sm);
padding-block: var(--spacing-3);
padding-inline: var(--spacing-2);
}
:where(a.rtds-steps__link):hover .rtds-steps__label {
text-decoration: underline;
}
/* Indicatore: nascosto su mobile */
.rtds-steps__indicator {
display: none;
width: var(--_steps-indicator-size);
height: var(--_steps-indicator-size);
align-items: center;
justify-content: center;
border-radius: 50%;
flex-shrink: 0;
line-height: 1;
color: var(--_steps-color-default);
background-color: transparent;
border: 2px solid var(--_steps-indicator-border);
}
/* Completato: cerchio con bordo + sfondo bianco + check icon */
:where(.rtds-steps__item--completed) .rtds-steps__indicator {
color: var(--_steps-color-completed);
border-color: currentColor;
background-color: var(--_steps-indicator-bg);
}
/* Attivo: cerchio con bordo spesso + sfondo bianco */
:where(.rtds-steps__item--active) .rtds-steps__indicator {
color: var(--_steps-color-active);
background-color: var(--_steps-indicator-bg);
border-color: var(--_steps-color-active);
border-width: var(--spacing-2);
}
.rtds-steps__label {
color: inherit;
}
:where(.rtds-steps__item--completed) .rtds-steps__label {
color: var(--_steps-label-color);
}
:where(.rtds-steps__item--active) .rtds-steps__label {
font-weight: 600;
color: var(--_steps-color-active);
}
/* Counter: visibile su mobile affiancato allo step attivo */
.rtds-steps__counter {
display: block;
flex-shrink: 0;
font-size: var(--fontsize-text-sm);
font-weight: 700;
color: var(--_steps-color-default);
}
@media (min-width: 40rem) {
.rtds-steps {
display: block;
}
.rtds-steps__list {
gap: var(--spacing-base);
}
/* Ripristina la visibilità di tutti gli step su desktop */
:where(.rtds-steps__item):not(.rtds-steps__item--active) {
position: static;
width: auto;
height: auto;
overflow: visible;
clip-path: none;
white-space: normal;
}
.rtds-steps__item {
border-bottom: var(--_steps-bar-height) solid var(--_steps-bar-color);
}
.rtds-steps__item--completed {
border-bottom-color: var(--_steps-color-completed);
}
.rtds-steps__item--active {
border-bottom-color: var(--_steps-color-active);
}
/* Indicatore: visibile su desktop */
.rtds-steps__indicator {
display: flex;
}
.rtds-steps__counter {
display: none;
}
}
/* Variante numerata */
:where(.rtds-steps--numbered) .rtds-steps__indicator {
font-size: var(--fontsize-text-sm);
font-weight: 600;
}
/* Attivo numerata: cerchio pieno + numero bianco */
:where(.rtds-steps--numbered .rtds-steps__item--active) .rtds-steps__indicator {
background-color: var(--_steps-color-active);
border-color: var(--_steps-color-active);
color: var(--color-content-inverse, var(--color-neutral-50));
}
/* Completato numerata: cerchio con bordo + sfondo bianco + check icon */
:where(.rtds-steps--numbered .rtds-steps__item--completed) .rtds-steps__indicator {
color: var(--_steps-color-completed);
border-color: currentColor;
background-color: var(--_steps-indicator-bg);
}
@layer components {
.rtds-steps {
--_steps-color-default: var(--steps-color-default, var(--color-content-03, var(--color-neutral-900)));
--_steps-color-active: var(--steps-color-active, var(--color-content-secondary, var(--color-secondary-500)));
--_steps-color-completed: var(--steps-color-completed, var(--color-content-secondary, var(--color-secondary-500)));
--_steps-label-color: var(--steps-label-color, var(--color-content-01, var(--color-neutral-900)));
--_steps-indicator-size: var(--steps-indicator-size, var(--spacing-6, 1.5rem));
--_steps-indicator-bg: var(--steps-indicator-bg, var(--color-background-01, var(--color-neutral-50)));
--_steps-indicator-border: var(--steps-indicator-border, var(--color-border-gray-03, var(--color-neutral-600)));
--_steps-bar-color: var(--steps-bar-color, var(--color-border-gray-03, var(--color-neutral-600)));
--_steps-bar-height: var(--steps-bar-height, var(--spacing-1, 0.25rem));
display: flex;
align-items: center;
gap: var(--spacing-2);
}
.rtds-steps__list {
flex: 1;
min-width: 0;
display: flex;
list-style: none;
padding: 0;
margin: 0;
}
.rtds-steps__item {
flex: 1;
display: flex;
flex-direction: column;
}
/* Nasconde visualmente gli step non attivi su mobile, lasciandoli accessibili agli screen reader */
:where(.rtds-steps__item):not(.rtds-steps__item--active) {
position: absolute;
width: 1px;
height: 1px;
overflow: hidden;
clip-path: inset(50%);
white-space: nowrap;
}
.rtds-steps__link {
display: flex;
flex-direction: row;
align-items: center;
gap: var(--spacing-2);
text-decoration: none;
color: var(--_steps-color-default);
font-size: var(--fontsize-text-sm);
padding-block: var(--spacing-3);
padding-inline: var(--spacing-2);
}
:where(a.rtds-steps__link):hover .rtds-steps__label {
text-decoration: underline;
}
/* Indicatore: nascosto su mobile */
.rtds-steps__indicator {
display: none;
width: var(--_steps-indicator-size);
height: var(--_steps-indicator-size);
align-items: center;
justify-content: center;
border-radius: 50%;
flex-shrink: 0;
line-height: 1;
color: var(--_steps-color-default);
background-color: transparent;
border: 2px solid var(--_steps-indicator-border);
}
/* Completato: cerchio con bordo + sfondo bianco + check icon */
:where(.rtds-steps__item--completed) .rtds-steps__indicator {
color: var(--_steps-color-completed);
border-color: currentColor;
background-color: var(--_steps-indicator-bg);
}
/* Attivo: cerchio con bordo spesso + sfondo bianco */
:where(.rtds-steps__item--active) .rtds-steps__indicator {
color: var(--_steps-color-active);
background-color: var(--_steps-indicator-bg);
border-color: var(--_steps-color-active);
border-width: var(--spacing-2);
}
.rtds-steps__label {
color: inherit;
}
:where(.rtds-steps__item--completed) .rtds-steps__label {
color: var(--_steps-label-color);
}
:where(.rtds-steps__item--active) .rtds-steps__label {
font-weight: 600;
color: var(--_steps-color-active);
}
/* Counter: visibile su mobile affiancato allo step attivo */
.rtds-steps__counter {
display: block;
flex-shrink: 0;
font-size: var(--fontsize-text-sm);
font-weight: 700;
color: var(--_steps-color-default);
}
@media (min-width: 40rem) {
.rtds-steps {
display: block;
}
.rtds-steps__list {
gap: var(--spacing-base);
}
/* Ripristina la visibilità di tutti gli step su desktop */
:where(.rtds-steps__item):not(.rtds-steps__item--active) {
position: static;
width: auto;
height: auto;
overflow: visible;
clip-path: none;
white-space: normal;
}
.rtds-steps__item {
border-bottom: var(--_steps-bar-height) solid var(--_steps-bar-color);
}
.rtds-steps__item--completed {
border-bottom-color: var(--_steps-color-completed);
}
.rtds-steps__item--active {
border-bottom-color: var(--_steps-color-active);
}
/* Indicatore: visibile su desktop */
.rtds-steps__indicator {
display: flex;
}
.rtds-steps__counter {
display: none;
}
}
/* Variante numerata */
:where(.rtds-steps--numbered) .rtds-steps__indicator {
font-size: var(--fontsize-text-sm);
font-weight: 600;
}
/* Attivo numerata: cerchio pieno + numero bianco */
:where(.rtds-steps--numbered .rtds-steps__item--active) .rtds-steps__indicator {
background-color: var(--_steps-color-active);
border-color: var(--_steps-color-active);
color: var(--color-content-inverse, var(--color-neutral-50));
}
/* Completato numerata: cerchio con bordo + sfondo bianco + check icon */
:where(.rtds-steps--numbered .rtds-steps__item--completed) .rtds-steps__indicator {
color: var(--_steps-color-completed);
border-color: currentColor;
background-color: var(--_steps-indicator-bg);
}
}
Indicatore di avanzamento per flussi multi-step (wizard, moduli a più pagine). Mostra gli step del percorso con i rispettivi stati (completato, attivo, futuro) senza includere content area né pulsanti di navigazione — entrambi sono responsabilità del consumer. Su mobile mostra solo lo step attivo (gli altri sono nascosti visivamente ma restano accessibili agli screen reader) affiancato da un contatore compatto, calcolato senza JavaScript.
Il componente produce sempre un <nav> con un <ol> di step. L’elemento interno di ogni step varia:
<a href="..."> — step completato con href fornito sull’oggetto step; consente di tornare a step precedenti senza JavaScript<span> — tutti gli altri casi: step completato senza href, step attivo, step futurosteps (default): indicatore circolare sempre presente per tutti gli stati — cerchio vuoto con bordo per gli step futuri, cerchio con bordo + spunta (check-solid) per i completati, cerchio con bordo spesso (8px) e sfondo bianco senza icona per l’attivonumbered: numero progressivo (1, 2, 3…) al posto di icone e cerchi; utile quando la sequenzialità numerica è significativaContesto di sviluppo Fractal/Nunjucks — parametri del context
.config.ymlusati nella libreria.
steps (array, obbligatorio): lista di oggetti step (vedi Oggetto step)ariaLabel (stringa, opzionale, default: "Avanzamento procedura"): label del <nav> letta dagli screen readercompletedLabel (stringa, opzionale, default: "Completato: "): prefisso sr-only per step completaticurrentLabel (stringa, opzionale, default: "Corrente: "): prefisso sr-only per lo step attivoclasses (stringa, opzionale): classi CSS aggiuntive sul <nav>label (stringa, obbligatorio): testo visibile dello stepcompleted (booleano, opzionale, default: false): segna lo step come completatoactive (booleano, opzionale, default: false): segna lo step come corrente — massimo uno per componentehref (stringa, opzionale): se presente e completed: true, lo step diventa un <a> navigabileicon (stringa, opzionale): ID icona SVG sprite per step completati (solo variante base); default check-solid. Ignorato nella variante numerata.Livello AA — criteri pertinenti:
<nav> landmark + <ol> comunica sequenzialitàaria-current="step" sullo step attivo<nav> — landmark navigation; identificato dall’aria-label configurabile<ol> — lista ordinata; comunica agli screen reader che gli step sono in sequenza<a> — ruolo implicito link; attivabile con Enter; solo per step completati con href<span> — nessun ruolo interattivo; usato per step attivi, futuri e completati senza link<span aria-current="step"> / <a aria-current="step"> — annuncia lo step corrente agli screen reader; posizionato sull’elemento interattivo (.rtds-steps__link), non sul <li>| Attributo | Valori | Condizione |
|---|---|---|
aria-label |
stringa | Sul <nav>; sempre presente |
aria-current |
"step" |
Sul .rtds-steps__link (<a> o <span>) dello step attivo |
aria-hidden |
"true" |
Su .rtds-steps__indicator (decorativo) e .rtds-steps__counter |
<span class="rtds-sr-only">Completato: </span> — prefisso sr-only davanti alla label degli step completati; comunicano lo stato senza dipendere dai colori<span class="rtds-sr-only">Corrente: </span> — prefisso sr-only per lo step attivo; in combinazione con aria-current="step" sul .rtds-steps__link, lo step viene annunciato chiaramentearia-hidden="true" sull’indicatore — icone, cerchi e numeri sono decorativi; lo stato è comunicato dal testo sr-onlyaria-hidden="true" sul contatore mobile — l’informazione è già accessibile tramite la struttura della lista completa.rtds-steps: <nav> wrapper; contiene le variabili triple fallback.rtds-steps--numbered: variante numerata; gli indicatori mostrano il numero progressivo con bordo.rtds-steps__list: <ol> — layout flex orizzontale.rtds-steps__item: <li> — flex colonna; border-bottom come barra visiva di separazione orizzontale.rtds-steps__item--active: step corrente — indicatore cerchio con bordo spesso (var(--spacing-2) = 8px) nel colore active e sfondo bianco (--_steps-indicator-bg), senza icona; label in grassetto; border-bottom nel colore active.rtds-steps__item--completed: step completato — border-bottom nel colore completed; indicatore con bordo e sfondo chiaro.rtds-steps__link: <a> o <span> — flex row centrato con gap; decorazione underline on hover solo sui link.rtds-steps__indicator: contenitore icona/numero/cerchio — sempre presente per tutti gli stati; dimensione fissa --_steps-indicator-size, centrato, forma circolare; cerchio vuoto (solo bordo) per step futuri, con icona o riempito per gli altri stati.rtds-steps__label: testo dello step; grassetto e colore active sullo step corrente.rtds-steps__counter: contatore X / Y; nascosto su desktop, affiancato allo step attivo su mobile (< 640px)Il componente espone variabili CSS per la personalizzazione dal CMS ospitante. Il CMS può sovrascrivere le variabili Tier 1; se non sovrascritte, usano i token semantici del DS.
| Proprietà CSS | Default DS | Descrizione |
|---|---|---|
--steps-color-default |
var(--color-content-03) |
Colore testo e label degli step futuri |
--steps-color-active |
var(--color-content-secondary) |
Colore indicatore e label dello step corrente |
--steps-color-completed |
var(--color-content-secondary) |
Colore indicatore e bordo inferiore degli step completati |
--steps-label-color |
var(--color-content-01) |
Colore delle label |
--steps-indicator-size |
var(--spacing-6) |
Dimensione (larghezza e altezza) dell’indicatore |
--steps-indicator-bg |
var(--color-background-01) |
Sfondo dell’indicatore per step completati |
--steps-indicator-border |
var(--color-border-gray-03) |
Colore del bordo dell’indicatore degli step futuri |
--steps-bar-color |
var(--color-border-gray-03) |
Colore della barra inferiore degli step futuri |
--steps-bar-height |
var(--spacing-1) |
Altezza della barra inferiore |
| Token DS | Fallback primitivo | Descrizione |
|---|---|---|
--color-content-03 |
var(--color-neutral-900) |
Grigio scuro per step futuri |
--color-content-secondary |
var(--color-secondary-500) |
Colore secondario del DS |
--color-content-01 |
var(--color-neutral-900) |
Testo principale |
--spacing-6 |
1.5rem |
Spacing base × 6 — dimensione indicatore |
--color-background-01 |
var(--color-neutral-50) |
Sfondo chiaro per indicatori completati |
--color-border-gray-03 |
var(--color-neutral-600) |
Grigio per bordo indicatore e barra degli step futuri |
--spacing-1 |
0.25rem |
Spacing base × 1 — altezza barra |
<!-- Variante base (cerchi e icone) -->
<nav class="rtds-steps" aria-label="Avanzamento procedura">
<ol class="rtds-steps__list">
<li class="rtds-steps__item rtds-steps__item--completed">
<a href="/step1" class="rtds-steps__link">
<span class="rtds-steps__indicator" aria-hidden="true">
<!-- icona check-solid, 16×16 -->
</span>
<span class="rtds-sr-only">Completato: </span>
<span class="rtds-steps__label">Dati anagrafici</span>
</a>
</li>
<li class="rtds-steps__item rtds-steps__item--active">
<span class="rtds-steps__link" aria-current="step">
<span class="rtds-steps__indicator" aria-hidden="true"></span>
<span class="rtds-sr-only">Corrente: </span>
<span class="rtds-steps__label">Contatti</span>
</span>
</li>
<li class="rtds-steps__item">
<span class="rtds-steps__link">
<span class="rtds-steps__indicator" aria-hidden="true"></span>
<span class="rtds-steps__label">Riepilogo</span>
</span>
</li>
</ol>
<span class="rtds-steps__counter" aria-hidden="true">2 / 3</span>
</nav>
<!-- Variante numerata -->
<nav class="rtds-steps rtds-steps--numbered" aria-label="Avanzamento procedura">
<ol class="rtds-steps__list">
<li class="rtds-steps__item rtds-steps__item--completed">
<span class="rtds-steps__link">
<span class="rtds-steps__indicator" aria-hidden="true">1</span>
<span class="rtds-sr-only">Completato: </span>
<span class="rtds-steps__label">Dati anagrafici</span>
</span>
</li>
<li class="rtds-steps__item rtds-steps__item--active">
<span class="rtds-steps__link" aria-current="step">
<span class="rtds-steps__indicator" aria-hidden="true">2</span>
<span class="rtds-sr-only">Corrente: </span>
<span class="rtds-steps__label">Contatti</span>
</span>
</li>
<li class="rtds-steps__item">
<span class="rtds-steps__link">
<span class="rtds-steps__indicator" aria-hidden="true">3</span>
<span class="rtds-steps__label">Riepilogo</span>
</span>
</li>
</ol>
<span class="rtds-steps__counter" aria-hidden="true">2 / 3</span>
</nav>X / Y) è calcolato interamente in Nunjucks — non richiede JavaScript.<span class="rtds-steps__counter"> è aria-hidden="true" perché la lista completa è già navigabile.icon per-step è ignorato nella variante numerata.active: true per istanza.@icon (variante base, per step completati)