Maîtriser contenteditable=plaintext-only : le guide technique pour des saisies propres et sécurisées

Dans le développement d’interfaces modernes, la gestion des entrées utilisateur est un défi permanent. Vous avez
sûrement déjà été confronté au problème suivant : un utilisateur copie-colle un texte riche depuis une page web ou un
document Word dans votre zone de commentaire, et voilà que votre mise en page explose, polluée par des balises <span>
inutiles, des styles inline, voire des scripts malveillants.
Pendant longtemps, nous avons utilisé des textarea pour leur simplicité, au prix d’une gestion complexe de l’
auto-expansion. Ou alors, nous avons forcé contenteditable en développant des usines à gaz en JavaScript pour nettoyer
les données à la volée.
Il existe désormais une solution native, robuste et extrêmement performante : l’attribut
contenteditable="plaintext-only".
Qu’est-ce que contenteditable=“plaintext-only” ?
Il s’agit d’une valeur spécifique pour l’attribut HTML contenteditable. Lorsqu’elle est appliquée à un élément (
généralement un <div> ou un <span>), le navigateur restreint strictement le comportement de saisie et de collage.
Contrairement au mode contenteditable="true" classique qui autorise la création de structures DOM complexes (nœuds de
texte, balises de formatage, images), le mode plaintext-only impose une contrainte forte : seuls les caractères
textuels et les retours à la ligne sont acceptés.
Tout contenu riche collé est immédiatement converti en texte brut par le moteur de rendu du navigateur avant même d’atteindre votre gestionnaire d’événements.
Pourquoi est-ce un levier stratégique ?
1. Sécurité renforcée par le design
Le premier argument est la sécurité. En autorisant du texte riche via contenteditable="true", vous vous exposez
potentiellement à des failles XSS (Cross-Site Scripting) si votre processus de nettoyage (sanitization) est incomplet ou
contourné.
Avec plaintext-only, la surface d’attaque est drastiquement réduite. Le navigateur n’interprète pas les balises HTML
insérées. Un attaquant qui tente d’injecter <script>alert(1)</script> verra ces caractères s’afficher comme du texte
littéral, sans aucune exécution. C’est le principe de la défense en profondeur par le choix technologique.
2. Performance et expérience utilisateur (UX)
Dans un contexte où chaque milliseconde compte, éviter le traitement JavaScript lourd est crucial.
- Réduction du DOM : Plus besoin de parser des arbres DOM complexes générés par des copier-coller malveillants.
- Auto-expansion native : En utilisant un
<div>aveccontenteditable="plaintext-only", vous bénéficiez nativement d’une zone qui s’adapte à la hauteur du contenu, sans écouteurs d’événements JavaScriptinputcomplexes pour recalculer la hauteur (comme c’était le cas pour lestextareaauto-ajustables).
3. Cohérence du contenu
Vos bases de données recevront des données uniformes. Fini les mélanges de polices, les couleurs disparates et les structures DOM inattendues qui rendent l’affichage ou le traitement backend (comme la génération de PDF ou l’exportation) imprévisibles.
Implémentation technique
L’implémentation est triviale, mais nécessite une attention particulière sur le style CSS pour conserver l’aspect d’une zone de saisie.
.input-field {
/* Utilisation de clamp pour une largeur fluide et réactive */
inline-size : clamp(18.75rem, 50%, 50rem);
min-block-size : 1.5em;
padding : .625rem;
border : .0625rem solid #ccc;
/* Assurer une typographie lisible */
font-family : sans-serif;
/* Éviter les surécritures inutiles avec :not */
&:not([contenteditable='plaintext-only']) {
border-color : red;
}
}
Voici comment structurer votre composant HTML :
<div
class="input-field"
contenteditable="plaintext-only"
role="textbox"
aria-multiline="true"
placeholder="Enter your text here...">
</div>
Le rôle de l’accessibilité
Il est indispensable d’ajouter role=textbox et aria-multiline=true pour que les technologies d’assistance
comprennent qu’il s’agit d’un champ de saisie textuel. Sans cela, l’élément n’est pas correctement interprété comme un
contrôle de formulaire.
Comparaison avec les alternatives
| Approche | Sécurité | Performance | Effort de dev |
|---|---|---|---|
textarea | Élevée | Élevée | Moyen (auto-resize) |
contenteditable=true | Faible | Faible | Très élevé (nettoyage) |
contenteditable=plaintext-only | Élevée | Élevée | Très faible |
Limitations et bonnes pratiques
Bien que puissant, ce mode a ses limites :
- Support navigateur : Il est largement supporté dans les navigateurs modernes (Chromium, WebKit). Vérifiez toujours la compatibilité si vous ciblez des environnements très spécifiques.
- Gestion des événements : Même si le texte est “propre”, vous devez toujours gérer les événements
inputoublurpour capturer la donnée et l’envoyer à votre backend. - Le placeholder :
contenteditablene supporte pas l’attributplaceholdernativement. Vous devrez utiliser une astuce CSS avec la pseudo-classe:emptypour afficher un texte d’aide lorsque le champ est vide.
[contenteditable='plaintext-only']:empty::before {
content : attr(data-placeholder);
color : #888;
}
Conclusion
Le passage à contenteditable="plaintext-only" n’est pas seulement une amélioration syntaxique. C’est un changement de
paradigme qui place la sécurité et la performance au cœur du design de vos interfaces. En déléguant la contrainte de
formatage au navigateur, vous libérez du temps de développement pour des fonctionnalités à plus haute valeur ajoutée,
tout en garantissant une expérience utilisateur cohérente et rapide.
N’attendez pas pour auditer vos champs de saisie actuels et migrer vers cette approche native.
FAQ
Est-ce que je peux quand même autoriser les emojis ?
Oui. Les emojis sont des caractères Unicode standard.plaintext-only les autorise parfaitement car ils ne
constituent pas du formatage HTML.
Comment récupérer la valeur avec JavaScript ?
Vous accédez au contenu exactement comme pour n'importe quel élément : utilisezelement.innerText ou
element.textContent pour récupérer le texte brut.
Qu'arrive-t-il si l'utilisateur essaie de coller du texte avec des liens ?
Le navigateur va automatiquement extraire uniquement la chaîne de caractères du lien, sans conserver la balise<a> ni l'attribut href. Le lien deviendra du texte brut non cliquable.
Puis-je utiliser cela dans un formulaire complexe ?
Oui, mais attention : undiv n'est pas soumis automatiquement avec le formulaire comme un input
ou textarea. Vous devez capturer le contenu en JavaScript et l'injecter dans un champ hidden
lors de la soumission du formulaire.
