Créer un composant "Paramètres"

Présentation de base de la création d'un composant de paramètres avec des curseurs et des cases à cocher.

Dans cet article, je souhaite partager ma réflexion sur la création d'un composant de paramètres pour le Web, qui est responsive, prend en charge plusieurs entrées d'appareil et fonctionne sur tous les navigateurs. Essayez la démonstration.

Démo

Si vous préférez les vidéos ou si vous souhaitez avoir un aperçu de l'UI/UX de ce que nous développons, voici un tutoriel plus court sur YouTube :

Présentation

J'ai divisé les aspects de ce composant dans les sections suivantes :

  1. Mises en page
  2. Couleur
  3. Saisie de plage personnalisée
  4. Saisie de case à cocher personnalisée
  5. Considérations sur l'accessibilité
  6. JavaScript

Mises en page

Il s'agit de la première démo du GUI Challenge à être entièrement basée sur CSS Grid ! Voici chaque grille mise en évidence avec les outils pour les développeurs Chrome pour la grille :

Contour coloré et espacement des marges qui permettent de visualiser toutes les zones qui composent la mise en page des paramètres

Just for gap

La mise en page la plus courante :

foo {
  display: grid;
  gap: var(--something);
}

J'appelle cette mise en page "just for gap" (juste pour l'espacement), car elle n'utilise que la grille pour ajouter des espaces entre les blocs.

Cinq mises en page utilisent cette stratégie. Les voici :

Mises en page de grille verticales mises en évidence avec des contours et des espaces remplis

L'élément fieldset, qui contient chaque groupe d'entrée (.fieldset-item), utilise gap: 1px pour créer les bordures fines entre les éléments. Pas de solution de bordure délicate !

Emplacement comblé
.grid {
  display: grid;
  gap: 1px;
  background: var(--bg-surface-1);

  & > .fieldset-item {
    background: var(--bg-surface-2);
  }
}
Astuce pour les bordures
.grid {
  display: grid;

  & > .fieldset-item {
    background: var(--bg-surface-2);

    &:not(:last-child) {
      border-bottom: 1px solid var(--bg-surface-1);
    }
  }
}

Retour à la ligne naturel dans la grille

La mise en page la plus complexe s'est avérée être la mise en page macro, le système de mise en page logique entre <main> et <form>.

Centrer le contenu d'encapsulation

Flexbox et les grilles permettent tous deux d'align-items ou d'align-content. Lorsque vous utilisez des éléments d'habillage, les alignements de mise en page content répartissent l'espace entre les enfants en tant que groupe.

main {
  display: grid;
  gap: var(--space-xl);
  place-content: center;
}

L'élément principal utilise le raccourci d'alignement place-content: center afin que les enfants soient centrés verticalement et horizontalement dans les mises en page à une et deux colonnes.

Dans la vidéo ci-dessus, vous pouvez voir comment le "contenu" reste centré, même s'il a été renvoyé à la ligne.

Répéter minmax auto-fit

<form> utilise une mise en page en grille adaptative pour chaque section. Cette mise en page passe d'une à deux colonnes en fonction de l'espace disponible.

form {
  display: grid;
  gap: var(--space-xl) var(--space-xxl);
  grid-template-columns: repeat(auto-fit, minmax(min(10ch, 100%), 35ch));
  align-items: flex-start;
  max-width: 89vw;
}

Cette grille a une valeur différente pour row-gap (--space-xl) que pour column-gap (--space-xxl) afin de personnaliser la mise en page responsive. Lorsque les colonnes s'empilent, nous voulons un grand espace, mais pas aussi grand que si nous étions sur un écran large.

La propriété grid-template-columns utilise trois fonctions CSS : repeat(), minmax() et min(). Una Kravets a écrit un excellent article de blog sur la mise en page, qu'elle appelle RAM.

Si vous comparez notre mise en page à celle d'Una, vous remarquerez trois ajouts spéciaux :

  • Nous transmettons une fonction min() supplémentaire.
  • Nous spécifions align-items: flex-start.
  • Il existe un style max-width: 89vw.

La fonction min() supplémentaire est bien décrite par Evan Minto sur son blog dans l'article Intrinsically Responsive CSS Grid with minmax() and min(). Je vous recommande de le lire. La correction d'alignement flex-start vise à supprimer l'effet d'étirement par défaut, de sorte que les enfants de cette mise en page n'ont pas besoin d'avoir des hauteurs égales. Ils peuvent avoir des hauteurs intrinsèques naturelles. La vidéo YouTube présente en détail cette nouvelle fonctionnalité d'alignement.

