<div class="rtds-upload rtds-w-full rtds-space-y-5 md:rtds-space-y-6">
    <!-- Pulsante principale per il caricamento -->
    <div class="rtds-upload__button-area rtds-flex rtds-flex-col rtds-p-4 rtds-items-center rtds-justify-center rtds-gap-4 md:rtds-gap-6 rtds-background-01 rtds-border-dashed rtds-border-gray-03 rtds-border-2 rtds-rounded-md">
        <div class="rtds-upload__description rtds-space-y-1.5">
            <!-- 
            note per accessibilità: il seguente paragrafo NON fornisce informazioni aggiuntive chi usa tecnologie assistive
            così come è formulato è riferito all'esperienza utente che usa un mouse ecc (non tastiera o screen reader).
            Inoltre fornisce indicazioni per la localizzazione del pulsante tramite posizionamento del pulsante stesso ("clicca sul pulsante qui sotto")
            violando così il criterio di successo WCAG 1.3.3 -->

            <p class="rtds-upload__help">Clicca il pulsante qui sotto per caricare i documenti dal tuo dispositivo.</p>
            <!-- note per accessibilità: il seguente paragrafo fornisce informazioni aggiuntive chi usa tecnologie assistive
             attraverso l'uso dell'id e dell'attributo aria-describedby="id-del-paragrafo" sull'input file-->
            <p id="upload-help-text" class="rtds-upload__help">Formati <strong>PDF, DOCX, JPG, PNG</strong> - Max: <strong>10 MB per file</strong></p>
        </div>
        <input type="file" id="upload-input-file-upload-default" class="rtds-upload__input rtds-sr-only" aria-describedby="upload-help-text" multiple accept="image/*,.pdf,.doc,.docx">
        <label for="upload-input-file-upload-default" class="rtds-upload__button rtds-btn rtds-btn--outlined rtds-content-01 rtds-border-gray-03 rtds-cursor-pointer">
            <svg class="rtds-icon rtds-fill-current rtds-w-5 rtds-h-5" aria-hidden="true" focusable="false" role="img">
                <use href="../../icons.svg#outline--arrow-up-on-square" />
            </svg>

            Carica file
        </label>
    </div>

    <!-- Lista dei file caricati/in caricamento -->

    <ul class="rtds-upload__file-list">

        <li class="rtds-upload__file">
            <div class="rtds-file is-loading" id="file-1">
                <!-- Icona del file -->
                <svg class="rtds-icon rtds-fill-current rtds-w-6 rtds-h-6 md:rtds-w-8 md:rtds-h-8 rtds-file__icon rtds-flex-shrink-0" aria-hidden="true" focusable="false" role="img">
                    <use href="../../icons.svg#outline--document-text" />
                </svg>

                <div class="rtds-file__info">
                    <!-- Informazioni del file -->
                    <p class="rtds-file__name rtds-text-sm rtds-font-bold rtds-mb-1">documento-caricamento.pdf</p>
                    <!-- Barra di progresso (per stati loading) -->

                    <div class="rtds-file__progress">
                        <div class="rtds-file__progress-bar" role="progressbar" style="--file-progress-bar-width: 65%" aria-valuenow="65" aria-valuemin="0" aria-valuemax="100">
                        </div>
                    </div>

                    <p class="rtds-file__status" aria-live="polite">

                        <span class="rtds-sr-only">

                            Caricamento file in corso: documento-caricamento.pdf -

                        </span>

                        <span class="rtds-file__weight rtds-text-xs rtds-font-medium">1MB di 2.1MB</span>

                    </p>

                </div>
                <!-- Azioni in base allo stato -->

                <!-- Loading: solo pulsante cancella -->
                <button type="button" class="rtds-btn 
    rtds-btn--icon rtds-btn--outlined rtds-border-none rtds-flex-shrink-0 rtds-content-01"><svg class="rtds-icon rtds-fill-current rtds-w-6 rtds-h-6" aria-hidden="true" focusable="false" role="img">
                        <use href="../../icons.svg#outline--x-circle" />
                    </svg>
                    <span class="rtds-sr-only">

                        Annulla caricamento file documento-caricamento.pdf
                    </span>

                </button>

            </div>
        </li>

        <li class="rtds-upload__file">
            <div class="rtds-file is-loading-error" id="file-2">
                <!-- Icona del file -->
                <svg class="rtds-icon rtds-fill-current rtds-w-6 rtds-h-6 md:rtds-w-8 md:rtds-h-8 rtds-file__icon rtds-flex-shrink-0" aria-hidden="true" focusable="false" role="img">
                    <use href="../../icons.svg#outline--document-text" />
                </svg>

                <div class="rtds-file__info">
                    <!-- Informazioni del file -->
                    <p class="rtds-file__name rtds-text-sm rtds-font-bold rtds-mb-1">documento-errore.docx</p>
                    <!-- Barra di progresso (per stati loading) -->

                    <div class="rtds-file__progress">
                        <div class="rtds-file__progress-bar" role="progressbar" style="--file-progress-bar-width: 30%" aria-valuenow="30" aria-valuemin="0" aria-valuemax="100">
                        </div>
                    </div>

                    <p class="rtds-file__status" aria-live="polite">

                        <span class="rtds-sr-only">

                            Errore caricamento file: documento-errore.docx -

                        </span>

                        <span class="rtds-file__weight rtds-text-xs rtds-font-medium">15MB</span>

                        <!-- Messaggio di errore -->
                        <span class="rtds-file__error rtds-text-xs rtds-font-bold rtds-content-error">
                            File troppo grande. Dimensione massima: 10MB
                        </span>

                    </p>

                </div>
                <!-- Azioni in base allo stato -->

                <!-- Loading Error: icona errore + pulsante cancella -->
                <div class="rtds-flex rtds-items-center rtds-gap-2">
                    <svg class="rtds-icon rtds-fill-current rtds-w-6 rtds-h-6 rtds-text-error" aria-hidden="true" focusable="false" role="img">
                        <use href="../../icons.svg#outline--exclamation-circle" />
                    </svg>

                    <button type="button" class="rtds-btn 
    rtds-btn--icon rtds-btn--outlined rtds-border-none rtds-flex-shrink-0 rtds-content-01"><svg class="rtds-icon rtds-fill-current rtds-w-6 rtds-h-6" aria-hidden="true" focusable="false" role="img">
                            <use href="../../icons.svg#outline--x-circle" />
                        </svg>
                        <span class="rtds-sr-only">

                            Annulla caricamento file documento-errore.docx
                        </span>

                    </button>

                </div>

            </div>
        </li>

        <li class="rtds-upload__file">
            <div class="rtds-file is-loading-completed" id="file-3">
                <!-- Icona del file -->
                <svg class="rtds-icon rtds-fill-current rtds-w-6 rtds-h-6 md:rtds-w-8 md:rtds-h-8 rtds-file__icon rtds-flex-shrink-0" aria-hidden="true" focusable="false" role="img">
                    <use href="../../icons.svg#outline--document-text" />
                </svg>

                <div class="rtds-file__info">
                    <!-- Informazioni del file -->
                    <p class="rtds-file__name rtds-text-sm rtds-font-bold rtds-mb-1">documento-completato.jpg</p>
                    <!-- Barra di progresso (per stati loading) -->

                    <div class="rtds-file__progress">
                        <div class="rtds-file__progress-bar" role="progressbar" style="--file-progress-bar-width: 100%" aria-valuenow="100" aria-valuemin="0" aria-valuemax="100">
                        </div>
                    </div>

                    <p class="rtds-file__status" aria-live="polite">

                        <span class="rtds-sr-only">

                            Caricamento file completato: documento-completato.jpg -

                        </span>

                        <span class="rtds-file__weight rtds-text-xs rtds-font-medium">850KB</span>

                    </p>

                </div>
                <!-- Azioni in base allo stato -->

                <!-- Loading Completed: icona check + pulsante cancella -->
                <div class="rtds-flex rtds-items-center rtds-gap-2">
                    <svg class="rtds-icon rtds-fill-current rtds-w-6 rtds-h-6 rtds-text-success" aria-hidden="true" focusable="false" role="img">
                        <use href="../../icons.svg#outline--check-circle" />
                    </svg>

                    <button type="button" class="rtds-btn 
    rtds-btn--icon rtds-btn--outlined rtds-border-none rtds-flex-shrink-0 rtds-content-01"><svg class="rtds-icon rtds-fill-current rtds-w-6 rtds-h-6" aria-hidden="true" focusable="false" role="img">
                            <use href="../../icons.svg#outline--x-circle" />
                        </svg>
                        <span class="rtds-sr-only">

                            Annulla caricamento file documento-completato.jpg
                        </span>

                    </button>

                </div>

            </div>
        </li>

        <li class="rtds-upload__file">
            <div class="rtds-file is-download" id="file-4">
                <!-- Icona del file -->
                <svg class="rtds-icon rtds-fill-current rtds-w-6 rtds-h-6 md:rtds-w-8 md:rtds-h-8 rtds-file__icon rtds-flex-shrink-0" aria-hidden="true" focusable="false" role="img">
                    <use href="../../icons.svg#outline--document-text" />
                </svg>

                <div class="rtds-file__info">
                    <!-- Informazioni del file -->
                    <p class="rtds-file__name rtds-text-sm rtds-font-bold rtds-mb-1">documento-scaricabile.pdf</p>
                    <!-- Barra di progresso (per stati loading) -->

                    <p class="rtds-file__status" aria-live="polite">

                        <span class="rtds-sr-only">

                        </span>

                        <span class="rtds-file__weight rtds-text-xs rtds-font-medium">1.8MB</span>

                    </p>

                </div>
                <!-- Azioni in base allo stato -->

                <!-- Download: pulsante scarica + pulsante elimina -->
                <div class="rtds-flex rtds-items-center rtds-gap-2">

                    <button type="button" class="rtds-btn 
    rtds-btn--icon rtds-btn--outlined rtds-border-none rtds-flex-shrink-0 rtds-content-01"><svg class="rtds-icon rtds-fill-current rtds-w-6 rtds-h-6" aria-hidden="true" focusable="false" role="img">
                            <use href="../../icons.svg#outline--arrow-down-tray" />
                        </svg>
                        <span class="rtds-sr-only">

                            Scarica il file documento-scaricabile.pdf
                        </span>

                    </button>

                    <button type="button" class="rtds-btn 
    rtds-btn--icon rtds-btn--outlined rtds-border-none rtds-flex-shrink-0 rtds-content-01"><svg class="rtds-icon rtds-fill-current rtds-w-6 rtds-h-6" aria-hidden="true" focusable="false" role="img">
                            <use href="../../icons.svg#outline--trash" />
                        </svg>
                        <span class="rtds-sr-only">

                            Elimina il file documento-scaricabile.pdf
                        </span>

                    </button>

                </div>

            </div>
        </li>

    </ul>

