Cómo encontrar elementos del DOM por texto
No existe un método getElementByText() en la API del DOM. Si necesitas localizar un elemento basándote en lo que dice en lugar de lo que es, tienes que construir esa capacidad tú mismo. Esto surge con más frecuencia de lo que pensarías: scripts de automatización, pruebas de interfaz de usuario, análisis de contenido dinámico, y el enfoque correcto depende de cuánta flexibilidad necesites.
Puntos clave
- La API del DOM no tiene un método integrado para seleccionar elementos por contenido de texto, pero tres enfoques nativos llenan este vacío: filtrar con
querySelectorAll, recorrer conTreeWalkery consultar con XPath. TreeWalkeres la opción nativa más versátil para búsquedas completas de texto en el DOM a través de cualquier tipo de elemento sin recopilar una NodeList grande por adelantado.- Prefiere
textContentsobreinnerTextpara la coincidencia de texto: es más rápido, evita activar el recálculo de diseño y se comporta de manera consistente independientemente de la visibilidad del elemento. - Ten cuidado con problemas comunes como espacios en blanco adicionales, texto anidado de descendientes y contenido inyectado dinámicamente que puede no estar presente cuando se ejecuta tu script.
Por qué querySelector no puede consultar el DOM por contenido de texto
querySelector() y querySelectorAll() solo aceptan selectores CSS. Aunque CSS tiene una pseudo-clase :has() y selectores de atributos, no existe un selector CSS estándar para hacer coincidir el contenido de texto de un elemento. Selectores como div:text("Submit") simplemente no existen en la especificación.
Esto te deja con tres enfoques prácticos: filtrar un conjunto de candidatos, recorrer el DOM con una API nativa o usar XPath.
Método 1: Filtrar un conjunto de candidatos por texto
El enfoque más simple es consultar elementos por etiqueta o clase, y luego filtrar por texto. Esto funciona bien cuando conoces el tipo de elemento de antemano.
function findByText(tag, text) {
return [...document.querySelectorAll(tag)].filter(el =>
el.textContent.trim() === text
)
}
// Uso
const buttons = findByText('button', 'Submit')
Esto es legible y rápido cuando el conjunto de candidatos es pequeño. La debilidad: solo busca un tipo de elemento a la vez. Buscar todos los elementos con '*' funciona pero es más lento en DOMs grandes.
Método 2: Recorrer el DOM con TreeWalker
TreeWalker es una API del DOM integrada que te permite recorrer nodos de manera eficiente. Tiene buen soporte en todos los navegadores modernos y evita la sobrecarga de recopilar una NodeList completa por adelantado.
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
}
// Uso
const matches = findElementsByText(document.body, 'TV')
Esto busca cualquier tipo de elemento a través de todo el árbol: una solución genérica que el enfoque específico por etiqueta no puede proporcionar. También admite terminación anticipada si solo necesitas la primera coincidencia.
Nota sobre
FILTER_SKIPvs.FILTER_REJECT: UsarFILTER_SKIPaquí significa que el walker todavía desciende a los hijos de un nodo que no coincide. Si usarasFILTER_REJECTen su lugar, el walker omitiría el nodo y todo su subárbol. Para búsquedas de texto,FILTER_SKIPes casi siempre lo que quieres, ya que eltextContentde un padre podría no coincidir aunque el de un descendiente más profundo sí lo haga.
Discover how at OpenReplay.com.
Método 3: Búsqueda de texto XPath en el DOM
Para coincidencias más expresivas, document.evaluate() admite expresiones XPath, incluidas consultas basadas en texto. Esta es la opción más poderosa para patrones complejos.
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)
)
}
// Encontrar cualquier elemento que contenga el texto "Submit"
const els = findByXPath('//*[contains(text(), "Submit")]')
La búsqueda de texto XPath en el DOM maneja coincidencias parciales y condiciones complejas de manera limpia. El compromiso es la legibilidad: la sintaxis XPath es desconocida para la mayoría de los desarrolladores frontend.
Una cosa a tener en cuenta: contains(text(), "Submit") solo coincide con los nodos de texto directos del elemento. Si “Submit” está dentro de un elemento hijo, esta expresión no coincidirá con el padre. Para buscar en todo el texto descendiente, usa contains(., "Submit") en su lugar, donde . se refiere al valor de cadena del elemento completo, incluidos sus descendientes.
textContent vs. innerText: Cuál usar para coincidencias
Ambas propiedades devuelven texto, pero se comportan de manera diferente:
| Propiedad | Devuelve | ¿Activa el diseño? |
|---|---|---|
textContent | Texto DOM sin procesar, incluidos elementos ocultos | No |
innerText | Solo texto renderizado | Sí (reflow) |
Usa textContent para la coincidencia de texto. Es más rápido, no activa el recálculo de diseño y funciona de manera consistente en todos los elementos independientemente de la visibilidad.
Problemas comunes al encontrar elementos del DOM por texto
Espacios en blanco: textContent incluye espacios en blanco del formato HTML. Siempre usa .trim() antes de comparar.
Texto anidado: El textContent de un elemento incluye todo el texto descendiente. <div><span>TV</span></div> — el textContent del div también es "TV". Sé específico sobre qué nivel de elemento estás apuntando.
Contenido dinámico: El texto inyectado después de la carga de la página no estará presente cuando se ejecute tu script. Usa un MutationObserver o ejecuta tu búsqueda después de confirmar que el contenido existe.
Elegir el enfoque correcto
- Tipo de elemento conocido, coincidencia simple → filtrar con
querySelectorAll - Cualquier tipo de elemento, búsqueda completa del DOM →
TreeWalker - Coincidencia parcial o patrón complejo → XPath a través de
document.evaluate()
Si estás trabajando en un contexto de pruebas, herramientas como Testing Library proporcionan getByText() integrado, aunque vale la pena conocer que las técnicas nativas anteriores siguen siendo esenciales para scripts que no son de prueba.
Conclusión
La búsqueda de DOM basada en texto es una brecha en la API estándar, pero estos tres enfoques cubren todos los casos prácticos. Usa querySelectorAll con un filtro para búsquedas rápidas y dirigidas cuando conoces el tipo de elemento. Recurre a TreeWalker cuando necesites un recorrido completo del DOM sin comprometerte con una etiqueta específica. Recurre a XPath cuando la lógica de coincidencia exija texto parcial o condiciones complejas. Cualquiera que sea el método que elijas, prefiere textContent sobre innerText, elimina los espacios en blanco antes de comparar y ten en cuenta el texto descendiente anidado para evitar coincidencias falsas.
Preguntas frecuentes
No. querySelector y querySelectorAll solo aceptan selectores CSS, y CSS no tiene un selector para hacer coincidir el contenido de texto. Necesitas usar enfoques basados en JavaScript como filtrar un conjunto de resultados de querySelectorAll, recorrer el DOM con TreeWalker o ejecutar una expresión XPath con document.evaluate para localizar elementos por lo que contienen.
FILTER_SKIP le dice al TreeWalker que omita el nodo actual pero aún visite a sus hijos. FILTER_REJECT omite el nodo y todo su subárbol. Para búsquedas basadas en texto, FILTER_SKIP suele ser la opción correcta porque un padre podría no coincidir mientras que un descendiente más profundo sí lo hace.
No. La expresión contains(text(), value) solo verifica los nodos de texto directos del elemento. Si la cadena objetivo está dentro de un elemento hijo anidado, usa contains(., value) en su lugar. El operador de punto se refiere al valor de cadena completo del elemento, incluido todo el texto descendiente.
textContent es más rápido porque no activa un reflow del diseño. Devuelve todo el texto en el subárbol del DOM independientemente de la visibilidad CSS, haciéndolo consistente y predecible. innerText devuelve solo texto renderizado y obliga al navegador a recalcular el diseño, lo que agrega una sobrecarga innecesaria para propósitos de coincidencia.
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.