max-width: 89vw mérite d'être détaillé dans cet article. Voici la mise en page avec et sans le style appliqué :

Que se passe-t-il ? Lorsque max-width est spécifié, il fournit un contexte, une taille explicite ou une taille définie pour que l'algorithme de mise en page auto-fit sache combien de répétitions il peut insérer dans l'espace. Bien qu'il semble évident que l'espace soit "pleine largeur", selon la spécification de la grille CSS, une taille ou une taille maximale définie doit être fournie. J'ai indiqué une taille maximale.

Alors, pourquoi 89vw ? Parce que "ça a marché" pour ma mise en page. Avec d'autres membres de l'équipe Chrome, nous cherchons à comprendre pourquoi une valeur plus raisonnable, comme 100vw, ne suffit pas et s'il s'agit d'un bug.

Espacement

L'harmonie de cette mise en page provient en grande partie d'une palette limitée d'espacements, sept pour être exact.

:root {
  --space-xxs: .25rem;
  --space-xs:  .5rem;
  --space-sm:  1rem;
  --space-md:  1.5rem;
  --space-lg:  2rem;
  --space-xl:  3rem;
  --space-xxl: 6rem;
}

Ces flux s'intègrent parfaitement à la grille, à CSS @nest et à la syntaxe de niveau 5 de @media. Voici un exemple de l'ensemble complet de styles de mise en page <main>.

main {
  display: grid;
  gap: var(--space-xl);
  place-content: center;
  padding: var(--space-sm);

  @media (width >= 540px) {
    & {
      padding: var(--space-lg);
    }
  }

  @media (width >= 800px) {
    & {
      padding: var(--space-xl);
    }
  }
}

Grille avec contenu centré, avec une marge intérieure modérée par défaut (comme sur mobile). Mais à mesure que l'espace de la fenêtre d'affichage augmente, il s'étale en augmentant la marge intérieure. Le CSS de 2021 est plutôt bon !

Vous vous souvenez de la mise en page "juste pour le trou" que nous avons vue précédemment ? Voici une version plus complète de leur apparence dans ce composant :

header {
  display: grid;
  gap: var(--space-xxs);
}

section {
  display: grid;
  gap: var(--space-md);
}

Couleur

L'utilisation contrôlée de la couleur a permis à ce design de se démarquer en tant que design expressif, mais minimaliste. Voici comment je procède :

:root {
  --surface1: lch(10 0 0);
  --surface2: lch(15 0 0);
  --surface3: lch(20 0 0);
  --surface4: lch(25 0 0);

  --text1: lch(95 0 0);
  --text2: lch(75 0 0);
}

Je nomme mes couleurs de surface et de texte avec des nombres plutôt qu'avec des noms comme surface-dark et surface-darker, car dans une requête média, je vais les inverser, et clair et foncé n'auront pas de sens.

Je les inverse dans une requête média de préférence comme ceci :

:root {
  ...

  @media (prefers-color-scheme: light) {
    & {
      --surface1: lch(90 0 0);
      --surface2: lch(100 0 0);
      --surface3: lch(98 0 0);
      --surface4: lch(85 0 0);

      --text1: lch(20 0 0);
      --text2: lch(40 0 0);
    }
  }
}

Il est important d'avoir un aperçu de la situation globale et de la stratégie avant de nous plonger dans les détails de la syntaxe des couleurs. Mais comme je suis allé un peu vite, revenons un peu en arrière.

LCH ?

Sans entrer trop dans la théorie des couleurs, LCH est une syntaxe orientée vers l'humain, qui s'adapte à la façon dont nous percevons les couleurs, et non à la façon dont nous les mesurons avec des chiffres (comme 255). Cela lui confère un avantage distinct, car les humains peuvent l'écrire plus facilement et d'autres humains seront en phase avec ces ajustements.

Capture d&#39;écran de la page Web pod.link/csspodcast, avec l&#39;épisode &quot;Color 2: Perception&quot; affiché
Découvrez la couleur perçue (et plus encore !) dans le podcast CSS.

Pour aujourd'hui, dans cette démo, concentrons-nous sur la syntaxe et les valeurs que je vais inverser pour créer les thèmes clair et sombre. Examinons une couleur de surface et une couleur de texte :

