Au moment de la rédaction de ce tutoriel, cette fonctionnalité est disponible sur les navitageurs basés sur Chromium à partir de la version 134 (Chrome, Edge, Chrome Android, Webview Android).
Jusqu'à maintenant, pour personnaliser en profondeur un <select> en CSS, il fallait ruser et utiliser un assemblage de balises HTML, de CSS et de Javascript. Mais réjouissez-vous, depuis peu, tout est devenu beaucoup plus simple.
Commençons par créer un sélecteur en HTML :
<h1>Veuillez sélectionner votre agence web favorite :</h1>
<select>
<option value="agence-karac">Agence karac</option>
<option value="karac-web-sarl">karac web Sàrl</option>
<option value="karac">karac</option>
</select>
Ajoutez le CSS suivant dans la balise <head> de la page ou dans un fichier .css séparée :
select,
select::picker(select) {
appearance: base-select;
}
Si l'on affiche le résultat dans un navigateur, on peut déjà constater que le "select" change légèrement d'apparance. Il passe de ceci :
à cela :
Voyons maintenant comment le personnaliser à notre sauce. Jusqu'en 2025, on pouvait déjà personnaliser certaines choses comme la couleur de fond ou la couleur du texte en faisant :
select {
background-color: #8ec89a;
color: white;
}
Ce qui est nouveau par contre, c'est que l'on puisse également modifier l'icône (qui est une flèche à l'origine) en utilisant le pseudo-element ::picker-icon de cette façon :
select::picker-icon {
content:'\2665';
color: white;
}
Ce qui nous donne, s'il on met le tout bout à bout, le résultat douteux suivant :
Si l'on reprend le pseudo-element ::picker(select) et qu'on y ajoute quelques propriétés CSS, on peut également personnaliser le contenu de la box qui s'ouvre lorsque l'on clic sur le sélecteur :
select::picker(select) {
appearance: base-select;
padding: 0.5rem;
border: 2px solid #8ec89a;
border-radius: 10px;
background-color: white;
color: #8ec89a;
}
Les nouveautés ne se situent pas qu'au niveau du CSS, puisque l'on est désormais autorisé à écrire du HTML directement à l'intérieur de notre balise <select>. Donc si je décide de mettre le logo de karac pour chaque option, rien ne m'empêchera de le faire, et d'ailleurs, pourquoi s'en priver ?
<select>
<option value="agence-karac">
<img src="just-k.png" alt="k comme karac">
Agence karac
</option>
<option value="karac-web-sarl">
<img src="just-k.png" alt="k comme karac">
karac web Sàrl
</option>
<option value="karac">
<img src="just-k.png" alt="k comme karac">
karac
</option>
</select>
On peut ajouter un peu de CSS pour rendre tout cela plus esthétique :
select option {
display: flex;
}
select option img {
width: 25px;
}
On a bien nos icônes devant chaque option du "select".
On va également pouvoir personnaliser ou supprimer la "checkmark" (la petite icône à gauche qui indique l'option sélectionnée. Pour cela, on utilisera le pseudo-element ::checkmark comme ceci :
option::checkmark {
content: '\2729';
}
Si on résume le code que l'on a écrit jusqu'à maintenant, on a pour le HTML :
<h1>Veuillez sélectionner votre agence web favorite :</h1>
<select>
<option value="agence-karac">
<img src="just-k.png" alt="k comme karac">
Agence karac
</option>
<option value="karac-web-sarl">
<img src="just-k.png" alt="k comme karac">
karac web Sàrl
</option>
<option value="karac">
<img src="just-k.png" alt="k comme karac">
karac
</option>
</select>
Et pour le CSS :
select,
select::picker(select) {
appearance: base-select;
padding: 0.5rem;
border: 2px solid #8ec89a;
border-radius: 10px;
background-color: white;
color: #8ec89a;
}
select {
background-color: #8ec89a;
color: white;
}
select::picker-icon {
content:'\2665';
color: white;
}
select option {
display: flex;
}
select option img {
width: 25px;
}
option::checkmark {
content: '\2729';
}
On a déjà quelque chose qui nous permet d'aller assez loin dans la personnalisation. Mais il est possible d'aller encore plus loin.
Il est maintenant possible de choisir à quel endroit par rapport au sélecteur, la liste des options s'ouvrira en ajoutant ces deux propriétées au pseudo-element ::picker(select) :
top: anchor(top);
left: anchor(center);
top : anchor(top)
Le haut de la liste des options sera en haut du sélecteur
left : anchor(center)
La gauche de la liste des options sera au centre du sélecteur
C'est un choix curieux mais c'est pour l'exemple.
Vous avez peut-être remarqué que jusqu'à maintenant, on n'a pas pu personnaliser autant la sélection courante du sélecteur que les options. Pourtant cela pourrait être pratique, par exemple pour appliquer le même style à la sélection courante qu'aux options.
Et bien c'est également prévu. Pour faire cela, il va falloir ajouter une balise <button> au tout début de notre <select> et y ajouter la balise <selectedcontent></selectedcontent> dans laquelle viendra se greffer automatiquement la sélection courante.
<button>
<selectedcontent></selectedcontent>
<svg fill="#8ec89a" version="1.1" width="26" height="26" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 100 100" enable-background="new 0 0 100 100" xml:space="preserve" stroke="#8ec89a"><g id="SVGRepo_bgCarrier" stroke-width="0"></g><g id="SVGRepo_tracerCarrier" stroke-linecap="round" stroke-linejoin="round"></g><g id="SVGRepo_iconCarrier"> <g> <path d="M49.288,59.647c0.383,0.348,0.863,0.519,1.342,0.519c0.076,0,0.151-0.015,0.228-0.023c0.028,0.001,0.057,0.008,0.085,0.008 c0.545,0,1.088-0.222,1.482-0.657l15.231-16.804c0.742-0.818,0.68-2.083-0.139-2.824c-0.818-0.743-2.083-0.679-2.824,0.139 L50.656,55.49L35.169,41.453c-0.819-0.744-2.083-0.68-2.824,0.139c-0.742,0.818-0.68,2.083,0.139,2.824L49.288,59.647z"></path> <path d="M50,83.214c18.449,0,33.458-15.009,33.458-33.457c0-18.449-15.009-33.458-33.458-33.458 c-18.448,0-33.457,15.009-33.457,33.458C16.543,68.205,31.552,83.214,50,83.214z M50,20.299c16.243,0,29.458,13.215,29.458,29.458 c0,16.242-13.215,29.457-29.458,29.457c-16.242,0-29.457-13.215-29.457-29.457C20.543,33.514,33.758,20.299,50,20.299z"></path></g></g></svg>
</button>
Le HTML de notre <select> ressemble désormais à cela :
<select>
<button>
<selectedcontent></selectedcontent>
<svg fill="#8ec89a" version="1.1" width="26" height="26" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 100 100" enable-background="new 0 0 100 100" xml:space="preserve" stroke="#8ec89a"><g id="SVGRepo_bgCarrier" stroke-width="0"></g><g id="SVGRepo_tracerCarrier" stroke-linecap="round" stroke-linejoin="round"></g><g id="SVGRepo_iconCarrier"> <g> <path d="M49.288,59.647c0.383,0.348,0.863,0.519,1.342,0.519c0.076,0,0.151-0.015,0.228-0.023c0.028,0.001,0.057,0.008,0.085,0.008 c0.545,0,1.088-0.222,1.482-0.657l15.231-16.804c0.742-0.818,0.68-2.083-0.139-2.824c-0.818-0.743-2.083-0.679-2.824,0.139 L50.656,55.49L35.169,41.453c-0.819-0.744-2.083-0.68-2.824,0.139c-0.742,0.818-0.68,2.083,0.139,2.824L49.288,59.647z"></path> <path d="M50,83.214c18.449,0,33.458-15.009,33.458-33.457c0-18.449-15.009-33.458-33.458-33.458 c-18.448,0-33.457,15.009-33.457,33.458C16.543,68.205,31.552,83.214,50,83.214z M50,20.299c16.243,0,29.458,13.215,29.458,29.458 c0,16.242-13.215,29.457-29.458,29.457c-16.242,0-29.457-13.215-29.457-29.457C20.543,33.514,33.758,20.299,50,20.299z"></path></g></g></svg>
</button>
<option value="agence-karac">
<img src="just-k.png" alt="k comme karac">
Agence karac
</option>
<option value="karac-web-sarl">
<img src="just-k.png" alt="k comme karac">
karac web Sàrl
</option>
<option value="karac">
<img src="just-k.png" alt="k comme karac">
karac
</option>
</select>
Vous aurez peut-être remarqué que j'ai ajouté une icône au format SVG qui remplacera le coeur qu'on avait jusqu'à maintenant.
Il va aussi falloir adapter notre CSS de la même manière qu'on l'avait fait pour les options.
Pour ce dernier exemple, j'ai ajusté plusieurs paramètres pour obtenir le résultat que je voulais.
Avec sa liste d'options :
Voici le code final en intégralité :
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Personnaliser un "select"</title>
<style>
body {
font-family: 'Trebuchet MS', sans-serif;
}
select,
select::picker(select) {
appearance: base-select;
padding: 0.5rem;
border: 0;
color: #8ec89a;
background-color: #f3f9f4;
}
select::picker(select) {
margin-bottom: 1rem;
border-radius: 25px;
}
select {
border-radius: 25px;
background-color: #f3f9f4;
}
select::picker-icon {
display: none;
}
select option {
display: flex;
padding: 0.5rem;
}
select selectedcontent {
display: flex;
align-items: center;
color: #8ec89a;
}
select selectedcontent img {
padding-right: 0.5rem;
width: 25px;
}
select option img {
width: 25px;
}
option::checkmark {
content: '\2729';
}
</style>
</head>
<body>
<h1>Veuillez sélectionner votre agence web favorite :</h1>
<select>
<button>
<selectedcontent></selectedcontent>
<svg fill="#8ec89a" version="1.1" width="26" height="26" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 100 100" enable-background="new 0 0 100 100" xml:space="preserve" stroke="#8ec89a"><g id="SVGRepo_bgCarrier" stroke-width="0"></g><g id="SVGRepo_tracerCarrier" stroke-linecap="round" stroke-linejoin="round"></g><g id="SVGRepo_iconCarrier"> <g> <path d="M49.288,59.647c0.383,0.348,0.863,0.519,1.342,0.519c0.076,0,0.151-0.015,0.228-0.023c0.028,0.001,0.057,0.008,0.085,0.008 c0.545,0,1.088-0.222,1.482-0.657l15.231-16.804c0.742-0.818,0.68-2.083-0.139-2.824c-0.818-0.743-2.083-0.679-2.824,0.139 L50.656,55.49L35.169,41.453c-0.819-0.744-2.083-0.68-2.824,0.139c-0.742,0.818-0.68,2.083,0.139,2.824L49.288,59.647z"></path> <path d="M50,83.214c18.449,0,33.458-15.009,33.458-33.457c0-18.449-15.009-33.458-33.458-33.458 c-18.448,0-33.457,15.009-33.457,33.458C16.543,68.205,31.552,83.214,50,83.214z M50,20.299c16.243,0,29.458,13.215,29.458,29.458 c0,16.242-13.215,29.457-29.458,29.457c-16.242,0-29.457-13.215-29.457-29.457C20.543,33.514,33.758,20.299,50,20.299z"></path></g></g></svg>
</button>
<option value="agence-karac">
<img src="just-k.png" alt="k comme karac">
Agence karac
</option>
<option value="karac-web-sarl">
<img src="just-k.png" alt="k comme karac">
karac web Sàrl
</option>
<option value="karac">
<img src="just-k.png" alt="k comme karac">
karac
</option>
</select>
</body>
</html>
Les possibilités ne s'arrêtent pas là et pourraient s'étendre à l'avenir sur d'autres éléments de formulaires. On pourrait par exemple rassembler les options dans des groupes d'options avec des variations de design, faire plusieurs colonnes d'options, mettre des effets de transition, etc.
Vous pourrez avoir plus d'infos sur les possibilités déjà implémentées suivre l'avancement de tout cela sur la doc MDN.