Introduzione
Quando si lavora con il DOM in JavaScript, il problema non è solo trovare un elemento, ma farlo in modo stabile, leggibile e manutenibile. In molti progetti, soprattutto quando l’interfaccia cresce, affidarsi a classi CSS o a strutture HTML troppo specifiche rende il codice fragile: basta cambiare un nome di classe o spostare un nodo per rompere la logica JavaScript.
Un approccio molto utile, pratico e spesso sottovalutato è l’uso degli attributi personalizzati, in particolare i data-attributes come data-action, data-id o data-role. Questi attributi permettono di selezionare gli elementi in base al loro significato funzionale, separando in modo chiaro la logica JavaScript dalla presentazione CSS.
In questo tutorial vedremo come usare i data-attributes per selezionare e manipolare elementi del DOM in modo più robusto, con un esempio reale: una piccola dashboard con schede prodotto, pulsanti di azione e un pannello informativo aggiornato dinamicamente.
Codice completo
<div class="catalogo">
<article class="card" data-product-id="101">
<h3>Taccuino tecnico</h3>
<p>Formato A5, copertina rigida.</p>
<button data-action="show-details">Dettagli</button>
<button data-action="add-to-cart">Aggiungi al carrello</button>
</article>
<article class="card" data-product-id="102">
<h3>Mouse wireless</h3>
<p>Silenzioso e ricaricabile via USB-C.</p>
<button data-action="show-details">Dettagli</button>
<button data-action="add-to-cart">Aggiungi al carrello</button>
</article>
</div>
<aside class="pannello" data-panel="info">
<h2>Informazioni prodotto</h2>
<p data-field="message">Seleziona un prodotto per vedere i dettagli.</p>
</aside>
<script>
// Dati di esempio: in un´app reale potrebbero arrivare da API
const products = {
101: {
name: "Taccuino tecnico",
description: "Formato A5, copertina rigida, 192 pagine.",
price: 9.99
},
102: {
name: "Mouse wireless",
description: "Mouse ergonomico, silenzioso e ricaricabile via USB-C.",
price: 24.5
}
};
// Selezioniamo il contenitore principale
const catalogo = document.querySelector(".catalogo");
// Selezioniamo il pannello informativo e il campo messaggio
const pannelloInfo = document.querySelector(´[data-panel="info"]´);
const messageField = document.querySelector(´[data-field="message"]´);
// Event delegation: ascoltiamo i click sul contenitore,
// così gestiamo anche eventuali elementi aggiunti in futuro
catalogo.addEventListener("click", (event) => {
const button = event.target.closest("button[data-action]");
// Se il click non arriva da un pulsante valido, interrompiamo
if (!button) return;
// Troviamo la scheda prodotto più vicina
const card = button.closest("[data-product-id]");
if (!card) return;
const productId = card.dataset.productId;
const action = button.dataset.action;
const product = products[productId];
if (!product) {
messageField.textContent = "Prodotto non trovato.";
return;
}
if (action === "show-details") {
messageField.innerHTML = `
<strong>${product.name}</strong><br>
${product.description}<br>
Prezzo: €${product.price.toFixed(2)}
`;
pannelloInfo.setAttribute("data-state", "visible");
}
if (action === "add-to-cart") {
messageField.textContent = `${product.name} aggiunto al carrello.`;
pannelloInfo.setAttribute("data-state", "success");
}
});
// Funzione utile: selezione sicura di un elemento per data-attribute
function getByData(selector, value) {
return document.querySelector(`[data-${selector}="${value}"]`);
}
// Esempio di utilizzo della funzione
const infoPanel = getByData("panel", "info");
console.log("Pannello trovato:", infoPanel);
</script> Spiegazione
Il punto forte di questo approccio è semplice: il JavaScript non dipende dall’aspetto grafico. Le classi CSS possono cambiare per esigenze di design, ma i data-attributes possono restare stabili perché rappresentano il ruolo funzionale di un elemento.
1. Cosa sono i data-attributes
I data-attributes sono attributi HTML personalizzati che iniziano con data-. Esempi:
- data-product-id="101": identifica un prodotto.
- data-action="add-to-cart": indica l’azione associata a un pulsante.
- data-panel="info": identifica una sezione della pagina.
In JavaScript puoi leggerli comodamente con element.dataset. Ad esempio, data-product-id diventa element.dataset.productId.
2. Selezione mirata con querySelector
Nel codice usiamo selettori come [data-panel="info"] o button[data-action]. Questo ci permette di prendere esattamente gli elementi che ci servono, senza dipendere da strutture troppo rigide.
È una soluzione molto utile quando:
- hai molti componenti simili nella stessa pagina;
- vuoi distinguere tra logica e stile;
- stai costruendo interfacce dinamiche o componenti riutilizzabili.
3. Event delegation per elementi dinamici
Invece di assegnare un listener a ogni pulsante, ascoltiamo il click sul contenitore .catalogo. Poi, con event.target.closest("button[data-action]"), risaliamo al pulsante effettivamente cliccato.
Questo è fondamentale per la manutenzione: se in futuro aggiungi nuove card al DOM, non devi registrare nuovi event listener. Il comportamento continua a funzionare automaticamente.
4. Uso di closest per trovare il contesto
Quando premi un pulsante, ci interessa sapere a quale prodotto appartiene. Per farlo usiamo closest("[data-product-id]"), che risale il DOM fino a trovare l’elemento più vicino con quell’attributo.
Questo evita di dipendere da livelli annidati specifici. Se domani aggiungi un wrapper interno al bottone, il codice continuerà a funzionare.
5. Manipolazione del contenuto
Nel pannello informativo aggiorniamo il testo con textContent oppure, quando serve formattazione, con innerHTML. In questo esempio, per mostrare il dettaglio prodotto, usiamo innerHTML perché vogliamo andare a capo e mettere in evidenza il nome.
Attenzione però: innerHTML va usato con cautela. Se i contenuti provengono dall’utente o da fonti non fidate, bisogna sanificarli per evitare problemi di sicurezza.
6. Una funzione riutilizzabile per selezionare elementi
La funzione getByData() è un piccolo helper che rende più leggibile la selezione di elementi tramite data-attributes. È utile in progetti medi o grandi, dove ripetere selettori complessi può diventare rumoroso.
Non è obbligatoria, ma aiuta a centralizzare lo stile di selezione e a mantenere il codice più coerente.
Best practice
- Usa i data-attributes per la logica, non per lo stile: le classi CSS servono al design, i data-attributes al comportamento.
- Preferisci nomi chiari e semantici: meglio data-action="add-to-cart" di un generico data-x="1".
- Usa event delegation quando gli elementi possono essere creati, rimossi o aggiornati dinamicamente.
- Controlla sempre i casi null: un selettore può non trovare nulla, quindi verifica prima di manipolare l’elemento.
- Evita innerHTML con input non fidato: per testo semplice usa textContent.
- Mantieni separati dati, struttura e comportamento: il DOM sarà più facile da mantenere nel tempo.
Riepilogo
La selezione e manipolazione del DOM diventa molto più solida quando usi i data-attributes come punto di riferimento. Questo approccio ti aiuta a scrivere codice meno fragile, più leggibile e più adatto a interfacce dinamiche.
Nel tutorial abbiamo visto come:
- selezionare elementi con attributi personalizzati;
- leggere i valori con dataset;
- usare closest() per risalire al contesto corretto;
- gestire eventi in modo efficiente con event delegation;
- aggiornare il contenuto del DOM in modo controllato.
Se vuoi costruire interfacce moderne e manutenibili, questo è uno degli strumenti più utili da aggiungere al tuo kit JavaScript.
Approfondisci con risorse ufficiali
- MDN - Using data attributes: documentazione completa sui data-attributes.
- MDN - HTMLElement.dataset: per leggere e scrivere attributi data in JavaScript.
- MDN - Document.querySelector(): per selezionare elementi con i selettori CSS.
- MDN - Element.closest(): utile per risalire nella gerarchia del DOM.
- MDN - Event delegation: concetto fondamentale per gestire eventi su elementi dinamici.