:root {
  --surface1: lch(10 0 0);
  --text1:    lch(95 0 0);

  @media (prefers-color-scheme: light) {
    & {
      --surface1: lch(90 0 0);
      --text1:    lch(40 0 0);
    }
  }
}

--surface1: lch(10 0 0) correspond à une luminosité de 10%, une chroma de 0 et une teinte de 0, soit un gris très foncé et incolore. Ensuite, dans la requête média pour le mode clair, la luminosité est inversée sur 90% avec --surface1: lch(90 0 0);. Voilà l'essentiel de la stratégie. Commencez par modifier la luminosité entre les deux thèmes, en conservant les rapports de contraste requis par la conception ou ce qui permet de maintenir l'accessibilité.

L'avantage de lch() ici est que la luminosité est orientée vers l'humain. Nous pouvons donc être sûrs qu'un changement de % sera perçu et cohérent comme étant % différent. hsl(), par exemple, n'est pas aussi fiable.

Pour en savoir plus sur les espaces colorimétriques et lch(), cliquez ici. Bientôt disponible !

Actuellement, les CSS n'ont pas accès à ces couleurs. Je répète : nous n'avons pas accès à un tiers des couleurs sur la plupart des écrans modernes. Et il ne s'agit pas de n'importe quelles couleurs, mais des couleurs les plus vives que l'écran puisse afficher. Nos sites Web sont délavés, car le matériel des écrans a évolué plus rapidement que les spécifications CSS et les implémentations des navigateurs.

Lea Verou

Contrôles de formulaire adaptatifs avec jeu de couleurs

De nombreux navigateurs proposent des commandes pour le thème sombre (Safari et Chromium, par exemple), mais vous devez spécifier dans le code CSS ou HTML que votre conception les utilise.

L'exemple ci-dessus montre l'effet de la propriété dans le panneau "Styles" des outils de développement. La démo utilise la balise HTML, qui, à mon avis, est généralement un meilleur emplacement :

<meta name="color-scheme" content="dark light">

Pour en savoir plus, consultez color-schemecet article de Thomas Steiner. Vous avez beaucoup plus à gagner que des cases à cocher sombres !

CSS accent-color

Il y a eu une activité récente autour de accent-color sur les éléments de formulaire, qui est un style CSS unique qui peut modifier la couleur de teinte utilisée dans l'élément d'entrée du navigateur. Pour en savoir plus, consultez cet article sur GitHub. Je l'ai inclus dans les styles de ce composant. Comme les navigateurs le permettent, mes cases à cocher seront plus en accord avec les touches de rose et de violet.

input[type="checkbox"] {
  accent-color: var(--brand);
}

Capture d&#39;écran de Chromium sur Linux avec des cases à cocher roses

Créations Color pop avec dégradés fixes et focus-within

La couleur ressort le mieux lorsqu'elle est utilisée avec parcimonie. L'une des façons dont j'aime y parvenir est d'utiliser des interactions d'interface utilisateur colorées.

La vidéo ci-dessus présente de nombreux niveaux de commentaires et d'interactions avec l'UI, qui contribuent à donner de la personnalité à l'interaction :

  • Mise en avant du contexte.
  • Fournir un retour d'information sur l'interface utilisateur indiquant le degré de remplissage de la valeur dans la plage.
  • Fournir un retour d'interface utilisateur indiquant qu'un champ accepte la saisie.

Pour fournir un retour d'information lorsqu'un élément est en cours d'interaction, le CSS utilise la pseudo-classe :focus-within pour modifier l'apparence de différents éléments. Décomposons .fieldset-item, c'est super intéressant :

.fieldset-item {
  ...

  &:focus-within {
    background: var(--surface2);

    & svg {
      fill: white;
    }

    & picture {
      clip-path: circle(50%);
      background: var(--brand-bg-gradient) fixed;
    }
  }
}

Lorsqu'un des enfants de cet élément est sélectionné :

  1. L'arrière-plan .fieldset-item est associé à une couleur de surface à contraste élevé.
  2. Le svg imbriqué est rempli en blanc pour un contraste plus élevé.
  3. L'élément <picture> imbriqué clip-path se développe en un cercle complet et l'arrière-plan est rempli par le dégradé fixe lumineux.

Période personnalisée

Voici un élément d'entrée HTML. Je vais vous montrer comment j'ai personnalisé son apparence :

<input type="range">

Cet élément comporte trois parties que nous devons personnaliser :

  1. Élément / conteneur de plage
  2. Track
  3. Pouce

