Article original : How to Create Accessible and User-Friendly Forms in React

Lors de la conception d'applications web, on vous posera souvent la question éternelle : "Votre site est-il accessible ?" et "Offre-t-il la meilleure expérience utilisateur ?". Ces deux questions sont tout à fait valides, mais elles sont souvent négligées au profit de fonctionnalités riches ou sophistiquées, réduisant ainsi l'audience du site.

Dans cet article, je vais vous apprendre à utiliser la bibliothèque React Hook Form, les attributs HTML et les considérations de développement pour vous assurer que votre site est disponible pour tous, en mettant l'accent sur :

  • les utilisateurs aveugles ou malvoyants, qui peuvent utiliser un lecteur d'écran

  • une meilleure rétroaction utilisateur

  • des indices visuels pour tous

  • des considérations de conception pour tous

En suivant ce tutoriel, vous pouvez soit télécharger le code depuis le dépôt GitHub (en visitant cette page), soit utiliser les extraits de code intégrés dans l'article.

Prérequis pour cet article :

  • Connaissance de React

  • Connaissance de l'écriture de TypeScript et de HTML / JSX.

  • Familiarité avec Tailwind CSS (non requis pour suivre ce tutoriel)

Table des matières

Le formulaire de base initial

Si nous examinons le formulaire dans son état actuel, vous pourriez penser qu'il a l'air bien. Mais en réalité, il n'est pas très accessible, ni ne propose une grande expérience utilisateur.

import { TvIcon } from "@heroicons/react/24/outline";

type FormData = {
    fullName: string;
    email: string;
    password: string;
    confirmPassword: string;
    agreeToTerms: boolean;
};

export const RegistrationForm = () => {
    const onSubmit = () => {
        alert(`Form submitted`);
    };

    return (
        <div className="flex justify-center items-center w-screen h-screen bg-gray-900">
            <div className="w-full max-w-md p-8 bg-black bg-opacity-75 rounded-lg">
                <div className="flex flex-row justify-center items-center gap-x-4">
                    <TvIcon className="h-12 w-12 text-white" />
                    <h1 className="text-7xl font-bold text-center text-red-600 mb-4">Getflix</h1>
                </div>
                <h2 className="text-3xl font-bold text-white mb-6 text-center">
                    Sign Up
                </h2>

                <form onSubmit={onSubmit} className="space-y-6">

                    {/* Full Name */}
                    <div>
                        <input
                            type="text"
                            placeholder="Full Name"
                            className="w-full p-3 rounded bg-gray-700 text-white placeholder-gray-400 "
                        />

                    </div>

                    {/* Email */}
                    <div>
                        <input
                            type="email"
                            placeholder="Email Address"
                            className="w-full p-3 rounded bg-gray-700 text-white placeholder-gray-400 "
                        />

                    </div>

                    {/* Password */}
                    <div>
                        <input
                            type="password"
                            placeholder="Password"
                            className="w-full p-3 rounded bg-gray-700 text-white placeholder-gray-400"
                        />

                    </div>

                    {/* Confirm Password */}
                    <div>
                        <input
                            type="password"
                            placeholder="Confirm Password"
                            className="w-full p-3 rounded bg-gray-700 text-white placeholder-gray-400 "
                        />

                    </div>

                    {/* Agree to Terms */}
                    <div className="flex items-center text-gray-400 text-sm">
                        <input

                            type="checkbox"
                            id="agreeToTerms"
                            className="mr-2"
                        />
                        <label htmlFor="agreeToTerms" className="select-none">
                            I agree to the Terms and Conditions
                        </label>
                    </div>


                    {/* Submit */}
                    <button
                        type="submit"
                        className="w-full py-3 bg-red-600 hover:bg-red-700 text-white rounded font-semibold transition"
                    >
                        Sign Up
                    </button>


                </form>
            </div>
        </div>
    );
};

Qu'est-ce qui ne va pas avec le formulaire ?

  • Manque de rétroaction d'action – l'absence de rétroaction utilisateur signifie que les utilisateurs peuvent être confus quant à savoir si une action a eu lieu ou non. Aucun message d'erreur ou rétroaction ne donne à l'utilisateur aucune indication sur ce qu'il doit faire pour corriger le formulaire.

  • Aucune étiquette pour les entrées de formulaire – L'absence d'étiquettes pour les entrées de formulaire empêche les lecteurs d'écran de comprendre leur but. Certains lecteurs d'écran peuvent manquer les placeholders, et une fois que l'utilisateur tape dans l'entrée, le placeholder est remplacé, perdant le contexte et rendant difficile le retour aux entrées erronées.

  • Manque de balisage d'accessibilité pour rendre le formulaire optimisé pour les lecteurs d'écran et les outils d'accessibilité.

Alors, comment pouvons-nous améliorer cela ? Plongeons directement dans le sujet.

Gestion des erreurs avec React-Hook-Form