</div>
<div class="rtds-upload rtds-w-full rtds-space-y-5 md:rtds-space-y-6">
  <!-- Pulsante principale per il caricamento -->
  <div class="rtds-upload__button-area rtds-flex rtds-flex-col rtds-p-4 rtds-items-center rtds-justify-center rtds-gap-4 md:rtds-gap-6 rtds-background-01 rtds-border-dashed rtds-border-gray-03 rtds-border-2 rtds-rounded-md">
      <div class="rtds-upload__description rtds-space-y-1.5">
            <!-- 
            note per accessibilità: il seguente paragrafo NON fornisce informazioni aggiuntive chi usa tecnologie assistive
            così come è formulato è riferito all'esperienza utente che usa un mouse ecc (non tastiera o screen reader).
            Inoltre fornisce indicazioni per la localizzazione del pulsante tramite posizionamento del pulsante stesso ("clicca sul pulsante qui sotto")
            violando così il criterio di successo WCAG 1.3.3 -->

            <p class="rtds-upload__help">Clicca il pulsante qui sotto per caricare i documenti dal tuo dispositivo.</p>
            <!-- note per accessibilità: il seguente paragrafo fornisce informazioni aggiuntive chi usa tecnologie assistive
             attraverso l'uso dell'id e dell'attributo aria-describedby="id-del-paragrafo" sull'input file-->
            <p id="upload-help-text" class="rtds-upload__help">Formati <strong>PDF, DOCX, JPG, PNG</strong> - Max: <strong>10 MB per file</strong></p>
      </div>
      <input 
      type="file" 
      id="upload-input-{{ 'file-upload-' + (loop.index if loop.index is defined else 'default') }}"
      class="rtds-upload__input rtds-sr-only" 
      aria-describedby="upload-help-text"
      {% if multiple %}multiple{% endif %}
      {% if accept %}accept="{{ accept }}"{% endif %}
    >
    <label for="upload-input-{{ 'file-upload-' + (loop.index if loop.index is defined else 'default') }}" class="rtds-upload__button rtds-btn rtds-btn--outlined rtds-content-01 rtds-border-gray-03 rtds-cursor-pointer">
      {% render '@icon', {
        id: 'outline--arrow-up-on-square',
        size: 'rtds-w-5 rtds-h-5'
      }, true %}
      {{ label or 'Carica file' }}
    </label>
  </div>

  <!-- Lista dei file caricati/in caricamento -->
  {% if files and files.length > 0 %}
    <ul class="rtds-upload__file-list">
      {% for file in files %}
        <li class="rtds-upload__file">
          {% render '@file' + file.variant, file.context, true %}
        </li>
      {% endfor %}
    </ul>
  {% endif %}
