<div class="rtds-container">
<div class="rtds-space-y-6 md:rtds-space-y-8">
<div class="rtds-space-y-4">
<div class="rtds-grid rtds-gap-6 lg:rtds-flex lg:rtds-justify-between">
<div class="rtds-loading-status" aria-live="polite" aria-busy="false" role="status">
<h2 class="rtds-sr-only">Risultati di ricerca</h2>
<span class="rtds-heading-3 rtds-font-normal">
<strong>230</strong> Servizi
</span>
</div>
<div>
<div class="rtds-grid md:rtds-flex md:rtds-items-center rtds-gap-2 md:rtds-gap-6 md:rtds-justify-end">
<div class="rtds-flex-1 md:rtds-flex-none">
<div class="rtds-input-field rtds-select-field rtds-field-inline rtds-select-field--sm">
<label for="select-field-1" class="rtds-input-field__label">
Rivolto a
</label>
<div class="rtds-select rtds-select--light">
<select id="select-field-1" class="">
<option value="1">Text</option>
<option value="2">Option 1</option>
<option value="3">Option 2</option>
<option value="4">Option 3</option>
<option value="5">Option 4</option>
<option value="6">Option 5</option>
</select>
</div>
</div>
</div>
<div class="rtds-flex-1 md:rtds-flex-none">
<div class="rtds-input-field rtds-select-field rtds-field-inline rtds-select-field--sm">
<label for="select-field-2" class="rtds-input-field__label">
Ordina per
</label>
<div class="rtds-select rtds-select--light">
<select id="select-field-2" class="">
<option value="1">Text</option>
<option value="2">Option 1</option>
<option value="3">Option 2</option>
<option value="4">Option 3</option>
<option value="5">Option 4</option>
<option value="6">Option 5</option>
</select>
</div>
</div>
</div>
</div>
</div>
</div>
<!-- CONTAINER PER EMPTY STATE - HA CONTENUTO SOLO SE NON CI SONO RISULTATI - DEVE ESSERE SEMPRE PRESENTE - CON I RISULTATI HA CLASSE -> rtds-sr-only -->
<div class="rtds-empty-state rtds-grid rtds-gap-4 rtds-sr-only" aria-live="assertive" aria-atomic="true"></div>
<div class="rtds-grid rtds-gap-4 rtds-grid-cols-1 md:rtds-grid-cols-2 lg:rtds-grid-cols-3">
<article class="rtds-card rtds-card--information rtds-bg-gradient-04
is-card-fullclickable rtds-group/card">
<div class="rtds-card__content">
<div class="rtds-card__heading">
<h3 class="rtds-card__title">
<a class="group-hover/card:rtds-underline" href="">
Nunc aliquam phasellus molestie blandit. Nisi, amet, id maecenas diam
</a>
</h3>
</div>
<div class="rtds-card__description ">
<p>
Neque blandit pellentesque nunc sed amet. Nisl, semper sed aliquam amet proin purus augue et.
</p>
</div>
<ul class="rtds-card__tags" aria-label="Categorie">
<li><span class="rtds-chip rtds-chip--category rtds-chip--sm">
label</span></li>
<li><span class="rtds-chip rtds-chip--category rtds-chip--sm">
label</span></li>
<li><span class="rtds-chip rtds-chip--category rtds-chip--sm">
label</span></li>
<li><span class="rtds-chip rtds-chip--category rtds-chip--sm">
label</span></li>
</ul>
</div>
</article>
<article class="rtds-card rtds-card--information rtds-bg-gradient-04
is-card-fullclickable rtds-group/card">
<div class="rtds-card__content">
<div class="rtds-card__heading">
<h3 class="rtds-card__title">
<a class="group-hover/card:rtds-underline" href="">
Nunc aliquam phasellus molestie blandit. Nisi, amet, id maecenas diam
</a>
</h3>
</div>
<div class="rtds-card__description ">
<p>
Neque blandit pellentesque nunc sed amet. Nisl, semper sed aliquam amet proin purus augue et.
</p>
</div>
<ul class="rtds-card__tags" aria-label="Categorie">
<li><span class="rtds-chip rtds-chip--category rtds-chip--sm">
label</span></li>
<li><span class="rtds-chip rtds-chip--category rtds-chip--sm">
label</span></li>
<li><span class="rtds-chip rtds-chip--category rtds-chip--sm">
label</span></li>
<li><span class="rtds-chip rtds-chip--category rtds-chip--sm">
label</span></li>
</ul>
</div>
</article>
<article class="rtds-card rtds-card--information rtds-bg-gradient-04
is-card-fullclickable rtds-group/card">
<div class="rtds-card__content">
<div class="rtds-card__heading">
<h3 class="rtds-card__title">
<a class="group-hover/card:rtds-underline" href="">
Nunc aliquam phasellus molestie blandit. Nisi, amet, id maecenas diam
</a>
</h3>
</div>
<div class="rtds-card__description ">
<p>
Neque blandit pellentesque nunc sed amet. Nisl, semper sed aliquam amet proin purus augue et.
</p>
</div>
<ul class="rtds-card__tags" aria-label="Categorie">
<li><span class="rtds-chip rtds-chip--category rtds-chip--sm">
label</span></li>
<li><span class="rtds-chip rtds-chip--category rtds-chip--sm">
label</span></li>
<li><span class="rtds-chip rtds-chip--category rtds-chip--sm">
label</span></li>
<li><span class="rtds-chip rtds-chip--category rtds-chip--sm">
label</span></li>
</ul>
</div>
</article>
<article class="rtds-card rtds-card--information rtds-bg-gradient-04
is-card-fullclickable rtds-group/card">
<div class="rtds-card__content">
<div class="rtds-card__heading">
<h3 class="rtds-card__title">
<a class="group-hover/card:rtds-underline" href="">
Nunc aliquam phasellus molestie blandit. Nisi, amet, id maecenas diam
</a>
</h3>
</div>
<div class="rtds-card__description ">
<p>
Neque blandit pellentesque nunc sed amet. Nisl, semper sed aliquam amet proin purus augue et.
</p>
</div>
<ul class="rtds-card__tags" aria-label="Categorie">
<li><span class="rtds-chip rtds-chip--category rtds-chip--sm">
label</span></li>
<li><span class="rtds-chip rtds-chip--category rtds-chip--sm">
label</span></li>
<li><span class="rtds-chip rtds-chip--category rtds-chip--sm">
label</span></li>
<li><span class="rtds-chip rtds-chip--category rtds-chip--sm">
label</span></li>
</ul>
</div>
</article>
<article class="rtds-card rtds-card--information rtds-bg-gradient-04
is-card-fullclickable rtds-group/card">
<div class="rtds-card__content">
<div class="rtds-card__heading">
<h3 class="rtds-card__title">
<a class="group-hover/card:rtds-underline" href="">
Nunc aliquam phasellus molestie blandit. Nisi, amet, id maecenas diam
</a>
</h3>
</div>
<div class="rtds-card__description ">
<p>
Neque blandit pellentesque nunc sed amet. Nisl, semper sed aliquam amet proin purus augue et.
</p>
</div>
<ul class="rtds-card__tags" aria-label="Categorie">
<li><span class="rtds-chip rtds-chip--category rtds-chip--sm">
label</span></li>
<li><span class="rtds-chip rtds-chip--category rtds-chip--sm">
label</span></li>
<li><span class="rtds-chip rtds-chip--category rtds-chip--sm">
label</span></li>
<li><span class="rtds-chip rtds-chip--category rtds-chip--sm">
label</span></li>
</ul>
</div>
</article>
<article class="rtds-card rtds-card--information rtds-bg-gradient-04
is-card-fullclickable rtds-group/card">
<div class="rtds-card__content">
<div class="rtds-card__heading">
<h3 class="rtds-card__title">
<a class="group-hover/card:rtds-underline" href="">
Nunc aliquam phasellus molestie blandit. Nisi, amet, id maecenas diam
</a>
</h3>
</div>
<div class="rtds-card__description ">
<p>
Neque blandit pellentesque nunc sed amet. Nisl, semper sed aliquam amet proin purus augue et.
</p>
</div>
<ul class="rtds-card__tags" aria-label="Categorie">
<li><span class="rtds-chip rtds-chip--category rtds-chip--sm">
label</span></li>
<li><span class="rtds-chip rtds-chip--category rtds-chip--sm">
label</span></li>
<li><span class="rtds-chip rtds-chip--category rtds-chip--sm">
label</span></li>
<li><span class="rtds-chip rtds-chip--category rtds-chip--sm">
label</span></li>
</ul>
</div>
</article>
</div>
</div>
<nav class="rtds-pagination rtds-flex-wrap rtds-justify-center" role="navigation" aria-label="Paginazione">
<ul class="rtds-pagination__list rtds-justify-center">
<li>
<a class="rtds-pagination__link rtds-pagination__link-button " href="#" aria-label="Prima pagina">
<svg class="rtds-icon rtds-fill-current rtds-w-4 rtds-h-5 md:rtds-w-5 md:rtds-h-5" aria-hidden="true" focusable="false" role="img">
<use href="../../icons.svg#mini--chevron-double-left" />
</svg>
</a>
</li>
<li>
<a class="rtds-pagination__link rtds-pagination__link-button" href="#" aria-label="Pagina precedente">
<svg class="rtds-icon rtds-fill-current rtds-w-4 rtds-h-5 md:rtds-w-5 md:rtds-h-5" aria-hidden="true" focusable="false" role="img">
<use href="../../icons.svg#mini--chevron-left" />
</svg>
</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-button" href="#" aria-label="Pagina successiva">
<svg class="rtds-icon rtds-fill-current rtds-w-4 rtds-h-5 md:rtds-w-5 md:rtds-h-5" aria-hidden="true" focusable="false" role="img">
<use href="../../icons.svg#mini--chevron-right" />
</svg>
</a>
</li>
<li>
<a class="rtds-pagination__link rtds-pagination__link-button " href="#" aria-label="Ultima pagina">
<svg class="rtds-icon rtds-fill-current rtds-w-4 rtds-h-5 md:rtds-w-5 md:rtds-h-5" aria-hidden="true" focusable="false" role="img">
<use href="../../icons.svg#mini--chevron-double-right" />
</svg>
</a>
</li>
</ul>
</nav>
</div>
</div>
{% if hasContainer %}
<div class="rtds-container">
{% endif %}
<div class="rtds-space-y-6 md:rtds-space-y-8{% if padding %} rtds-py-6{% endif %}">
<div class="rtds-space-y-4">
{% block filters %}
{% if filtersSelected %}
<div class="rtds-pb-6">
{% render '@filters--v2-selected', true %}
</div>
{% endif %}
{% endblock filters %}
<div class="rtds-grid rtds-gap-6 lg:rtds-flex lg:rtds-justify-between">
<div class="rtds-loading-status" aria-live="polite" aria-busy="{{ ariaBusy }}" role="status">
{% block title %}
{% if srOnlyTitle %}
<h2 class="rtds-sr-only">Risultati di ricerca</h2>
<span class="rtds-heading-3 rtds-font-normal">
{{ title|safe }}
</span>
{% else %}
<h2 class="rtds-heading-3 rtds-font-normal">
{{ title|safe }}
</h2>
{% endif %}
{% endblock title %}
</div>
{% block rightContent %}
{% if sorting or mobileFilters or rightContent %}
<div{% if ariaBusy == true %} class="rtds-hidden"{% endif %}>
{% block rightContentInner %}
{% if sorting %}
<div class="rtds-grid md:rtds-flex md:rtds-items-center rtds-gap-2 md:rtds-gap-6 md:rtds-justify-end">
<div class="rtds-flex-1 md:rtds-flex-none">
{% render '@select-field--sm',{label: 'Rivolto a', selectId: 'select-field-1', inline: 'true', variant: '--light' }, true %}
</div>
<div class="rtds-flex-1 md:rtds-flex-none">
{% render '@select-field--sm',{label: 'Ordina per', selectId: 'select-field-2', inline: 'true', variant: '--light' }, true %}
</div>
</div>
{% endif %}
{% if mobileFilters %}
<div class="rtds-pt-6 lg:rtds-hidden">
{% render '@button--icon-left', {
icon: 'mini--adjustments-horizontal',
iconTransformType: 'scale',
classes: 'rtds-btn--inverted',
label: 'Filtra la ricerca',
callback: 'openDialog("mobileFilters", this)',
ariaControls: 'mobileFilters',
ariaHasPopup: 'dialog',
ariaExpanded: true
}, true %}
{% render '@modal-dialog--filters', {dialogId: 'mobileFilters'}, true %}
</div>
{% endif %}
{% endblock rightContentInner %}
</div>
{% endif %}
{% endblock rightContent %}
</div>
<!-- CONTAINER PER EMPTY STATE - HA CONTENUTO SOLO SE NON CI SONO RISULTATI - DEVE ESSERE SEMPRE PRESENTE - CON I RISULTATI HA CLASSE -> rtds-sr-only -->
<div class="rtds-empty-state rtds-grid rtds-gap-4{% if emptyState == false %} rtds-sr-only{% endif %}" aria-live="assertive" aria-atomic="true">
{%- block emptyState -%}
{%- endblock emptyState -%}
</div>
{% block results %}
<div class="rtds-grid rtds-gap-4 rtds-grid-cols-1{% if resultsGridClasses %} {{ resultsGridClasses }}{% endif %}">
{% for i in range(0, resultsCount) %}
{% render '@card' + resultsCard.variant, resultsCard.context, true %}
{% endfor %}
</div>
{% endblock results %}
</div>
{% block pagination %}
{% render '@pagination--centered' %}
{% endblock pagination %}
</div>
{% if hasContainer %}
</div>
{% endif %}
{
"ariaBusy": false,
"srOnlyTitle": true,
"emptyState": false,
"sorting": true,
"resultsCount": 6,
"title": "<strong>230</strong> Servizi",
"resultsGridClasses": "md:rtds-grid-cols-2 lg:rtds-grid-cols-3",
"resultsCard": {
"variant": "--information-with-gradient"
},
"hasContainer": true
}
.rtds-loading-status[aria-busy="true"] {
width: 100%;
}
@layer components {
.rtds-loading-status[aria-busy="true"] {
@apply rtds-w-full;
}
}
Area dei risultati di ricerca con intestazione contatore, griglia di card, paginazione e gestione degli stati di caricamento, vuoto e filtri selezionati.
Il componente è renderizzato come <div class="rtds-space-y-6 md:rtds-space-y-8">. Può essere avvolto in <div class="rtds-container"> se hasContainer: true.
Contiene, nell’ordine:
@filters--v2-selected) — visibile solo se filtersSelected: true<div class="rtds-loading-status">) con aria-live, aria-busy e role="status"<h2> visibile (o rtds-sr-only se srOnlyTitle: true) + <span> con contatore visuale@select-field--sm) e/o pulsante filtri mobile + dialog — visibili se sorting / mobileFilters: trueemptyState: true, altrimenti rtds-sr-only@card + variante) — ripetuta resultsCount volte@pagination--centered)--loading, --empty-state)Le varianti loading e empty-state estendono @search-results sovrascrivendo blocchi specifici:
search-results--loading.njk — sostituisce il blocco title con spinner + heading “Caricamento risultati…”; svuota i blocchi results e paginationsearch-results--empty-state.njk — sostituisce il blocco title con “Nessun risultato trovato”; popola il blocco emptyState con icona e messaggio; svuota results e paginationdefault: Griglia con sorting, senza filtri mobilihas-container: Aggiunge rtds-container attorno all’intera areahas-padding: Aggiunge padding verticale rtds-py-6has-mobile-filters: Mostra il pulsante “Filtra la ricerca” su mobile con dialog modalehas-filters-selected: Come has-mobile-filters con la barra @filters--v2-selected visibileloading: Spinner di caricamento, nessuna card né paginazioneempty-state: Messaggio “Nessun risultato trovato”, nessuna card né paginazioneContesto di sviluppo Fractal/Nunjucks — parametri del context
.config.yml. Non descrivono attributi HTML da usare nei CMS o ambienti di implementazione.
ariaBusy (booleano, opzionale): Valore di aria-busy sul contenitore .rtds-loading-status. Default: falsesrOnlyTitle (booleano, opzionale): Se true, l’<h2> del contatore è nascosto visivamente (rtds-sr-only) e il contatore è mostrato in uno <span>. Default: trueemptyState (booleano, opzionale): Se true, mostra il contenitore .rtds-empty-state (rimuove rtds-sr-only). Default: falsetitle (stringa, opzionale): HTML del titolo risultati, accetta markup (filtro safe). Default: '<strong>230</strong> Servizi'resultsCount (numero, opzionale): Numero di card da iterare nella griglia. Default: 6hasContainer (booleano, opzionale): Avvolge l’intera area in <div class="rtds-container">. Default: non impostatopadding (booleano, opzionale): Aggiunge rtds-py-6 alla sezione. Default: non impostatoresultsGridClasses (stringa, opzionale): Classi Tailwind per la griglia risultati. Default: 'md:rtds-grid-cols-2 lg:rtds-grid-cols-3'resultsCard.variant (stringa, opzionale): Suffisso variante della card da renderizzare (es. '--information-with-gradient', '--information-02', '--news-small'). Default: '--information-with-gradient'resultsCard.context (oggetto, opzionale): Context aggiuntivo passato al componente @cardsorting (booleano, opzionale): Mostra i due @select-field--sm per ordinamento. Default: truemobileFilters (booleano, opzionale): Mostra il pulsante “Filtra la ricerca” e il dialog @modal-dialog--filters. Default: non impostatofiltersSelected (booleano, opzionale): Mostra la barra @filters--v2-selected con i filtri attivi. Default: non impostatoLivello AA — criteri pertinenti:
aria-live="polite" sul contenitore .rtds-loading-status annuncia aggiornamenti risultati; aria-live="assertive" sul contenitore .rtds-empty-state annuncia immediatamente la mancanza di risultatiaria-busy gestisce lo stato di caricamento; role="status" identifica l’area di stato; aria-controls, aria-haspopup, aria-expanded sul pulsante filtri mobile<h2> per il titolo della sezione risultati; gerarchia heading mantenuta in tutti gli stati.rtds-loading-status con aria-live="polite", aria-busy, role="status" — annuncia aggiornamenti risultati in modo non interruttivo.rtds-empty-state con aria-live="assertive", aria-atomic="true" — annuncia immediatamente la transizione allo stato vuoto; è sempre presente nel DOM, nascosto con rtds-sr-only quando non attivo<h2> con rtds-sr-only (se srOnlyTitle: true) — accessibile agli screen reader ma nascosto visivamente; affiancato da <span> con il contatore visuale@modal-dialog--filters gestisce internamente role="dialog", aria-modal, aria-labelledby e focus trap| Attributo | Valori | Condizione |
|---|---|---|
aria-live |
polite |
Su .rtds-loading-status — sempre presente |
aria-busy |
true / false |
Su .rtds-loading-status — riflette il parametro ariaBusy |
role |
status |
Su .rtds-loading-status — sempre presente |
aria-live |
assertive |
Su .rtds-empty-state — sempre presente |
aria-atomic |
true |
Su .rtds-empty-state — sempre presente |
aria-controls |
"mobileFilters" |
Sul pulsante filtri mobile — quando mobileFilters: true |
aria-haspopup |
dialog |
Sul pulsante filtri mobile — quando mobileFilters: true |
aria-expanded |
true |
Sul pulsante filtri mobile — quando mobileFilters: true |
| Tasto | Azione |
|---|---|
Tab |
Raggiunge i select di ordinamento, il pulsante filtri mobile, le card, la paginazione |
Enter / Space |
Apre il dialog filtri mobile (pulsante) |
Escape |
Chiude il dialog filtri mobile (gestito da @modal-dialog--filters) |
@modal-dialog--filtersaria-busy="true" sull’elemento con role="status" — lo screen reader segnala che il contenuto è in aggiornamentoaria-busy passa a false, aria-live="polite" annuncia il nuovo contatore risultati.rtds-empty-state perde rtds-sr-only, aria-live="assertive" annuncia immediatamente il messaggio@card usato.rtds-loading-status: Contenitore del titolo e contatore risultati; con [aria-busy="true"] si espande a rtds-w-full.rtds-empty-state: Contenitore del messaggio stato vuoto; sempre nel DOM, nascosto con rtds-sr-only quando emptyState: false<!-- Stato predefinito: griglia 2–3 colonne con card information-with-gradient -->
<div class="rtds-space-y-6 md:rtds-space-y-8">
<div class="rtds-space-y-4">
<div class="rtds-loading-status" aria-live="polite" aria-busy="false" role="status">
<h2 class="rtds-sr-only">Risultati di ricerca</h2>
<span class="rtds-heading-3 rtds-font-normal"><strong>230</strong> Servizi</span>
</div>
<div class="rtds-empty-state rtds-grid rtds-gap-4 rtds-sr-only" aria-live="assertive" aria-atomic="true"></div>
<div class="rtds-grid rtds-gap-4 rtds-grid-cols-1 md:rtds-grid-cols-2 lg:rtds-grid-cols-3">
<!-- @card--information-with-gradient × resultsCount -->
</div>
</div>
<!-- @pagination--centered -->
</div>
<!-- Stato di caricamento (ariaBusy: true) -->
<div class="rtds-loading-status" aria-live="polite" aria-busy="true" role="status">
<div class="rtds-loading-results ...">
<!-- @icon spinner -->
<h2 class="rtds-heading-3">Caricamento risultati...</h2>
</div>
</div>
<!-- Stato vuoto (emptyState: true) -->
<div class="rtds-empty-state rtds-grid rtds-gap-4" aria-live="assertive" aria-atomic="true">
<!-- @icon outline--exclamation-circle -->
<h3 class="rtds-heading-4">Non ci sono risultati per questi criteri di ricerca</h3>
</div>@search-box o @search-results-header)loading, empty-state) sono: {% block filters %}, {% block title %}, {% block rightContent %}, {% block rightContentInner %}, {% block emptyState %}, {% block results %}, {% block pagination %}aria-busy, la classe rtds-sr-only sull’elemento .rtds-empty-state e la visibilità della griglia risultati@filters--v2-selected, @select-field--sm, @button--icon-left, @modal-dialog--filters, @card (+ variante), @pagination--centered