Apprenez un système simple pour uniformiser les états de chargement, d'erreur et vides sur web et mobile, afin que l'UI générée (y compris par IA) reste cohérente et demande moins de retouches finales.

Les états de chargement, d'erreur et vides sont les écrans (ou petits blocs d'UI) que les gens voient quand l'app attend, que quelque chose a échoué, ou qu'il n'y a tout simplement rien à afficher. C'est normal : les réseaux sont lents, les permissions sont refusées, et les nouveaux comptes commencent sans données.
Ils se dégradent parce qu'ils sont généralement ajoutés tard et rapidement. Les équipes construisent d'abord le chemin heureux, puis collent un spinner, un message rouge et un placeholder « aucun élément » là où l'UI casse. Faites ça sur des dizaines d'écrans et vous vous retrouvez avec une pile de cas uniques.
L'itération rapide aggrave le problème. Quand l'UI est produite vite (y compris via une génération par IA), la mise en page principale peut apparaître en minutes, mais ces états sont faciles à zapper. Chaque nouvel écran finit avec un style de spinner différent, un libellé différent (« Réessayer » vs « Try again »), et un placement de bouton différent. La vitesse gagnée au départ se transforme en travail de polissage juste avant le lancement.
Des états discordants confondent les utilisateurs et coûtent du temps aux équipes. Les gens ne savent pas si une liste vide signifie « aucun résultat », « pas encore chargé » ou « vous n'avez pas accès ». La QA doit tester une longue traîne de petites variations, et des bugs passent entre les mailles parce que le comportement diffère entre web et mobile.
« Désordonné » ressemble souvent à ceci :
Le but est simple : une approche partagée sur web et mobile. Si votre équipe génère des fonctionnalités rapidement (par exemple en utilisant une plateforme comme Koder.ai), disposer d'un modèle d'état partagé compte encore plus parce que chaque nouvel écran commence cohérent par défaut.
La plupart des apps répètent les mêmes points de pression : listes, pages de détail, formulaires, tableaux de bord. C'est là que spinners, bannières et messages « rien ici » se multiplient.
Commencez par nommer et standardiser cinq types d'état :
Deux cas spéciaux méritent leurs propres règles car ils se comportent différemment :
Sur les écrans et plateformes, gardez la structure cohérente : où l'état apparaît, le style d'icône, le ton et les actions par défaut (Réessayer, Actualiser, Effacer les filtres, Créer). Ce qui peut varier, c'est le contexte : le nom de l'écran et une phrase qui reprend les mots de l'utilisateur.
Exemple : si vous générez à la fois une liste web et une liste mobile pour « Projets », elles doivent partager le même modèle pour zéro résultat. Le libellé de l'action peut toujours correspondre à la plateforme (« Effacer les filtres » vs « Réinitialiser »).
Si chaque écran invente son propre spinner, sa carte d'erreur et son message vide, vous finirez avec une douzaine de versions légèrement différentes. La réparation la plus rapide est un petit « state kit » que toute fonctionnalité peut greffer.
Commencez par trois composants réutilisables qui fonctionnent partout : Loading, Error et Empty. Gardez-les volontairement sobres. Ils doivent être faciles à reconnaître et ne pas concurrencer l'UI principale.
Rendez les composants prévisibles en définissant un petit ensemble d'entrées :
Puis verrouillez l'apparence. Décidez une fois pour toutes des espacements, typographie, taille d'icône et style de bouton, et traitez cela comme une règle. Quand la taille d'icône et le type de bouton restent les mêmes, les utilisateurs cessent de remarquer l'UI d'état et commencent à lui faire confiance.
Limitez les variantes pour que le kit ne devienne pas un second design system. Trois tailles couvrent généralement : petit (inline), par défaut (section) et pleine page (bloquant).
Si vous générez des écrans dans Koder.ai, une consigne simple comme « utiliser le StateKit de l'app pour loading/error/empty avec la variante par défaut » empêche la dérive. Cela réduit aussi le nettoyage de dernière minute entre React web et Flutter mobile.
La copie fait partie du système, pas de la décoration. Même quand la mise en page est cohérente, des tournures ad hoc font paraître les écrans différents.
Choisissez une voix partagée : courte, spécifique, calme. Dites ce qui s'est passé en termes simples, puis dites à l'utilisateur quoi faire ensuite. La plupart des écrans n'ont besoin que d'un titre clair, d'une courte explication et d'une action évidente.
Quelques modèles de message couvrent la majorité des situations. Gardez-les courts pour qu'ils tiennent sur les petits écrans :
Évitez les textes vagues comme « Quelque chose a mal tourné » seuls. Si vous ne connaissez pas réellement la cause, dites ce que vous savez et ce que l'utilisateur peut faire maintenant. « Nous n'avons pas pu charger vos projets » vaut mieux que « Erreur ».
Appliquez une règle : chaque état d'erreur et vide propose une étape suivante.
Ceci est d'autant plus important avec l'UI générée par IA, où les écrans apparaissent vite. Les modèles maintiennent la copie cohérente et évitent de réécrire des dizaines de messages ponctuels au moment du polissage final.
Quand les écrans d'état suggèrent des actions différentes d'une page à l'autre, les utilisateurs hésitent. Les équipes finissent par retoucher les boutons et la copie juste avant le lancement.
Décidez quelle action correspond à chaque état, et gardez le placement et le libellé cohérents. La plupart des écrans devraient n'avoir qu'une action primaire. Si vous ajoutez une seconde, elle doit soutenir le chemin principal, pas le concurrencer.
Limitez les actions autorisées :
Des boutons sobres sont une fonctionnalité. Ils rendent l'UI familière et aident les écrans générés à rester cohérents.
Affichez « Réessayer » seulement quand le réessai peut raisonnablement fonctionner (timeouts, réseau instable, 5xx). Ajoutez un petit debounce pour que les taps répétés n'envoient pas une pluie de requêtes, et basculez le bouton en état de chargement pendant le réessai.
Après des échecs répétés, conservez le même bouton primaire et améliorez l'aide secondaire (par exemple, un conseil « Vérifiez la connexion » ou « Réessayez plus tard »). Évitez d'introduire de nouvelles mises en page juste parce que quelque chose a échoué deux fois.
Pour les détails d'erreur, affichez une raison claire et actionnable (« Votre session a expiré. Connectez‑vous à nouveau. »). Cachez les détails techniques par défaut. Si vous en avez besoin, planquez‑les derrière un « Détails » cohérent sur toutes les plateformes.
Exemple : la liste « Projets » échoue à se charger sur mobile. Les deux plateformes affichent la même action primaire « Réessayer », la désactivent pendant le réessai, et après deux échecs ajoutent un petit indice de connexion au lieu de changer complètement la mise en page.
Traitez la cohérence des états comme un petit changement produit, pas comme une refonte. Allez par étapes et facilitez l'adoption.
Commencez par un instantané rapide de ce que vous avez déjà. Ne visez pas la perfection. Capturez les variations courantes : skeletons vs spinners, erreurs pleine page vs bannières, écrans « aucun résultat » avec des tons différents.
Un plan de déploiement pratique :
Une fois les composants existants, le véritable gain de temps vient d'un jeu de règles court qui élimine les débats : quand un état bloque toute la page vs seulement une carte, et quelles actions doivent être présentes.
Gardez les règles courtes :
Si vous utilisez un générateur UI comme Koder.ai, ces règles se payent rapidement. Vous pouvez demander « utiliser les composants du state kit » et obtenir des écrans qui correspondent à votre système sur React web et Flutter mobile avec moins de nettoyage.
Le polissage tardif vient souvent du fait que la gestion des états a été construite en one‑offs. Un écran « fonctionne », mais l'expérience change chaque fois que quelque chose prend du temps, échoue ou n'a pas de données.
Les skeletons aident, mais les laisser trop longtemps donne l'impression que l'app est figée. Une cause fréquente est d'afficher un skeleton plein pour un appel lent sans signal que quelque chose bouge.
Limitez dans le temps : après un court délai, basculez sur un message plus léger « Toujours en cours de chargement… » ou affichez une progression quand vous le pouvez.
Les équipes écrivent souvent un nouveau message à chaque fois, même quand le problème est le même. « Quelque chose a mal tourné », « Impossible de récupérer » et « Erreur réseau » peuvent décrire un seul cas, mais ils sonnent incohérents et compliquent le support.
Choisissez un libellé par type d'erreur et réutilisez‑le sur web et mobile, avec le même ton et niveau de détail.
Une autre erreur classique est d'afficher un état vide avant que les données aient fini de charger, ou d'afficher « Aucun élément » alors que le vrai problème est une requête qui a échoué. L'utilisateur effectue la mauvaise action (par exemple ajouter du contenu quand il devrait réessayer).
Rendez l'ordre de décision explicite : chargement d'abord, puis erreur si ça a échoué, puis vide seulement quand vous savez que la requête a réussi.
Une erreur sans action de récupération crée des impasses. L'inverse est aussi courant : trois boutons qui se disputent l'attention.
Restez concis :
Les petites différences s'accumulent : style d'icône, padding, formes de bouton. C'est aussi là que l'UI générée par IA peut diverger si les consignes varient d'un écran à l'autre.
Verrouillez les espacements, la librairie d'icônes et la mise en page des composants d'état pour que chaque nouvel écran hérite de la même structure.
Si vous voulez une gestion cohérente des états sur web et mobile, rendez explicites les règles « ennuyeuses ». La plupart des retouches de dernière minute viennent du fait que chaque écran invente son propre comportement de chargement, ses timeouts et ses libellés.
Pour un chargement pleine page, choisissez une valeur par défaut : skeletons pour les écrans riches en contenu (listes, cartes, tableaux de bord) et un spinner seulement pour les attentes courtes où la mise en page est inconnue.
Ajoutez un seuil de timeout pour que l'UI ne reste pas figée en silence. Si le chargement dépasse environ 8 à 10 secondes, basculez sur un message clair et une action visible comme « Réessayer ».
Pour les chargements partiels, ne videz pas l'écran. Gardez le contenu existant visible et affichez un petit indicateur de progression près de la section qui se met à jour (par exemple, une fine barre dans l'en‑tête ou un spinner inline).
Pour les données en cache, préférez « périmées mais utilisables ». Affichez le contenu en cache immédiatement et ajoutez un discret « Actualisation… » pour que les gens comprennent pourquoi les données peuvent changer.
Le hors‑ligne est un état à part. Dites‑le simplement, et dites ce qui fonctionne encore. Exemple : « Vous êtes hors‑ligne. Vous pouvez consulter les projets enregistrés, mais la synchronisation est en pause. » Proposez une seule action suivante comme « Réessayer » ou « Ouvrir les éléments enregistrés ».
Appliquez ces règles de base :
Si vous générez l'UI avec un outil comme Koder.ai, intégrer ces règles dans un state kit partagé aide chaque nouvel écran à être cohérent par défaut.
Imaginez un CRM simple avec un écran Liste de Contacts et un écran Détail Contact. Si vous traitez chargement, erreur et état vide comme des one‑offs, web et mobile divergent vite. Un petit système maintient l'alignement même quand l'UI est produite rapidement.
État vide au premier lancement (Liste de Contacts) : l'utilisateur ouvre Contacts et ne voit encore rien. Sur web et mobile, le titre reste le même (« Contacts »), le message d'état explique pourquoi (« Pas encore de contacts ») et une action claire est proposée (« Ajoutez votre premier contact »). Si une configuration est requise (connexion d'une boîte mail ou import CSV), l'état vide indique exactement cette étape.
Chargement réseau lent : l'utilisateur ouvre la page de détail d'un Contact. Les deux plateformes affichent un skeleton prévisible qui correspond à la structure finale (en‑tête, champs clés, notes). Le bouton retour fonctionne toujours, le titre de la page est visible, et vous évitez des spinners aléatoires à différents emplacements.
Erreur serveur : la requête de détail échoue. Le même motif apparaît sur web et mobile : un titre court, une phrase, et une action primaire (« Réessayer »). Si le réessai échoue encore, proposez une seconde option comme « Retour à Contacts », pour que l'utilisateur ne soit pas bloqué.
Ce qui reste cohérent est simple :
Une release peut sembler « finie » jusqu'à ce que quelqu'un tombe sur une connexion lente, un compte neuf ou une API instable. Cette checklist aide à repérer les lacunes de dernière minute sans transformer la QA en chasse au trésor.
Commencez par les écrans de listes, car ils se multiplient. Choisissez trois listes communes (résultats de recherche, éléments enregistrés, activité récente) et vérifiez qu'elles utilisent toutes la même structure d'état vide : un titre clair, une phrase utile et une action primaire.
Assurez‑vous que les états vides n'apparaissent jamais pendant le chargement. Si vous affichez « Rien ici pour l'instant » une fraction de seconde puis remplacez par du contenu, la confiance baisse vite.
Vérifiez les indicateurs de chargement pour la cohérence : taille, placement et durée minimale sensée pour éviter le scintillement. Si le web montre un spinner en barre supérieure mais le mobile un skeleton pleine page pour le même écran, ça ressemble à deux produits différents.
Les erreurs doivent toujours répondre à « et ensuite ? » Chaque erreur nécessite une étape suivante : réessayer, actualiser, changer les filtres, se reconnecter ou contacter le support.
Un passage rapide avant de marquer la build prête :
Si vous utilisez un constructeur IA comme Koder.ai, ces vérifications comptent encore plus parce que les écrans peuvent être générés vite, mais la cohérence dépend toujours d'un kit partagé et de règles de copie communes.
La cohérence est plus simple quand elle fait partie du travail quotidien, pas d'un rattrapage ponctuel. Chaque nouvel écran doit utiliser les mêmes motifs sans que quelqu'un se rappelle de « faire correspondre » à la fin.
Intégrez le comportement d'état dans la définition de prêt. Un écran n'est pas terminé tant qu'il n'a pas un état de chargement, un état vide (si applicable) et un état d'erreur avec une action claire.
Gardez les règles légères, mais écrivez‑les. Un court document avec quelques captures d'écran et les modèles de copie exacts suffit généralement. Traitez les nouvelles variantes comme des exceptions. Quand quelqu'un propose un nouveau design d'état, demandez si c'est vraiment un nouveau cas ou si ça rentre dans le kit.
Si vous refactorez beaucoup d'écrans, réduisez le risque en procédant par étapes contrôlées : mettez à jour un flux à la fois, vérifiez‑le sur web et mobile, puis continuez. Dans Koder.ai, les snapshots et le rollback peuvent sécuriser les gros changements, et le planning mode peut aider à définir le state kit partagé pour que les écrans nouvellement générés respectent vos défauts dès le départ.
Choisissez cette semaine une zone où les états posent souvent des retouches de dernière minute (souvent recherche, onboarding ou fil d'activité). Puis :
Un signe concret que ça marche : moins de tickets « petits » comme « ajouter réessayer », « l'état vide est bizarre » ou « le spinner bloque la page ».
Désignez un propriétaire unique pour les standards d'état (un·e designer, un tech lead, ou les deux). Il/elle n'a pas besoin d'approuver tout, mais doit protéger le kit pour qu'il ne se scinde pas progressivement en variantes qui se ressemblent, se comportent différemment et coûtent du temps plus tard.
Commencez par nommer un petit ensemble d'états que vous utiliserez partout : chargement initial, actualisation, état vide de base, zéro résultat et erreur. Ajoutez des règles explicites pour le hors-ligne et le réseau lent afin qu'ils ne soient pas traités comme des erreurs aléatoires. Une fois que l'équipe s'accorde sur les noms et les déclencheurs, l'interface devient prévisible entre les écrans et les plateformes.
Créez un petit StateKit composé de trois éléments réutilisables : Loading, Error et Empty. Chacun doit être piloté par les mêmes entrées (titre, message court, une action primaire et détails optionnels) pour que n'importe quel écran puisse l'utiliser sans inventer une nouvelle UI. Faites de la variante par défaut la plus simple à utiliser pour décourager les versions isolées.
Utilisez un ordre de décision simple : affichez le chargement tant que la requête n'est pas terminée, affichez l'erreur si elle a échoué, et n'affichez l'état vide qu'après une réponse réussie sans données. Cela empêche le bug courant où « Aucun élément » clignote brièvement avant que le contenu n'apparaisse. Ça aide aussi la QA car le comportement devient consistant partout.
Choisissez une action par défaut par état et réutilisez le même libellé et placement. Les erreurs obtiennent généralement « Réessayer », les états vides de base « Créer » (ou l'étape suivante), et les zéro résultats « Effacer les filtres ». Quand l'action primaire est prévisible, les utilisateurs agissent plus vite et les équipes passent moins de temps à débattre du libellé du bouton.
Rédigez la copie selon un modèle partagé : un titre court qui nomme la situation, une phrase expliquant clairement en langage simple, et une action suivante évidente. Préférez des messages spécifiques comme « Nous n'avons pas pu charger vos projets » plutôt que des formulations vagues comme « Quelque chose a mal tourné ». Gardez un ton calme et uniforme pour que web et mobile donnent l'impression d'un même produit.
Traitez le hors-ligne comme un état à part. Affichez le contenu en cache si disponible, dites simplement « Vous êtes hors-ligne » et expliquez ce qui fonctionne encore. Proposez une seule action suivante comme « Réessayer » pour éviter que l'utilisateur soit bloqué.
Évitez les flashes d'erreur précoces sur une connexion lente en attendant un bref délai avant de changer l'UI. Si le chargement dépasse un seuil, basculez sur un message clair de type « Toujours en cours de chargement… » et proposez une action visible comme « Réessayer ». Cela rend l'app réactive même si le réseau traîne.
Utilisez trois variantes de taille : inline petit (dans une carte ou une section), section par défaut, et pleine page bloquante. Définissez quand chacune est autorisée pour éviter l'improvisation. C'est la cohérence des espacements, du style d'icône et des boutons entre les variantes qui rend l'expérience homogène.
Intégrez quelques règles : déplacez le focus sur le message et l'action primaire quand l'état apparaît, annoncez le chargement et les erreurs par des textes clairs pour le lecteur d'écran, et assurez-vous que les boutons sont faciles à toucher. Ne comptez pas uniquement sur la couleur ou l'animation pour communiquer le statut. Si ces règles font partie du StateKit, chaque nouvel écran les héritera automatiquement.
Déployez par zone produit, en commençant par les listes et écrans de détail à fort trafic. Faites l'inventaire, choisissez quelques placements canoniques, puis remplacez les états isolés par les composants partagés au fur et à mesure que vous touchez chaque écran. Si vous générez l'UI dans Koder.ai, ajoutez une consigne permanente pour utiliser le StateKit par défaut afin que les nouveaux écrans ne divergent pas.