La gestion des erreurs dans les formulaires est un aspect critique de tout flux de soumission de formulaire. Sans cela, le processus devient à la fois chaotique et frustrant pour l'utilisateur. Nous pouvons atténuer cette frustration en ajoutant des messages d'erreur utiles qui expliquent les problèmes.

Une bibliothèque populaire pour travailler avec des formulaires dans React est la bibliothèque react-hook-form. Elle est utilisée par plus de 1,4 million de personnes selon leurs statistiques GitHub.

Allez-y et installez-la si vous ne l'avez pas déjà :

npm install react-hook-form

Nous allons ensuite implémenter les fonctions de base requises du package react-hook-form, en utilisant le hook useForm() comme suit :

// définir notre structure de type à utiliser dans le formulaire
type FormData = {
    fullName: string;
    email: string;
    password: string;
    confirmPassword: string;
    agreeToTerms: boolean;
};

// utilisation de base de `useForm()`
const {
    register,
    handleSubmit,
    watch,
    formState: { errors },
  } = useForm<Inputs>()

Explication rapide :

  • register : L'un des concepts clés dans React Hook Form est d'« enregistrer » votre composant/élément HTML. Cela signifie que vous pouvez accéder à la valeur de l'élément pour la validation du formulaire et lors de la soumission du formulaire.

  • handleSubmit : Il s'agit de la fonction clé nécessaire pour soumettre le formulaire, exécuter la validation et toute autre vérification configurée. Elle peut prendre jusqu'à deux arguments :

    1. handleSubmit(onSuccess) – appelé lorsque la soumission du formulaire est valide et peut être soumise correctement.

    2. handleSubmit(onSuccess, onFail) – ici, vous pouvez passer deux fonctions à la méthode handleSubmit() : la première sera exécutée lorsque React Hook Form juge le formulaire valide et vous permet de continuer. La seconde sera appelée lorsque le formulaire détecte une erreur. Cela peut provenir de la validation ou d'une autre stipulation.

  • watch : Watch est une fonction qui surveille un élément spécifié pour les changements et retourne sa valeur. Par exemple, si vous surveillez un élément d'entrée, vous pouvez afficher la saisie de l'utilisateur en temps réel ou avoir un autre élément la valider par rapport à une valeur prédéfinie. Un bon exemple est la confirmation du mot de passe correspondant au champ de mot de passe précédent.

  • formState : il s'agit d'un objet qui contient des informations sur votre formulaire. L'objet formState suit l'état du formulaire, comme :

    1. isDirtytrue si l'utilisateur a modifié n'importe quelle entrée.

    2. isValidtrue si le formulaire passe toutes les validations.

    3. errors – un objet contenant toute erreur de validation par champ.

    4. isSubmittingtrue pendant que le formulaire est en cours de soumission (utile pour afficher des indicateurs de chargement)

    5. isSubmittedtrue après que le formulaire a été soumis.

    6. touchedFields – quels champs l'utilisateur a interagi.

    7. dirtyFields – quels champs l'utilisateur a modifiés.

Nous pouvons utiliser n'importe laquelle de ces propriétés en les incluant dans notre objet d'état de formulaire. Nous déstructurons la propriété errors afin de pouvoir utiliser les erreurs plus tard dans notre formulaire pour afficher des messages d'erreur ou valider qu'il n'y a pas d'erreurs sur la page.

Intégration des méthodes useForm à notre formulaire

Maintenant que nous en savons plus sur la méthode useForm() et react-hook-form, nous devons intégrer cela avec notre élément <form/> existant. Cela nous permettra d'utiliser toutes les fonctionnalités de react-hook-form que nous avons discutées jusqu'à présent dans notre formulaire.

```xml import { TvIcon } from "@heroicons/react/24/outline"; import { useState } from "react"; import { useForm } from "react-hook-form";

type FormData = { fullName: string; email: string; password: string; confirmPassword: string; agreeToTerms: boolean; };

export const RegistrationForm = () => { const { register, handleSubmit, formState: { errors }, watch, } = useForm();

const onSubmit = () => { alert(Form submitted); };

return (

Getflix

Sign Up

{/ Full Name /}

{errors.fullName && (

{errors.fullName.message}

)}

{/ Email /}

{errors.email && (

{errors.email.message}

)}

{/ Password /}

{errors.password && (

{errors.password.message}

)}

{/ Confirm Password /}

value === watch("password") || "Passwords do not match", })} type="password" placeholder="Confirm Password" className="w-full p-3 rounded bg-gray-700 text-white placeholder-gray-400 focus:outline-none focus:ring-2 focus:ring-red-500" /> {errors.confirmPassword && (

{errors.confirmPassword.message}

)}

{/ Agree to Terms /}

I agree to the Terms and Conditions

{errors.agreeToTerms && (

{errors.agreeToTerms.message}

)}

{/ Submit /} Sign Up

{/ Already have account /}

Already have an account?{"