Comment trouver des éléments DOM par texte
Il n’existe pas de méthode getElementByText() dans l’API DOM. Si vous devez localiser un élément en fonction de son contenu textuel plutôt que de son type, vous devez construire cette fonctionnalité vous-même. Ce besoin se présente plus souvent qu’on ne le pense — scripts d’automatisation, tests d’interface utilisateur, analyse de contenu dynamique — et l’approche appropriée dépend du niveau de flexibilité dont vous avez besoin.
Points clés à retenir
- L’API DOM ne dispose d’aucune méthode native pour sélectionner des éléments par contenu textuel, mais trois approches natives comblent cette lacune : le filtrage avec
querySelectorAll, le parcours avecTreeWalkeret l’interrogation avec XPath. TreeWalkerest l’option native la plus polyvalente pour effectuer des recherches textuelles complètes dans le DOM sur n’importe quel type d’élément sans collecter au préalable une grande NodeList.- Privilégiez
textContentplutôt queinnerTextpour la correspondance de texte — c’est plus rapide, cela évite de déclencher un recalcul de mise en page et le comportement est cohérent quelle que soit la visibilité de l’élément. - Attention aux pièges courants comme les espaces blancs superflus, le texte des descendants imbriqués et le contenu injecté dynamiquement qui peut ne pas être présent lors de l’exécution de votre script.
Pourquoi querySelector ne peut pas interroger le DOM par contenu textuel
querySelector() et querySelectorAll() n’acceptent que des sélecteurs CSS. Bien que CSS dispose d’une pseudo-classe :has() et de sélecteurs d’attributs, il n’existe aucun sélecteur CSS standard pour faire correspondre le contenu textuel d’un élément. Des sélecteurs comme div:text("Submit") n’existent tout simplement pas dans la spécification.
Il vous reste donc trois approches pratiques : filtrer un ensemble de candidats, parcourir le DOM avec une API native ou utiliser XPath.
Méthode 1 : Filtrer un ensemble de candidats par texte
L’approche la plus simple consiste à interroger les éléments par balise ou classe, puis à filtrer par texte. Cela fonctionne bien lorsque vous connaissez le type d’élément à l’avance.
function findByText(tag, text) {
return [...document.querySelectorAll(tag)].filter(el =>
el.textContent.trim() === text
)
}
// Usage
const buttons = findByText('button', 'Submit')
Cette méthode est lisible et rapide lorsque l’ensemble de candidats est petit. La faiblesse : elle ne recherche qu’un seul type d’élément à la fois. Rechercher tous les éléments avec '*' fonctionne mais est plus lent sur les DOM volumineux.
Méthode 2 : Parcourir le DOM avec TreeWalker
TreeWalker est une API DOM native qui vous permet de parcourir les nœuds efficacement. Elle est bien prise en charge par tous les navigateurs modernes et évite la surcharge liée à la collecte d’une NodeList complète au préalable.
function findElementsByText(root, text) {
const walker = document.createTreeWalker(
root,
NodeFilter.SHOW_ELEMENT,
{
acceptNode(node) {
return node.textContent.trim() === text
? NodeFilter.FILTER_ACCEPT
: NodeFilter.FILTER_SKIP
}
}
)
const results = []
while (walker.nextNode()) results.push(walker.currentNode)
return results
}
// Usage
const matches = findElementsByText(document.body, 'TV')
Cette méthode recherche n’importe quel type d’élément dans l’ensemble de l’arborescence — une solution générique que l’approche spécifique par balise ne peut pas fournir. Elle prend également en charge l’arrêt anticipé si vous n’avez besoin que de la première correspondance.
Remarque sur
FILTER_SKIPvs.FILTER_REJECT: L’utilisation deFILTER_SKIPici signifie que le walker descend toujours dans les enfants d’un nœud non correspondant. Si vous utilisiezFILTER_REJECTà la place, le walker ignorerait le nœud et toute sa sous-arborescence. Pour la recherche de texte,FILTER_SKIPest presque toujours ce que vous voulez, car letextContentd’un parent peut ne pas correspondre même si celui d’un descendant plus profond correspond.
Discover how at OpenReplay.com.
Méthode 3 : Recherche de texte XPath dans le DOM
Pour une correspondance plus expressive, document.evaluate() prend en charge les expressions XPath, y compris les requêtes basées sur le texte. C’est l’option la plus puissante pour les motifs complexes.
function findByXPath(expression, context = document) {
const result = document.evaluate(
expression,
context,
null,
XPathResult.ORDERED_NODE_SNAPSHOT_TYPE,
null
)
return Array.from({ length: result.snapshotLength }, (_, i) =>
result.snapshotItem(i)
)
}
// Trouver n'importe quel élément contenant le texte "Submit"
const els = findByXPath('//*[contains(text(), "Submit")]')
La recherche de texte XPath dans le DOM gère proprement les correspondances partielles et les conditions complexes. Le compromis est la lisibilité — la syntaxe XPath est peu familière pour la plupart des développeurs frontend.
Un point à garder à l’esprit : contains(text(), "Submit") ne correspond qu’aux nœuds textuels directs de l’élément. Si “Submit” se trouve à l’intérieur d’un élément enfant, cette expression ne correspondra pas au parent. Pour rechercher dans tout le texte des descendants, utilisez plutôt contains(., "Submit"), où . fait référence à la valeur textuelle complète de l’élément, y compris ses descendants.
textContent vs. innerText : lequel utiliser pour la correspondance
Les deux propriétés retournent du texte, mais elles se comportent différemment :
| Propriété | Retourne | Déclenche la mise en page ? |
|---|---|---|
textContent | Texte brut du DOM, y compris les éléments masqués | Non |
innerText | Uniquement le texte rendu | Oui (reflow) |
Utilisez textContent pour la correspondance de texte. C’est plus rapide, cela ne déclenche pas de recalcul de mise en page et fonctionne de manière cohérente sur tous les éléments quelle que soit leur visibilité.
Pièges courants lors de la recherche d’éléments DOM par texte
Espaces blancs : textContent inclut les espaces blancs provenant du formatage HTML. Utilisez toujours .trim() avant de comparer.
Texte imbriqué : Le textContent d’un élément inclut tout le texte des descendants. <div><span>TV</span></div> — le textContent du div est également "TV". Soyez précis sur le niveau d’élément que vous ciblez.
Contenu dynamique : Le texte injecté après le chargement de la page ne sera pas présent lors de l’exécution de votre script. Utilisez un MutationObserver ou exécutez votre recherche après avoir confirmé l’existence du contenu.
Choisir la bonne approche
- Type d’élément connu, correspondance simple → filtrage avec
querySelectorAll - N’importe quel type d’élément, recherche DOM complète →
TreeWalker - Correspondance partielle ou motif complexe → XPath via
document.evaluate()
Si vous travaillez dans un contexte de test, des outils comme Testing Library fournissent getByText() nativement — bon à savoir, bien que les techniques natives ci-dessus restent essentielles pour les scripts hors contexte de test.
Conclusion
La recherche DOM basée sur le texte est une lacune de l’API standard, mais ces trois approches couvrent tous les cas pratiques. Utilisez querySelectorAll avec un filtre pour des recherches rapides et ciblées lorsque vous connaissez le type d’élément. Optez pour TreeWalker lorsque vous avez besoin d’un parcours complet du DOM sans vous engager sur une balise spécifique. Tournez-vous vers XPath lorsque la logique de correspondance exige du texte partiel ou des conditions complexes. Quelle que soit la méthode choisie, privilégiez textContent plutôt que innerText, supprimez les espaces blancs avant de comparer et tenez compte du texte des descendants imbriqués pour éviter les fausses correspondances.
FAQ
Non. querySelector et querySelectorAll n'acceptent que des sélecteurs CSS, et CSS n'a pas de sélecteur pour faire correspondre le contenu textuel. Vous devez utiliser des approches basées sur JavaScript telles que le filtrage d'un ensemble de résultats querySelectorAll, le parcours du DOM avec TreeWalker ou l'exécution d'une expression XPath avec document.evaluate pour localiser des éléments par leur contenu.
FILTER_SKIP indique au TreeWalker d'ignorer le nœud actuel mais de visiter quand même ses enfants. FILTER_REJECT ignore le nœud et toute sa sous-arborescence. Pour les recherches basées sur le texte, FILTER_SKIP est généralement le bon choix car un parent peut ne pas correspondre alors qu'un descendant plus profond correspond.
Non. L'expression contains(text(), value) ne vérifie que les nœuds textuels directs de l'élément. Si la chaîne cible se trouve à l'intérieur d'un élément enfant imbriqué, utilisez plutôt contains(., value). L'opérateur point fait référence à la valeur textuelle complète de l'élément, y compris tout le texte des descendants.
textContent est plus rapide car il ne déclenche pas de reflow de mise en page. Il retourne tout le texte dans la sous-arborescence DOM quelle que soit la visibilité CSS, ce qui le rend cohérent et prévisible. innerText ne retourne que le texte rendu et force le navigateur à recalculer la mise en page, ce qui ajoute une surcharge inutile pour les besoins de correspondance.
Complete picture for complete understanding
Capture every clue your frontend is leaving so you can instantly get to the root cause of any issue with OpenReplay — the open-source session replay tool for developers. Self-host it in minutes, and have complete control over your customer data.
Check our GitHub repo and join the thousands of developers in our community.