DOM Utils — Referencia rápida
Utilidades mínimas y declarativas para manipular el DOM. Tras configurar el alias @/* hacia src/*, importa desde @/lib/dom.
Solo existen aquí las funciones que el sitio realmente usa. Si necesitas algo que no está, primero considera si element.querySelector directo es más claro que agregar otro helper.
Tipos y concordancia
Sección titulada «Tipos y concordancia»$(), $opt() y $$() son genéricas: <T extends Element = HTMLElement>. Sin especificar el genérico, devuelven HTMLElement — no Element — porque es lo que casi siempre estás seleccionando (botones, inputs, divs) y porque on(), onAll(), show() y hide() piden HTMLElement. Con Element como default, el resultado de $() no encajaba directo en esas funciones y tocaba tipar todo a mano.
Con HTMLElement de default, esto ya funciona sin genéricos explícitos:
import { $, on } from "@/lib/dom"
const boton = $("[data-submit]")on(boton, "click", () => {})Solo especifica el genérico cuando necesites propiedades de un subtipo concreto (.value en HTMLInputElement, .checked en checkboxes) o cuando selecciones algo que no es HTMLElement (un SVGElement, por ejemplo).
Selectores
Sección titulada «Selectores»$() — Elemento requerido
Sección titulada «$() — Elemento requerido»Busca el primer elemento que coincida con el selector dentro del ámbito indicado. A diferencia de querySelector, garantiza que el resultado exista: lanza un error si no encuentra el elemento. Úsala cuando el elemento sea imprescindible para que el script funcione correctamente.
export function $<T extends Element = HTMLElement>( selector: string, root: ParentNode = document): T { const el = root.querySelector<T>(selector) if (!el) throw new Error(`DOM: elemento no encontrado: ${selector}`) return el}import { $ } from "@/lib/dom"
// Selector globalconst boton = $<HTMLButtonElement>("[data-submit]")
// Buscar dentro de un elementoconst input = $<HTMLInputElement>("[data-email]", formulario)$opt() — Elemento opcional
Sección titulada «$opt() — Elemento opcional»Busca el primer elemento que coincida con el selector, pero permite que no exista. Retorna el elemento encontrado o null cuando no hay coincidencias. Es útil para componentes, páginas o estados donde un elemento puede estar ausente de forma válida.
export function $opt<T extends Element = HTMLElement>( selector: string, root: ParentNode = document): T | null { return root.querySelector<T>(selector)}import { $opt } from "@/lib/dom"
const modal = $opt<HTMLDivElement>("[data-modal]")if (modal) show(modal)$$() — Todos los elementos
Sección titulada «$$() — Todos los elementos»Busca todos los elementos que coincidan con el selector dentro del ámbito indicado. Siempre retorna un array real, vacío si no hay coincidencias, en lugar de un NodeList. Esto permite recorrer los resultados directamente con forEach, transformarlos con map o filtrarlos con filter.
export function $$<T extends Element = HTMLElement>( selector: string, root: ParentNode = document): T[] { return Array.from(root.querySelectorAll<T>(selector))}import { $$ } from "@/lib/dom"
const items = $$<HTMLLIElement>("[data-item]")items.forEach((item) => console.log(item.textContent))
// Buscar dentro de un contenedorconst campos = $$<HTMLInputElement>("[data-field]", formulario)Mostrar / Ocultar
Sección titulada «Mostrar / Ocultar»show() — Mostrar elementos
Sección titulada «show() — Mostrar elementos»Desactiva el atributo booleano hidden de un elemento o de cada elemento de un array. El elemento vuelve a participar visualmente en el layout según sus estilos habituales.
export function show(el: HTMLElement | HTMLElement[]): void { const elementos = Array.isArray(el) ? el : [el] elementos.forEach((e) => { e.hidden = false })}import { show } from "@/lib/dom"
show(mensajeFinal)hide() — Ocultar elementos
Sección titulada «hide() — Ocultar elementos»Activa el atributo booleano hidden de un elemento o de cada elemento de un array. Esto oculta los elementos de forma semántica y hace que dejen de ocupar espacio en el layout.
export function hide(el: HTMLElement | HTMLElement[]): void { const elementos = Array.isArray(el) ? el : [el] elementos.forEach((e) => { e.hidden = true })}import { hide } from "@/lib/dom"
hide([cargador1, cargador2])CSS Variables
Sección titulada «CSS Variables»getCssVar() — Leer variable CSS
Sección titulada «getCssVar() — Leer variable CSS»Lee el valor calculado directamente custom property CSS desde el elemento indicado. El tercer argumento permite proporcionar un valor por defecto cuando la variable no está definida o no produce un valor útil, evitando repetir comprobaciones en cada llamada.
export function getCssVar( el: Element | null | undefined, varName: string, fallback = ""): string { if (!el) return fallback return getComputedStyle(el).getPropertyValue(varName).trim() || fallback}import { getCssVar } from "@/lib/dom"
const azul = getCssVar(elemento, "--color-verlun-blue", "#2547FF")Event Listeners
Sección titulada «Event Listeners»Ambas funciones retornan una función para desuscribirse.
on() — Agregar listener
Sección titulada «on() — Agregar listener»Registra un event listener sobre un elemento y retorna una función de limpieza. Guarda esa función cuando el listener deba eliminarse al desmontar un componente, cambiar de página o finalizar un ciclo de vida.
export function on<K extends keyof HTMLElementEventMap>( el: HTMLElement | Window | Document | null | undefined, type: K, listener: (ev: HTMLElementEventMap[K]) => void, options?: AddEventListenerOptions): () => void { if (!el) return () => {} el.addEventListener(type as string, listener as EventListener, options) return () => { el.removeEventListener(type as string, listener as EventListener, options) }}import { on } from "@/lib/dom"
const limpiar = on(boton, "click", () => console.log("Clickeado"))
// Remover despuéslimpiar()onAll() — Mismo listener en varios eventos
Sección titulada «onAll() — Mismo listener en varios eventos»Registra el mismo handler para varios tipos de evento y retorna una única función para desuscribirlos todos. Es útil cuando una actualización debe reaccionar, por ejemplo, tanto a cambios de texto como a cambios de selección en un formulario.
export function onAll<K extends keyof HTMLElementEventMap>( el: HTMLElement | Window | Document | null | undefined, types: K[], listener: (ev: HTMLElementEventMap[K]) => void, options?: AddEventListenerOptions): () => void { const remover = types.map((type) => on(el, type, listener, options)) return () => remover.forEach((remove) => remove())}import { onAll } from "@/lib/dom"
const limpiar = onAll(formulario, ["input", "change"], actualizarContador)Observers
Sección titulada «Observers»Todos retornan una función para dejar de observar.
onVisible() — Visibilidad en viewport
Sección titulada «onVisible() — Visibilidad en viewport»Observa si un elemento entra o sale del viewport usando IntersectionObserver. El handler recibe un booleano con el estado actual de visibilidad y la función retornada detiene la observación. Las opciones permiten controlar qué proporción del elemento debe ser visible antes de activar el callback.
export function onVisible( el: Element | null | undefined, callback: (visible: boolean) => void, options?: IntersectionObserverInit): () => void { if (!el) return () => {} const observer = new IntersectionObserver( ([entry]) => callback(entry.isIntersecting), options ) observer.observe(el) return () => observer.disconnect()}import { onVisible } from "@/lib/dom"
const limpiar = onVisible(seccion, (visible) => { if (visible) iniciarAnimacion()})
// Con opciones: threshold indica cuándo se activaonVisible(elemento, handler, { threshold: 0.5 })onResize() — Cambios de tamaño
Sección titulada «onResize() — Cambios de tamaño»Observa los cambios de tamaño de un elemento mediante ResizeObserver. Cada vez que cambia, el handler recibe su rectángulo calculado para poder sincronizar un canvas, recalcular un layout o actualizar medidas derivadas. La función retornada desconecta el observer.
export function onResize( el: Element | null | undefined, callback: (rect: DOMRect) => void): () => void { if (!el) return () => {} const observer = new ResizeObserver(() => callback(el.getBoundingClientRect()) ) observer.observe(el) return () => observer.disconnect()}import { $, onResize } from "@/lib/dom"
const canvas = $<HTMLCanvasElement>("[data-canvas]")
const limpiar = onResize(canvas, (rect) => { canvas.width = rect.width canvas.height = rect.height redibujar()})onMutation() — Cambios en el DOM
Sección titulada «onMutation() — Cambios en el DOM»Observa mutaciones en el elemento indicado, como cambios de atributos, texto o nodos hijos, según las opciones configuradas. El handler se ejecuta cuando ocurre una mutación y la función retornada deja de observar. Por ejemplo, sirve para reaccionar a cambios de data-theme en <html>.
export function onMutation( el: Element | null | undefined, callback: (cambios: MutationRecord[]) => void, options: MutationObserverInit = { attributes: true, childList: true, subtree: true }): () => void { if (!el) return () => {} const observer = new MutationObserver(callback) observer.observe(el, options) return () => observer.disconnect()}import { onMutation } from "@/lib/dom"
const limpiar = onMutation(document.documentElement, actualizarColores, { attributes: true, attributeFilter: ["data-theme"]})Resumen
Sección titulada «Resumen»| Función | Qué hace |
|---|---|
$() | Seleccionar un elemento requerido; lanza error si falta |
$opt() | Seleccionar un elemento opcional; retorna null si falta |
$$() | Seleccionar todos los elementos que coincidan |
show() | Mostrar elemento(s) |
hide() | Ocultar elemento(s) |
getCssVar() | Leer una variable CSS calculada |
on() | Agregar un event listener |
onAll() | Agregar el mismo listener a varios eventos |
onVisible() | Observar entrada y salida del viewport |
onResize() | Observar cambios de tamaño |
onMutation() | Observar cambios en el DOM |
Consideraciones
Sección titulada «Consideraciones»- Usa
$()cuando la ausencia del elemento indique un error de programación. - Usa
$opt()para elementos condicionales o páginas que no siempre incluyen el mismo markup. $$()devuelve un array real, por lo que puedes usarmap,filteryforEachsin conversiones.- Conserva la función de limpieza de listeners y observers cuando el ciclo de vida del script lo requiera.
- Si seleccionas algo que no es HTML (un
<svg>, por ejemplo) especifica el genérico:$<SVGElement>(...). Sin eso, TypeScript lo trata comoHTMLElementy las propiedades específicas de SVG no van a estar disponibles.