Impara un sistema semplice per stati coerenti di caricamento, errore e vuoto su web e mobile, così l'interfaccia generata dall'AI resta omogenea e richiede meno ritocchi finali.

Gli stati di caricamento, errore e vuoto sono le schermate (o piccoli blocchi UI) che le persone vedono quando l'app sta aspettando, qualcosa è fallito o non c'è nulla da mostrare. Sono normali: le reti sono lente, i permessi vengono negati e gli account nuovi partono da zero dati.
Si incasinano perché di solito vengono aggiunti alla fine e in fretta. I team costruiscono prima il percorso felice, poi aggiungono uno spinner, un messaggio rosso e un segnaposto “nessun elemento” dove l'interfaccia si rompe. Fatto questo su decine di schermate si ottiene una pila di soluzioni una tantum.
L'iterazione veloce peggiora la cosa. Quando l'UI è prodotta rapidamente (inclusa l'UI generata dall'AI), il layout principale può apparire in minuti, ma questi stati sono facili da saltare. Ogni nuova schermata finisce con uno spinner diverso, una formulazione differente (“Riprova” vs “Tentare di nuovo”), e posizioni di pulsanti diverse. La velocità guadagnata all'inizio si trasforma in lavoro di rifinitura prima del lancio.
Stati non corrispondenti confondono gli utenti e costano tempo ai team. Le persone non capiscono se una lista vuota significa “nessun risultato”, “non ancora caricato” o “non hai accesso”. QA deve testare una lunga coda di piccole variazioni e i bug passano perché il comportamento differisce tra web e mobile.
“Incasinato” spesso si manifesta così:
L'obiettivo è semplice: un approccio condiviso tra web e mobile. Se il tuo team genera funzionalità velocemente (per esempio usando una piattaforma come Koder.ai), avere uno schema condiviso per gli stati è ancora più importante perché ogni nuova schermata parte coerente per impostazione predefinita.
La maggior parte delle app ripete gli stessi punti critici: liste, pagine di dettaglio, form, dashboard. Qui spiccano spinner, banner e messaggi “niente qui”.
Inizia nominando e standardizzando cinque tipi di stato:
Due casi speciali meritano regole proprie perché si comportano diversamente:
Su schermi e piattaforme, mantieni la struttura coerente: dove appare lo stato, lo stile delle icone, il tono e le azioni di default (Riprova, Aggiorna, Azzera filtri, Crea). Quello che può variare è il contesto: il nome della schermata e una frase che usa le parole dell'utente.
Esempio: se generi sia una lista web che una lista mobile per “Progetti”, dovrebbero condividere lo stesso pattern per zero-results. L'etichetta dell'azione può comunque adattarsi alla piattaforma (“Azzera filtri” vs “Reset”).
Se ogni schermata inventa il proprio spinner, la scheda di errore e il messaggio vuoto, finirai con una dozzina di versioni leggermente diverse. La soluzione più veloce è un piccolo “state kit” che ogni feature possa usare.
Inizia con tre componenti riutilizzabili che funzionino ovunque: Loading, Error e Empty. Rendili volutamente noiosi. Devono essere facili da riconoscere e non competere con l'UI principale.
Rendi i componenti prevedibili definendo un piccolo insieme di input:
Poi blocca l'aspetto. Decidi una volta la spaziatura, la tipografia, la dimensione delle icone e lo stile dei pulsanti, e trattalo come regola. Quando la dimensione delle icone e il tipo di pulsante restano gli stessi, gli utenti smettono di notare l'UI di stato e cominciano a fidarsene.
Limita le varianti così il kit non diventi un secondo design system. Tre dimensioni coprono di solito il necessario: small (inline), default (sezione) e full-page (bloccante).
Se generi schermate in Koder.ai, un'istruzione semplice come “use the app StateKit for loading/error/empty with default variant” previene la deriva. Riduce anche il lavoro di pulizia al termine su React web e Flutter mobile.
Il copy fa parte del sistema, non è decorazione. Anche quando il layout è coerente, frasi improvvisate fanno sembrare le schermate diverse.
Scegli una voce condivisa: breve, specifica, calma. Spiega cosa è successo in termini semplici, poi indica cosa fare dopo. La maggior parte delle schermate ha bisogno solo di un titolo chiaro, una breve spiegazione e un'azione ovvia.
Alcuni schemi di messaggio coprono la maggior parte delle situazioni. Mantienili brevi in modo che entrino negli schermi piccoli:
Evita testi vaghi come “Qualcosa è andato storto” da soli. Se davvero non conosci la causa, dì quello che sai e cosa può fare l'utente adesso. “Non siamo riusciti a caricare i tuoi progetti” è meglio di “Errore”.
Stabilisci una regola: ogni errore e stato vuoto offre un passo successivo.
Questo è ancora più importante con l'UI generata dall'AI, dove le schermate appaiono in fretta. I template mantengono il copy coerente così non riscrivi dozzine di messaggi one-off durante la rifinitura finale.
Quando le schermate di stato suggeriscono azioni diverse da una pagina all'altra, gli utenti esitano. I team poi finiscono a modificare pulsanti e testi poco prima del lancio.
Decidi quale azione appartiene a ogni stato e mantieni posizione ed etichetta consistenti. La maggior parte delle schermate dovrebbe avere un'azione primaria. Se aggiungi una seconda, dovrebbe supportare il percorso principale, non competere con esso.
Mantieni le azioni ammesse ristrette:
Pulsanti noiosi sono una caratteristica. Rendono l'UI familiare e aiutano le schermate generate a rimanere coerenti.
Mostra “Riprova” solo quando il retry ha senso (timeout, rete instabile, 5xx). Aggiungi un breve debounce così tocchi ripetuti non mandino spam di richieste, e passa il pulsante a uno stato di caricamento mentre si riprova.
Dopo ripetuti fallimenti, mantieni lo stesso pulsante primario e migliora l'aiuto secondario (per esempio, un suggerimento “Controlla la connessione” o “Riprova più tardi”). Evita di introdurre nuovi layout solo perché qualcosa è fallito due volte.
Per i dettagli di errore, mostra una ragione chiara su cui l'utente possa agire (“La tua sessione è scaduta. Effettua di nuovo l'accesso.”). Nascondi i dettagli tecnici per impostazione predefinita. Se servono, mettili dietro un'affordance “Dettagli” coerente tra le piattaforme.
Esempio: una lista “Progetti” non riesce a caricare su mobile. Entrambe le piattaforme mostrano la stessa azione primaria “Riprova”, la disabilitano durante il tentativo e dopo due fallimenti aggiungono un piccolo suggerimento sulla connessione invece di cambiare l'intero layout.
Tratta la coerenza degli stati come una piccola modifica di prodotto, non come un redesign. Vai per gradi e rendi l'adozione facile.
Inizia con uno snapshot veloce di quello che hai già. Non puntare alla perfezione. Cattura le variazioni comuni: skeleton vs spinner, errori full-page vs banner, schermate “nessun risultato” con tono diverso.
Un piano di rollout pratico:
Una volta che i componenti esistono, il vero risparmio di tempo è un set di regole corto che elimina il dibattito: quando uno stato blocca tutta la pagina vs solo una card, e quali azioni devono essere presenti.
Mantieni le regole concise:
Se usi un generatore di UI come Koder.ai, queste regole ripagano velocemente. Puoi chiedere di “use the state kit components” e ottenere schermate che corrispondono al tuo sistema sia su React web che su Flutter mobile con meno lavoro di pulizia.
Il lavoro di rifinitura finale capita spesso perché la gestione degli stati è stata sviluppata come soluzioni una tantum. Una schermata “funziona”, ma l'esperienza è diversa ogni volta che qualcosa impiega tempo, fallisce o è senza dati.
Gli skeleton aiutano, ma lasciarli troppo a lungo fa pensare che l'app si sia bloccata. Una causa comune è mostrare uno skeleton completo su una chiamata lenta senza indicazione che qualcosa stia ancora avanzando.
Limitane la durata: dopo una breve attesa passa a un messaggio più leggero “Ancora in caricamento…” o mostra il progresso quando possibile.
I team spesso scrivono un messaggio nuovo ogni volta, anche quando il problema è lo stesso. “Qualcosa è andato storto”, “Impossibile recuperare” e “Errore di rete” possono descrivere un unico caso, ma risultano incoerenti e complicano il supporto.
Scegli un'etichetta per tipo di errore e riutilizzala su web e mobile, con lo stesso tono e livello di dettaglio.
Un altro errore classico è mostrare lo stato vuoto prima che i dati siano finiti di caricare, o mostrare “Nessun elemento” quando il problema reale è una richiesta fallita. L'utente fa l'azione sbagliata (per esempio aggiungere contenuto quando dovrebbe riprovare).
Rendi esplicito l'ordine di decisione: prima loading, poi error se è fallita, poi empty solo quando sai che la richiesta è riuscita.
Un errore senza azione di recupero crea dead end. L'opposto è comune: tre pulsanti che competono per attenzione.
Mantienilo essenziale:
Piccole differenze si sommano: stili di icone, padding, forme dei pulsanti. Questo è anche dove l'UI generata dall'AI può deviare se i prompt variano tra schermate.
Blocca spaziatura, set di icone e layout per i componenti di stato così ogni nuova schermata eredita la stessa struttura.
Se vuoi una gestione coerente degli stati tra web e mobile, rendi esplicite le regole “noiose”. La maggior parte dei ritocchi finali avviene perché ogni schermata inventa il proprio comportamento di caricamento, timeout ed etichette.
Per un caricamento full page scegli una predefinizione: skeleton per schermate con contenuti pesanti (liste, card, dashboard) e uno spinner solo per attese brevi dove il layout è sconosciuto.
Aggiungi una soglia di timeout così l'UI non resta appesa in silenzio. Se il caricamento supera circa 8–10 secondi, passa a un messaggio chiaro e a un'azione visibile come “Riprova”.
Per caricamenti parziali non svuotare lo schermo. Mantieni visibile il contenuto esistente e mostra un piccolo indicatore di progresso vicino alla sezione che si sta aggiornando (per esempio una barra sottile nell'header o uno spinner inline).
Per dati cache, preferisci “stale but usable”. Mostra subito il contenuto cache e aggiungi un sottile indicatore “Aggiornamento in corso” così le persone capiscono perché i dati potrebbero cambiare.
Offline è uno stato a sé. Dillo chiaramente e indica cosa funziona ancora. Esempio: “Sei offline. Puoi visualizzare progetti salvati, ma la sincronizzazione è sospesa.” Offri un solo passo successivo come “Riprova” o “Apri elementi salvati”.
Mantieni queste regole coerenti tra piattaforme:
Se generi UI con uno strumento come Koder.ai, incorporare queste regole in uno StateKit condiviso aiuta a mantenere ogni nuova schermata coerente di default.
Immagina un CRM semplice con una schermata Lista Contatti e una schermata Dettaglio Contatto. Se tratti caricamento, errore e vuoto come soluzioni one-off, web e mobile si discosteranno rapidamente. Un piccolo sistema mantiene tutto allineato anche quando l'UI viene prodotta in fretta.
Empty di primo avvio (Lista Contatti): l'utente apre Contatti e non vede nulla. Su web e mobile il titolo resta lo stesso (“Contatti”), il messaggio vuoto spiega perché (“Ancora nessun contatto”) e viene offerta un'unica azione chiara (“Aggiungi il primo contatto”). Se è richiesto un setup (per esempio collegare una casella o importare un CSV), lo stato vuoto indica quel passo esatto.
Caricamento con rete lenta: l'utente apre la pagina Dettaglio Contatto. Entrambe le piattaforme mostrano uno skeleton prevedibile che rispecchia la struttura finale della pagina (header, campi principali, note). Il pulsante indietro funziona ancora, il titolo della pagina è visibile e si evitano spinner casuali in posti diversi.
Errore server: la richiesta di dettaglio fallisce. Lo stesso pattern appare su web e mobile: un titolo breve, una frase, e un'azione primaria (“Riprova”). Se il retry fallisce di nuovo, offrire una seconda opzione come “Torna ai Contatti” così l'utente non resta bloccato.
Ciò che resta coerente è semplice:
Una release può sembrare “fatta” finché qualcuno non incontra una connessione lenta, un account nuovo o un'API instabile. Questa checklist aiuta a individuare gap dell'ultimo miglio senza trasformare QA in una caccia al tesoro.
Inizia con le liste, perché si moltiplicano. Scegli tre liste comuni (risultati di ricerca, elementi salvati, attività recenti) e verifica che usino tutte la stessa struttura per lo stato vuoto: titolo chiaro, una frase utile e un'azione primaria.
Assicurati che gli stati vuoti non appaiano mentre i dati sono ancora in caricamento. Se mostri “Niente qui” per un istante e poi lo sostituisci con contenuto, la fiducia cala rapidamente.
Controlla gli indicatori di caricamento per coerenza: dimensione, posizione e una durata minima sensata così non tremolano. Se sul web appare uno spinner in cima e su mobile uno skeleton a schermo intero per la stessa schermata, sembra un prodotto diverso.
Gli errori devono sempre rispondere a “e adesso?” Ogni errore necessita di un passo successivo: riprova, aggiorna, modifica filtri, effettua di nuovo l'accesso o contatta supporto.
Un rapido controllo prima di considerare la build pronta:
Se usi un builder AI come Koder.ai, questi controlli contano ancora di più perché le schermate si possono generare velocemente, ma la coerenza dipende sempre da un kit condiviso e da regole di copy comuni.
La coerenza è più facile quando è parte del lavoro quotidiano, non una pulizia una tantum. Ogni nuova schermata dovrebbe usare gli stessi pattern senza che qualcuno debba ricordarsi di “farla combaciare” alla fine.
Rendi il comportamento degli stati parte della definition of done. Una schermata non è completa finché non ha uno stato di caricamento, uno stato vuoto (se pertinente) e uno stato di errore con un'azione chiara.
Tieni le regole leggere, ma scrivile. Un breve documento con qualche screenshot e i pattern di copy esatti è di solito sufficiente. Tratta le nuove varianti come eccezioni. Quando qualcuno propone un nuovo design di stato, chiedi se è davvero un caso nuovo o se rientra nel kit.
Se stai rifattando molte schermate, riduci il rischio facendo a fasi: aggiorna un flusso alla volta, verifica su web e mobile, poi prosegui. In Koder.ai, snapshot e rollback possono rendere i cambi più grandi più sicuri, e la planning mode può aiutare a definire lo StateKit condiviso così le nuove schermate seguono le tue impostazioni predefinite fin dal primo giorno.
Scegli un'area questa settimana dove gli stati causano spesso rifiniture finali (spesso ricerca, onboarding o feed di attività). Poi:
Un segno concreto che funziona: meno ticket “piccoli” come “aggiungi riprova”, “lo stato vuoto sembra strano” o “lo spinner blocca la pagina”.
Assegna un proprietario per gli standard degli stati (un designer, un tech lead o entrambi). Non devono approvare tutto, ma devono proteggere il kit dall'essere lentamente frammentato in nuove varianti che sembrano simili, si comportano diversamente e costano tempo più avanti.
Inizia nominando un piccolo insieme di stati che userete ovunque: initial loading, refreshing, empty baseline, zero results ed error. Aggiungi regole esplicite per offline e rete lenta così non vengono trattati come errori casuali. Quando il team concorda nomi e trigger, l'interfaccia diventa prevedibile su schermi e piattaforme.
Costruisci un piccolo StateKit con tre componenti riutilizzabili: Loading, Error e Empty. Mantieni ogni componente guidato dagli stessi input (titolo, breve messaggio, un'azione primaria e dettagli opzionali) così qualsiasi schermata può riutilizzarlo senza inventare nuove varianti. Rendi la variante predefinita la più semplice da usare in modo che i team smettano di creare one-off.
Usa un ordine decisionale semplice: mostra il caricamento finché la richiesta non è terminata, poi mostra l'errore se è fallita, e solo dopo una risposta riuscita senza dati mostra lo stato vuoto. Questo evita il bug comune in cui “Nessun elemento” appare brevemente prima che il contenuto arrivi. Aiuta anche QA perché il comportamento è coerente ovunque.
Scegli un'azione predefinita per ogni stato e riutilizza la stessa etichetta e posizione sulle schermate. Gli errori di solito hanno “Riprova”, le empty baseline hanno “Crea” (o il passo successivo di setup), e zero results hanno “Azzera filtri”. Quando l'azione primaria è prevedibile, gli utenti agiscono più rapidamente e i team sprecano meno tempo a discutere le parole dei pulsanti.
Scrivi il testo in un template condiviso: un titolo breve che descriva la situazione, una frase che la spieghi in linguaggio semplice e un passo successivo chiaro. Preferisci messaggi specifici come “Non siamo riusciti a caricare i tuoi progetti” invece di frasi vaghe come “Qualcosa è andato storto”. Mantieni tono calmo e coerente così web e mobile sembrano un unico prodotto.
Tratta l'offline come uno stato a sé: mostra contenuti cache quando disponibili, scrivi chiaramente “Sei offline” e spiega cosa funziona ancora. Offri un solo passo successivo come “Riprova” in modo che l'utente non resti bloccato a indovinare.
Evita lampi di errore su connessioni lente aspettando brevemente prima di cambiare l'interfaccia. Se il caricamento supera una soglia, passa a uno stile chiaro “Ancora in caricamento…” e fornisci un'azione visibile come “Riprova”. Così l'app sembra reattiva anche quando la rete non lo è.
Usa tre varianti di dimensione: inline piccolo (dentro una card o sezione), sezione di default e full-page bloccante. Definisci quando è permessa ciascuna variante così i team non improvvisano per ogni schermata. Mantenere la stessa spaziatura, set di icone e stile dei bottoni tra le varianti è ciò che rende l'esperienza coerente.
Incorpora poche regole: porta il focus sul messaggio e sull'azione primaria quando lo stato appare, annuncia caricamenti ed errori con etichette chiare, e assicurati che i pulsanti siano facili da premere. Non usare solo colore o animazione per comunicare lo stato. Se queste regole sono parte dello StateKit, ogni nuova schermata le eredita automaticamente.
Fallo per area prodotto, una alla volta, iniziando da liste e schermate di dettaglio più critiche. Fai l'inventario, scegli alcune posizioni canoniche, poi sostituisci gli stati one-off con i componenti condivisi man mano che tocchi ogni schermata. Se generi UI in Koder.ai, aggiungi l'istruzione permanente di usare lo StateKit per evitare derive.