Penser “Composants” en design et développement
Plongez au cœur du développement web où les composants marient ingénieusement fonctionnalité et esthétique. Explorez comment ces briques essentielles de code peuvent révolutionner l'interaction utilisateur, rendant chaque expérience à la fois plus intuitive et engageante.
Les composants occupent une place fondamentale dans le développement web actuel. Ils permettent aux développeurs de construire et réutiliser des parties plus ou moins importantes de code qui peuvent être assemblées pour créer des interfaces utilisateurs complexes. Dans cet article, nous allons voir ce qui, techniquement, définit un composant, quels sont les bénéfices à en utiliser et le lien qui existe entre les composants en design et ceux en développement.
Qu’est-ce qu’un composant ?
Techniquement parlant, un composant est un module de code indépendant qui encapsule une fonctionnalité spécifique. Les principales caractéristiques d’un composant sont qu’il doit :
- être réutilisable,
- être possiblement modulable, avec notamment certaines propriétés,
- suivre une convention de nommage,
- être facile à comprendre et utiliser.
Plus schématiquement, pour concevoir une fonctionnalité, il est nécessaire de l'imaginer et de la décomposer en "briques" qui seront ensuite reliées entre elles. Un composant est donc une brique de code, pouvant être utilisé et réutilisé à divers endroits dans l’application. En termes de design, un composant est dans sa fondation un élément qui répond à un besoin d’un utilisateur, il est donc souvent interactif ou sert de communication avec l’utilisateur.
Pourquoi utiliser des composants en développement ?
Découper le code en composants offre de nombreux avantages :
- Centraliser, on regroupe le code à un seul endroit.
- Réduire le code, le centraliser implique donc, implicitement, une réduction du volume de code fourni, étant donné qu’il n’y a plus de duplication.
- Limiter le potentiel de bugs, en effet, si on imagine le même code utilisé à plusieurs endroits sans être centralisé, et qu’on le modifie à un endroit, mais pas aux autres, des bugs peuvent survenir. Le centraliser permet de faire une seule modification, qui sera effective partout.
- Améliorer la compréhension, moins de volume signifie souvent une meilleure compréhension.
- Être évolutif, au fur et à mesure qu'une application gagne en complexité, les composants peuvent être combinés et réutilisés pour créer des interfaces plus complexes. Ce qui facilite la gestion de grandes bases de code et permet le maintien d’une expérience utilisateur cohérente.
Un des seuls “défaut” de cette approche serait d’avoir potentiellement plus de fichiers/dossiers et donc une architecture de projet nécessitant une très bonne organisation pour s’y retrouver. Chez Atipik, nous privilégions la mise en place de design systems pour les projets qui comportent un nombre de composants important.
Pourquoi utiliser des composants en design ?
De la même manière, lorsqu’on design un produit, il est très intéressant d’utiliser des composants. Parmi les principaux avantages, on retrouve :
- Apporter une cohérence à l’expérience utilisateur, avoir des composants ayant un même style et une même interaction partout dans l’application permet d’avoir une interface cohérente et simple à utiliser.
- Être évolutif, pouvoir suivre l’évolution du produit et s’adapter à de nouveaux besoins utilisateurs.
- Réduire l’effort, en centralisant le style des composants, cela permet d’apporter des changements en un clin d’oeil et de les appliquer à toutes les vues de l’application en même temps.
- Limiter les incohérences de style, ne plus avoir de duplication de style permet de ne pas avoir à appliquer les éventuelles mises à jour de design partout. Un seul endroit suffit, et cela limite, voire empêche, les incohérences dans les vues.
Le point positif le plus important selon moi est que, combinées, ces approches en design ET en développement permettent une meilleure compréhension ainsi qu’une communication plus fluide entre designers et développeurs. En effet, on reprenant les mêmes termes, les mêmes noms, les mêmes propriétés pour les composants, cela simplifie grandement le travail du développeur pour mettre en œuvre les spécifications de conception. Sans parler du gain de temps lors d’éventuelles mises à jour de design. Par exemple, imaginons un composant “Button”, si celui-ci vient à changer en design, en tant que développeur on n’a pas besoin de chercher où faire la modification, on va directement dans le ficher du composant Button.
Il existe des outils permettant de construire des interfaces utilisateurs à l’aide de composants, les plus connus sont surement Figma (que nous utilisons chez Atipik), Sketch et Adobe XD. L’avantage de Figma est qu’il permet une collaboration plus facile entre membres d’une équipe, via notamment la possibilité de travailler en temps réel avec les designers ou développeurs (commentaires, partage de design, modification en temps réel, etc.).
Exemple pratique de l’utilisation de composants
Contexte de l’exemple : on souhaite avoir une liste qui répertorie les différents produits que l’on a en stock. Un champ de recherche est présent afin de filtrer la liste. Le design, très simpliste, car ayant peu d’importance ici, ressemblera à ça :
Dès qu’on voit ou qu’on imagine une fonctionnalité (comme dans notre cas), le premier réflexe est de remarquer les éléments qui semblent se répéter. Une fois identifiés, on peut alors en faire des composants réutilisables.
Ici, ce qui saute aux yeux, c’est la liste de produits. En effet, on remarque que la liste affiche toujours les mêmes types de valeurs dans le même ordre : nom du produit, prix. On a donc tout intérêt de créer un composant prenant en paramètre un produit et affichant ces mêmes informations.
Pour l’exemple, j’utilise ici le framework Vue dans sa version 3. Ce premier composant sera donc comme suit :
// src/components/ProductListItem.vue
<script setup>
const props = defineProps({
// le paramètre produit passé au composant
product: {
type: Object,
required: true,
},
});
</script>
<template>
<tr>
<td>
{{ product.name }}
</td>
<td>{{ product.price }}€</td>
</tr>
</template>
Ensuite, on “remonte” l’architecture en se disant qu’il serait bien de regrouper l’affichage de la liste dans un composant. On aura donc un paramètre contenant la liste des produits à afficher, sur laquelle on itèrera en utilisant notre composant précédemment créé pour afficher nos produits un par un. Cela donne donc :
// src/components/ProductList.vue
<script setup>
import { computed } from "vue";
import ProductListItem from "./ProductListItem";
const props = defineProps({
// on passe en paramètre la liste des produits à afficher
products: {
type: Array,
required: true,
},
});
</script>
<template>
<table class="list-table">
<thead>
<tr>
<th>Name</th>
<th>Price</th>
</tr>
</thead>
<tbody>
<ProductListItem
v-for="product in products"
:key="product.name"
:product="product"
/>
</tbody>
</table>
</template>
<style scoped>
.list-table {
margin-top: 1rem;
text-align: left;
border-collapse: collapse;
}
.list-table th {
border-bottom: solid 1px black;
}
</style>
Puis, le dernier composant potentiellement réutilisable serait ici le champ de recherche. D’ailleurs, on pourrait se dire qu’ici ni la liste ni le champ de recherche ne sont réutilisés. Cependant il convient toujours de se poser la question de savoir s’il y a un potentiel de réutilisation plus tard dans d’autres fonctionnalités. Ici, on se rend compte qu’effectivement un champ de recherche et une liste de produits peuvent potentiellement être affichés et utilisés à d’autres endroits dans le code.
On crée donc notre champ de recherche :
// src/components/MyInput.vue
<script setup>
import { computed } from "vue";
const props = defineProps({
valueModel: {
type: String,
required: true,
},
});
const emit = defineEmits(["update:valueModel"]);
const value = computed({
get() {
return props.valueModel;
},
set(newValue) {
emit("update:valueModel", newValue);
},
});
</script>
<template>
<input v-model="value" class="my-input" />
</template>
<style scoped>
.my-input {
border: solid 1px black;
outline: none;
border-radius: 5px;
padding: 0.2rem 0.4rem;
}
.my-input:focus {
border-color: rgb(46, 168, 250);
}
</style>
Enfin, on utilise nos composants dans notre fichier principal, ici App. Ce fichier contiendra la valeur de notre liste de produits, passée au composant dédié, ainsi que la valeur du champ de recherche, servant à filtrer la liste.
// src/App.vue
<script setup>
import ProductList from "./components/ProductList";
import MyInput from "./components/MyInput";
import { ref, watch } from "vue";
const searchValue = ref("");
const products = ref([
{ name: "Pencil", price: 5.5 },
{ name: "Rubber", price: 3.9 },
{ name: "Ruler", price: 8.2 },
{ name: "Cisors", price: 12 },
]);
</script>
<template>
<div class="container">
<MyInput
v-model:valueModel="searchValue"
placeholder="Search a product..."
/>
<ProductList
:products="
products.filter((product) =>
product.name.toLowerCase().includes(searchValue.toLowerCase())
)
"
/>
</div>
</template>
<style>
.container {
display: flex;
flex-direction: column;
max-width: 15rem;
}
</style>
Et voilà ! Maintenant, imaginons que les designs changent et qu’on ne veut plus que le prix soit affiché en noir, mais en orange. Rien de plus simple :
// on va dans le composant concerné : src/components/ProductListItem.vue
// et on passe de cette ligne :
<td>{{ product.price }}€</td>
// à cette ligne :
<td style="color: orange">{{ product.price }}€</td>
Hop, notre prix s’affiche désormais en orange sur tous les produits.
Limite des composants
Bien que l’utilisation de composants comporte de nombreux avantages, il serait faux de dire que c’est un système parfait.
En effet, si les composants permettent de regrouper un comportement commun aux éléments d’une application, ils deviennent potentiellement vite lourds dès que la complexité de l’application augmente. Par exemple un composant “select” (ou “dropdown”) peut vite comporter de la logique complexe et spécifique à certains cas (select simple/multiple, prise en compte des tableaux / chaines de caractères / objets en tant que valeurs, groupes, personnalisation des éléments dans la listes, etc.). Il peut vite y avoir beaucoup de cas spéciaux et cela peut entraîner des effets de bords indésirables, notamment aux endroits où le composant est déjà utilisé.
De plus, lorsqu’un projet prend de l’ampleur, le nombre de composants peut fortement augmenter et induire une certaine difficulté dans leur gestion. Une bonne organisation/structure est alors absolument nécessaire.
Conclusion
Les composants sont un outil puissant pour les développeurs ainsi que les designers. C’est un langage commun, une zone d’échanges. Ils permettent notamment d’améliorer l’efficacité et la communication entre les deux équipes. Il faut cependant s’y prendre de manière appropriée et utilisant par exemple les mêmes noms, attributs, etc.
Une fois les bonnes conditions réunies, le développement d’un projet n’en sera que plus rapide et efficace
Jérémy
Ingénieur Logiciel · Web