Styles des éléments de plage

input[type="range"] {
  /* style setting variables */
  --track-height: .5ex;
  --track-fill: 0%;
  --thumb-size: 3ex;
  --thumb-offset: -1.25ex;
  --thumb-highlight-size: 0px;

  appearance: none;         /* clear styles, make way for mine */
  display: block;
  inline-size: 100%;        /* fill container */
  margin: 1ex 0;            /* ensure thumb isn't colliding with sibling content */
  background: transparent;  /* bg is in the track */
  outline-offset: 5px;      /* focus styles have space */
}

Les premières lignes de CSS sont les parties personnalisées des styles. J'espère que le fait de les étiqueter clairement vous aidera. Le reste des styles sont principalement des styles de réinitialisation, afin de fournir une base cohérente pour la création des parties délicates du composant.

Styles de pistes

input[type="range"]::-webkit-slider-runnable-track {
  appearance: none; /* clear styles, make way for mine */
  block-size: var(--track-height);
  border-radius: 5ex;
  background:
    /* hard stop gradient:
        - half transparent (where colorful fill we be)
        - half dark track fill
        - 1st background image is on top
    */
    linear-gradient(
      to right,
      transparent var(--track-fill),
      var(--surface1) 0%
    ),
    /* colorful fill effect, behind track surface fill */
    var(--brand-bg-gradient) fixed;
}

Pour ce faire, il faut "révéler" la couleur de remplissage vive. Pour ce faire, utilisez le dégradé d'arrêt strict en haut. Le dégradé est transparent jusqu'au pourcentage de remplissage, puis utilise la couleur de la surface de la piste non remplie. Derrière cette surface vide se trouve une couleur pleine largeur, qui attend que la transparence la révèle.

Style de remplissage de la piste

Ma conception nécessite JavaScript pour conserver le style de remplissage. Il existe des stratégies CSS uniquement, mais elles exigent que l'élément de pouce ait la même hauteur que la piste, et je n'ai pas pu trouver d'harmonie dans ces limites.

/* grab sliders on page */
const sliders = document.querySelectorAll('input[type="range"]')

/* take a slider element, return a percentage string for use in CSS */
const rangeToPercent = slider => {
  const max = slider.getAttribute('max') || 10;
  const percent = slider.value / max * 100;

  return `${parseInt(percent)}%`;
};

/* on page load, set the fill amount */
sliders.forEach(slider => {
  slider.style.setProperty('--track-fill', rangeToPercent(slider));

  /* when a slider changes, update the fill prop */
  slider.addEventListener('input', e => {
    e.target.style.setProperty('--track-fill', rangeToPercent(e.target));
  })
})

Je pense que cela améliore l'aspect visuel. Le curseur fonctionne parfaitement sans JavaScript. La propriété --track-fill n'est pas obligatoire. Elle n'aura tout simplement pas de style de remplissage si elle n'est pas présente. Si JavaScript est disponible, remplissez la propriété personnalisée tout en observant les modifications apportées par l'utilisateur et en synchronisant la propriété personnalisée avec la valeur.

Cet excellent article sur CSS-Tricks, écrit par Ana Tudor, présente une solution CSS uniquement pour le remplissage de la piste. J'ai également trouvé cet élément range très inspirant.

Styles de miniatures

input[type="range"]::-webkit-slider-thumb {
  appearance: none; /* clear styles, make way for mine */
  cursor: ew-resize; /* cursor style to support drag direction */
  border: 3px solid var(--surface3);
  block-size: var(--thumb-size);
  inline-size: var(--thumb-size);
  margin-top: var(--thumb-offset);
  border-radius: 50%;
  background: var(--brand-bg-gradient) fixed;
}

La majorité de ces styles servent à créer un joli cercle. Là encore, vous voyez le dégradé d'arrière-plan fixe qui unifie les couleurs dynamiques des miniatures, des pistes et des éléments SVG associés. J'ai séparé les styles pour l'interaction afin d'isoler la technique box-shadow utilisée pour la mise en surbrillance au survol :

@custom-media --motionOK (prefers-reduced-motion: no-preference);

::-webkit-slider-thumb {
  

  /* shadow spread is initally 0 */
  box-shadow: 0 0 0 var(--thumb-highlight-size) var(--thumb-highlight-color);

  /* if motion is OK, transition the box-shadow change */
  @media (--motionOK) {
    & {
      transition: box-shadow .1s ease;
    }
  }

  /* on hover/active state of parent, increase size prop */
  @nest input[type="range"]:is(:hover,:active) & {
    --thumb-highlight-size: 10px;
  }
}