</div>
{
  "label": "Carica file",
  "multiple": true,
  "accept": "image/*,.pdf,.doc,.docx",
  "helpText": "Formato supportati: JPG, PNG, PDF, DOC, DOCX. Dimensione massima: 10MB per file.",
  "maxFileSize": "10MB",
  "files": [
    {
      "variant": "--loading",
      "context": {
        "id": "1"
      }
    },
    {
      "variant": "--loading-error",
      "context": {
        "id": "2"
      }
    },
    {
      "variant": "--loading-completed",
      "context": {
        "id": "3"
      }
    },
    {
      "variant": "--download",
      "context": {
        "id": "4"
      }
    }
  ]
}
  • Content:
    /**
     * UPLOAD COMPONENT
     * Componente per il caricamento file
     */
    
    @layer components {
    
      .rtds-upload__button {
        @apply focus-visible:rtds-ring focus-visible:rtds-ring-offset-2 focus-visible:rtds-ring-offset-white focus-visible:rtds-ring-focusring focus-visible:rtds-shadow-[0_0_0_7px_rgba(255,255,255,1)] focus-visible:rtds-outline-none;
      }
    
      .rtds-upload__input:focus + .rtds-upload__button,
      .rtds-upload__input:focus-visible + .rtds-upload__button {
        @apply rtds-ring rtds-ring-offset-2 rtds-ring-offset-white rtds-ring-focusring rtds-shadow-[0_0_0_7px_rgba(255,255,255,1)] rtds-outline-none;
      }
    
      .rtds-upload__description {
        @apply rtds-text-sm md:rtds-text-base rtds-text-center rtds-content-03;
      }
    
    
      /* Lista file - Struttura ul/li */
      .rtds-upload__file-list {
        @apply rtds-list-none rtds-p-0 rtds-m-0 rtds-space-y-3;
      }
    }
  • URL: /components/raw/upload/upload.css
  • Filesystem Path: components/08-servizi/upload/upload.css
  • Size: 854 Bytes

