Template literals con tag personalizzati per creare HTML sicuro

by Anastasia P.
SHARE
Template literals con tag personalizzati per creare HTML sicuro
© Guida-HTML5.it

Introduzione

I template literals non servono soltanto a inserire variabili dentro una stringa o a scrivere testo su più righe. Una funzionalità meno conosciuta, ma molto utile, è rappresentata dalle tagged template: una funzione può “intercettare” un template literal, analizzarne le parti statiche e i valori dinamici, quindi restituire una nuova stringa elaborata.

Questo approccio è particolarmente pratico quando si deve generare HTML a partire da dati variabili. Invece di concatenare manualmente stringhe e valori, possiamo creare un tag personalizzato che esegue automaticamente l’escaping HTML. In questo modo, un testo proveniente da un utente non viene interpretato come codice HTML.

È importante precisare che un tag template non sostituisce una vera libreria di sanitizzazione in scenari complessi. Tuttavia, per testo semplice inserito in nodi HTML, rappresenta un’ottima dimostrazione di come separare la struttura della pagina dai dati dinamici.

Codice completo

const escapeHtml = (value) => {
  return String(value)
    .replaceAll("&", "&")
    .replaceAll("<", "&lt;")
    .replaceAll(">", "&gt;")
    .replaceAll(´"´, "&quot;")
    .replaceAll("´", "'");
};

function html(strings, ...values) {
  return strings.reduce((result, currentString, index) => {
    const value = values[index - 1];

    // La prima parte statica non ha un valore precedente.
    if (index === 0) {
      return currentString;
    }

    // Tutti i valori dinamici vengono convertiti in testo sicuro.
    return result + escapeHtml(value) + currentString;
  }, "");
}

const prodotto = {
  nome: ´Tastiera <gaming>´,
  descrizione: ´Layout "compatto" per sviluppatori´,
  prezzo: 49.9
};

const schedaProdotto = html`
  <article class="product-card">
    <h2>${prodotto.nome}</h2>
    <p>${prodotto.descrizione}</p>
    <strong>Prezzo: ${prodotto.prezzo.toFixed(2)} €</strong>
  </article>
`;

document.querySelector("#app").innerHTML = schedaProdotto;

Per provare l’esempio, è sufficiente avere nel documento HTML un elemento contenitore come <div id="app"></div>. Il risultato sarà una scheda prodotto costruita su più righe, con dati dinamici convertiti in testo sicuro.

Spiegazione

Come funziona una tagged template

Quando scriviamo html`...`, JavaScript non tratta il template literal come una semplice stringa. Invoca invece la funzione html, passando due categorie di argomenti:

  • un array con le parti statiche del testo;
  • tutti i valori inseriti nelle espressioni ${...}.

Consideriamo questo esempio:

const nome = "Ada";
const ruolo = "sviluppatrice";

function mostraParti(strings, ...values) {
  console.log(strings);
  console.log(values);
}

mostraParti`Nome: ${nome}, Ruolo: ${ruolo}`;

L’array strings contiene le parti fisse, mentre values contiene i valori di nome e ruolo. La sintassi con i tre puntini, chiamata rest parameter, raccoglie un numero variabile di espressioni.

Ricostruire la stringa

Nel codice completo, il metodo reduce() combina progressivamente testo statico e valori dinamici. Per ogni posizione, la funzione aggiunge:

  • la parte statica corrente;
  • il valore precedente, dopo l’escaping;
  • la parte statica successiva.

La funzione escapeHtml() sostituisce i caratteri che possono avere un significato speciale in HTML. Per esempio, il carattere < diventa &lt;. Di conseguenza, il valore <script> viene visualizzato come testo e non interpretato dal browser come un elemento HTML.

Valori dinamici e formattazione

È possibile eseguire operazioni dentro un’espressione del template literal. Nell’esempio, prodotto.prezzo.toFixed(2) formatta il prezzo con due cifre decimali prima che il valore venga inserito nella stringa.

Questa tecnica è utile per creare piccole viste, messaggi, email HTML o frammenti di interfaccia senza ricorrere a numerose concatenazioni con l’operatore +.

Best practice

  • Separa struttura e dati: usa il template per definire la struttura e le espressioni per inserire i valori.
  • Esegui l’escaping dei dati esterni: dati ricevuti da utenti, API o URL non devono essere inseriti direttamente in HTML.
  • Non confondere escaping e sanitizzazione: l’esempio protegge il testo inserito nei contenuti HTML, ma non gestisce ogni possibile contesto, come attributi complessi o codice JavaScript.
  • Evita HTML dinamico quando non serve: per aggiornare un singolo testo, preferisci textContent.
  • Mantieni i tag personalizzati semplici: una funzione tag dovrebbe avere una responsabilità chiara, come escaping, formattazione o localizzazione.
  • Controlla i dati prima della visualizzazione: formatta date, numeri e valori opzionali prima di passarli al template.

Per esempio, se il contenuto non deve essere interpretato come HTML, è spesso più sicuro usare direttamente il DOM:

const titolo = document.querySelector("#titolo");
titolo.textContent = prodotto.nome;

In questo caso il browser inserisce il valore come testo senza interpretarlo come markup.

Riepilogo

I template literals con tag personalizzati permettono di trasformare una semplice stringa multilinea in uno strumento di elaborazione riutilizzabile. Una funzione tag riceve le parti statiche e i valori dinamici, li combina e può applicare regole specifiche prima di restituire il risultato.

L’esempio dell’escaping HTML mostra un caso concreto: creare markup leggibile mantenendo sotto controllo i dati variabili. La soluzione è particolarmente adatta a componenti piccoli e frammenti HTML generati lato client. Per applicazioni più grandi, è comunque consigliabile valutare il DOM, librerie di templating o strumenti di sanitizzazione progettati per il contesto specifico.

Approfondisci con risorse ufficiali

SHARE