L'objectif était de créer une mise en évidence visuelle animée et facile à gérer pour les commentaires des utilisateurs. En utilisant une ombre portée, je peux éviter de déclencher la mise en page avec l'effet. Pour ce faire, je crée une ombre non floue qui correspond à la forme circulaire de l'élément thumb. Ensuite, je modifie et fais passer la taille de la propagation au survol.

Si seulement l'effet de mise en surbrillance était aussi simple sur les cases à cocher…

Sélecteurs inter-navigateurs

J'ai trouvé que j'avais besoin de ces sélecteurs -webkit- et -moz- pour obtenir une cohérence entre les navigateurs :

input[type="range"] {
  &::-webkit-slider-runnable-track {}
  &::-moz-range-track {}
  &::-webkit-slider-thumb {}
  &::-moz-range-thumb {}
}

Case à cocher personnalisée

Voici un élément d'entrée HTML. Je vais vous montrer comment j'ai personnalisé son apparence :

<input type="checkbox">

Cet élément comporte trois parties que nous devons personnaliser :

  1. Élément de case à cocher
  2. Libellés associés
  3. Effet de mise en évidence

Élément de case à cocher

input[type="checkbox"] {
  inline-size: var(--space-sm);   /* increase width */
  block-size: var(--space-sm);    /* increase height */
  outline-offset: 5px;            /* focus style enhancement */
  accent-color: var(--brand);     /* tint the input */
  position: relative;             /* prepare for an absolute pseudo element */
  transform-style: preserve-3d;   /* create a 3d z-space stacking context */
  margin: 0;
  cursor: pointer;
}

Les styles transform-style et position préparent le pseudo-élément que nous allons introduire plus tard pour styliser la mise en surbrillance. Sinon, il s'agit principalement de petites choses liées au style qui relèvent de mon opinion. Je préfère que le curseur soit un pointeur, j'aime les décalages de contour, les cases à cocher par défaut sont trop petites et, si accent-color est pris en charge, intégrez ces cases à cocher dans la palette de couleurs de la marque.

Libellés de cases à cocher

Il est important de fournir des libellés pour les cases à cocher pour deux raisons. La première consiste à indiquer à quoi sert la valeur de la case à cocher, pour répondre à la question "activé ou désactivé pour quoi ?". La seconde concerne l'UX : les utilisateurs Web se sont habitués à interagir avec les cases à cocher via les libellés associés.

entrée
<input
  type="checkbox"
  id="text-notifications"
  name="text-notifications"
>
étiquette
<label for="text-notifications">
  <h3>Text Messages</h3>
  <small>Get notified about all text messages sent to your device</small>
</label>

Sur votre libellé, ajoutez un attribut for qui pointe vers une case à cocher par ID : <label for="text-notifications">. Sur votre case à cocher, doublez le nom et l'ID pour vous assurer qu'elle est trouvée avec différents outils et technologies, comme une souris ou un lecteur d'écran : <input type="checkbox" id="text-notifications" name="text-notifications">. :hover, :active et d'autres fonctionnalités sont disponibles sans frais avec la connexion, ce qui augmente les possibilités d'interaction avec votre formulaire.

Mise en surbrillance de la case à cocher

Je souhaite que mes interfaces soient cohérentes. L'élément de curseur présente une belle mise en surbrillance de la miniature que j'aimerais utiliser avec la case à cocher. La miniature a pu utiliser box-shadow et sa propriété spread pour agrandir et réduire une ombre. Toutefois, cet effet ne fonctionne pas ici, car nos cases à cocher sont carrées, et doivent l'être.

J'ai pu obtenir le même effet visuel avec un pseudo-élément et une quantité malheureuse de CSS délicat :

@custom-media --motionOK (prefers-reduced-motion: no-preference);