Componente Upload File

Componente per il caricamento di file basato sul Design System di Designers Italia, variante “Lista file” con rappresentazione statica degli stati.

Descrizione

Il componente Upload è un organismo che permette la rappresentazione dell’interfaccia di caricamento file con una struttura semantica ul/li seguendo esattamente le specifiche di Designers Italia. Il componente mostra diversi stati dei file (successo, caricamento, errore) in modo puramente visuale.

Quando Usarlo

Utilizza questo componente quando è necessario mostrare l’interfaccia di caricamento file, come:

  • Form di registrazione o profili utente per foto del profilo
  • Richieste di servizi online che prevedono allegati
  • Piattaforme di condivisione contenuti
  • Form di supporto tecnico con screenshot
  • Qualsiasi contesto che richiede raccolta di documenti

Caratteristiche Principali

Struttura HTML

  • Lista semantica: Utilizza <ul class="upload-file-list"> e <li class="upload-file">
  • Accessibilità: Testo nascosto con rtds-sr-only per screen reader
  • Stati visivi: Classi per success, uploading, error
  • Icone SVG: Supporto per sprite SVG

Stati Supportati (tramite componente File)

  • loading: File in caricamento con progress bar e pulsante cancella
  • loading-error: Errore durante caricamento con icona errore e messaggio
  • loading-completed: Caricamento completato con icona check
  • download: File disponibile con pulsanti scarica ed elimina

Componente File

Il componente Upload utilizza il componente File separato (@file) per gestire la rappresentazione di ogni singolo file. Consulta la documentazione del componente File per maggiori dettagli sui parametri e comportamenti specifici.

Comportamento

Il componente è puramente rappresentativo e non include logica JavaScript. Mostra stati statici definiti nella configurazione. La lista dei file utilizza il componente separato @file per ogni elemento.

Ogni file viene renderizzato tramite il componente File che supporta i seguenti stati:

  • loading: File in caricamento
  • loading-error: Errore durante caricamento
  • loading-completed: Caricamento completato
  • download: File disponibile per download

Accessibilità

Il componente rispetta le linee guida WCAG 2.1:

  • Navigazione da tastiera: Tutti gli elementi sono accessibili
  • Screen reader: Span rtds-sr-only per contesto
  • Semantica: Lista HTML semantica
  • Stati ARIA: Attributi appropriati per progress bar
  • Focus management: Focus chiaramente visibile

Configurazioni - Sviluppo in Nunjucks

Parametri Principali

label (string)

  • Descrizione: Testo del pulsante di caricamento
  • Default: “Carica file”
  • Esempio: label: "Carica documenti"

multiple (boolean)

  • Descrizione: Permette caricamento multiplo
  • Default: true
  • Esempio: multiple: false

accept (string)

  • Descrizione: Tipi di file accettati
  • Default: "image/*,.pdf,.doc,.docx"
  • Esempi:
    • Solo immagini: "image/*"
    • Solo PDF: ".pdf"
    • Documenti: ".pdf,.doc,.docx,.txt"

helpText (string)

  • Descrizione: Testo di aiuto sotto il pulsante
  • Default: Informazioni sui formati supportati
  • Esempio: helpText: "Dimensione massima: 5MB per file"

maxFileSize (string)

  • Descrizione: Dimensione massima per file (solo informativo)
  • Default: "10MB"
  • Esempi: "5MB", "2GB", "500KB"

files (array)

  • Descrizione: Lista di file da mostrare (utilizza componente File)
  • Struttura:
    files:
      - name: "documento.pdf"
        size: "1.2MB"
        status: "loading-completed" # loading, loading-error, loading-completed, download
        progress: 100 # obbligatorio per stati loading
        errorMessage: "Messaggio di errore" # solo per loading-error

Varianti Disponibili

1. Default

context:
  label: 'Carica documenti'
  • Componente base senza file mostrati

2. Con File in Diversi Stati

context:
  files:
    - name: 'documento-caricamento.pdf'
      size: '2.1MB'
      status: 'loading'
      progress: 65
    - name: 'file-completato.jpg'
      size: '850KB'
      status: 'loading-completed'
      progress: 100
    - name: 'file-errore.pdf'
      size: '15MB'
      status: 'loading-error'
      progress: 30
      errorMessage: 'File troppo grande. Max 10MB'
    - name: 'documento-download.docx'
      size: '2.1MB'
      status: 'download'
  • Mostra tutti gli stati del componente File

Stili CSS

Classi Principali

  • .rtds-upload: Container principale
  • .rtds-upload__button-area: Area pulsante di caricamento
  • .rtds-upload__button: Pulsante di caricamento
  • .rtds-upload__file-list: Lista file (ul)

Le classi per i singoli file sono gestite dal componente File:

  • .rtds-upload__file: Singolo file (su elemento <li> che wrappa il componente rtds-file)
  • .rtds-file.is-loading: File in caricamento
  • .rtds-file.is-loading-error: File con errore
  • .rtds-file.is-loading-completed: File completato
  • .rtds-file.is-download: File per download

Responsive

Il componente è completamente responsive:

  • Desktop: Layout orizzontale con icona, testo e pulsante
  • Mobile: Layout verticale compatto

Note di Sviluppo

Dipendenze

  • Nunjucks: Per il templating
  • CSS: Framework Tailwind con prefisso rtds-
  • SVG Sprites: Icone tramite sprite system

Limiti Attuali

  • Solo rappresentazione statica: Nessuna logica JavaScript
  • Icone fisse: Usa sempre icona generica “file”
  • SVG Sprites: Richiede sprite system configurato

Best Practices

UX

  1. Stati chiari: Usa colori e icone distintive per ogni stato
  2. Messaggi specifici: Errori descrittivi e comprensibili
  3. Accessibilità: Sempre testo nascosto per screen reader
  4. Consistenza: Mantieni lo stesso pattern per tutti gli stati

Accessibilità

  1. Testo nascosto: Usa rtds-sr-only per contesto
  2. Semantica: Lista HTML per struttura logica
  3. Focus: Pulsanti accessibili da tastiera
  4. ARIA: Attributi appropriati per progress bar

Contenuto

  1. Nomi file: Mantieni nomi descrittivi ma non troppo lunghi
  2. Dimensioni: Mostra sempre la dimensione del file
  3. Stati: Usa terminologia coerente (completato, caricamento, errore)
  4. Messaggi: Errori specifici e azionabili