input[type="checkbox"]::before {
  --thumb-scale: .01;                        /* initial scale of highlight */
  --thumb-highlight-size: var(--space-xl);

  content: "";
  inline-size: var(--thumb-highlight-size);
  block-size: var(--thumb-highlight-size);
  clip-path: circle(50%);                     /* circle shape */
  position: absolute;                         /* this is why position relative on parent */
  top: 50%;                                   /* pop and plop technique (https://web.dev/centering-in-css#5-pop-and-plop) */
  left: 50%;
  background: var(--thumb-highlight-color);
  transform-origin: center center;            /* goal is a centered scaling circle */
  transform:                                  /* order here matters!! */
    translateX(-50%)                          /* counter balances left: 50% */
    translateY(-50%)                          /* counter balances top: 50% */
    translateZ(-1px)                          /* PUTS IT BEHIND THE CHECKBOX */
    scale(var(--thumb-scale))                 /* value we toggle for animation */
  ;
  will-change: transform;

  @media (--motionOK) {                       /* transition only if motion is OK */
    & {
      transition: transform .2s ease;
    }
  }
}

/* on hover, set scale custom property to "in" state */
input[type="checkbox"]:hover::before {
  --thumb-scale: 1;
}

Créer un pseudo-élément de cercle est une tâche simple, mais le placer derrière l'élément auquel il est associé était plus difficile. Voici ce que j'ai obtenu avant et après avoir résolu le problème :

Il s'agit d'une micro-interaction, mais il est important pour moi de conserver la cohérence visuelle. La technique de mise à l'échelle de l'animation est la même que celle que nous avons utilisée ailleurs. Nous définissons une propriété personnalisée sur une nouvelle valeur et laissons CSS la faire passer en fonction des préférences de mouvement. La fonctionnalité clé ici est translateZ(-1px). Le parent a créé un espace 3D, et cet enfant pseudo-élément y a puisé en se plaçant légèrement en arrière dans l'espace Z.

Accessibilité

La vidéo YouTube montre très bien les interactions avec la souris, le clavier et le lecteur d'écran pour ce composant de paramètres. Je vais vous donner quelques détails.

Choix des éléments HTML

<form>
<header>
<fieldset>
<picture>
<label>
<input>

Chacun d'eux contient des conseils et astuces pour l'outil de navigation de l'utilisateur. Certains éléments fournissent des conseils d'interaction, d'autres connectent l'interactivité et d'autres encore aident à façonner l'arborescence d'accessibilité dans laquelle un lecteur d'écran navigue.

Attributs HTML

Nous pouvons masquer les éléments dont les lecteurs d'écran n'ont pas besoin, en l'occurrence l'icône à côté du curseur :

<picture aria-hidden="true">

La vidéo ci-dessus montre le flux du lecteur d'écran sur macOS. Notez que la mise au point de l'entrée passe directement d'un curseur à l'autre. En effet, nous avons masqué l'icône qui aurait pu être un arrêt sur le chemin du curseur suivant. Sans cet attribut, un utilisateur devrait s'arrêter, écouter et passer l'image qu'il ne peut pas voir.

Le SVG est un ensemble de calculs. Ajoutons un élément <title> pour un titre libre au survol de la souris et un commentaire lisible sur ce que les calculs créent :

<svg viewBox="0 0 24 24">
  <title>A note icon</title>
  <path d="M12 3v10.55c-.59-.34-1.27-.55-2-.55-2.21 0-4 1.79-4 4s1.79 4 4 4 4-1.79 4-4V7h4V3h-6z"/>
</svg>

À part ça, nous avons utilisé suffisamment de code HTML clairement indiqué pour que les tests de formulaire fonctionnent très bien avec la souris, le clavier, les manettes de jeu vidéo et les lecteurs d'écran.

JavaScript

J'ai déjà expliqué comment la couleur de remplissage de la piste était gérée à partir de JavaScript. Examinons maintenant le JavaScript associé à <form> :

const form = document.querySelector('form');

form.addEventListener('input', event => {
  const formData = Object.fromEntries(new FormData(form));
  console.table(formData);
})

Chaque fois que l'utilisateur interagit avec le formulaire et le modifie, la console enregistre le formulaire en tant qu'objet dans un tableau pour faciliter l'examen avant l'envoi à un serveur.

Capture d&#39;écran des résultats console.table(), où les données du formulaire sont affichées dans un tableau

Conclusion

Maintenant que vous savez comment j'ai fait, comment feriez-vous ? Voilà une architecture de composants amusante ! Qui va créer la première version avec des emplacements dans son framework préféré ? 🙂

Diversifions nos approches et découvrons toutes les façons de créer sur le Web. Créez une démo, tweetez-moi les liens et je l'ajouterai à la section Remixes de la communauté ci-dessous !

Remix de la communauté

  • @tomayac pour son style concernant la zone de survol des libellés des cases à cocher ! Cette version ne comporte aucun espace vide entre les éléments : démo et source.