React

Autofill che rompe il form

L'autofill rompe il form quando il browser scrive nel campo senza evento React: lo stato resta vuoto, il campo sembra pieno e il submit invia niente.

In sintesi

  • Il browser compila i campi prima che React ascolti gli eventi.
  • I token di autoComplete vengono dalla specifica HTML del WHATWG.
  • La correzione robusta è non controllare i campi che il browser compila.

L'autofill rompe il form quando il browser scrive nel campo senza emettere un evento React: lo stato resta vuoto, il campo sembra pieno e il submit invia niente.

Perché lo stato resta indietro

Il browser compila i campi prima che React sia pronto ad ascoltare gli eventi. Con un campo controllato il testo visibile arriva dal browser, mentre la variabile dello stato è ancora una stringa vuota: le due copie non si parlano.


  Email
  
  Continue

I token di autoComplete vengono dalla specifica HTML del WHATWG: email, given-name e one-time-code sono valori riconosciuti, mentre un token inventato viene ignorato dal browser.

La correzione: lasciare il valore nel DOM

function LoginForm() {
  async function onSubmit(event: React.FormEvent) {
    event.preventDefault();
    const data = new FormData(event.currentTarget);
    await fetch("/api/login", {
      method: "POST",
      headers: { "content-type": "application/json" },
      body: JSON.stringify(Object.fromEntries(data.entries())),
    });
  }

  return (
    
      Email
      
      Password
      
      Continue
    
  );
}

Nessun useState: il campo non ha una seconda copia da tenere allineata, quindi quello che l’autofill ha scritto è l’unica copia esistente. FormData legge il DOM al submit e non dipende da un evento che potrebbe non arrivare.

I tre sintomi

  • Campo visivamente pieno, stato vuoto: la validazione dice che il campo è obbligatorio anche se il testo si vede.
  • Password non aggiornata: il gestore compila due campi e solo uno arriva al submit.
  • Doppio valore: dopo il primo tasto il valore del browser e quello dello stato si sovrascrivono a vicenda.
  • Leggere il campo con useEffect al mount: il gestore di password scrive dopo, la lettura restituisce stringa vuota e il bug sembra un problema di React.

Riprodurre il caso

npx playwright codegen http://localhost:5173

Con il registratore si compila il form a mano e si riproduce l'invio; Playwright, licenza Apache-2.0, conserva i passaggi e li riesegue, così la correzione va verificata su ogni browser e non solo su quello di sviluppo.

La regola di decisione

Regola: lascia al DOM i campi che il browser conosce, email, current-password, street-address, one-time-code, e controlla solo quelli che costruisci tu, come uno slider o un selettore di date. Il segnale è la provenienza del valore: se può arrivare da fuori, il DOM è la fonte; se nasce da un gesto dentro l’app, lo stato va bene.

La verifica non finisce con un test verde: Chrome, Safari e Firefox scrivono nel campo in momenti diversi e con eventi diversi. Un test Playwright che usa fill() non riproduce l’autofill, perché emette gli stessi eventi di un utente; serve un profilo con credenziali salvate oppure una registrazione manuale dello schermo.

React ricrea i nodi quando cambia la key di un form: un contatore come key azzera il DOM e con esso quello che il gestore aveva scritto. Tieni la key stabile, oppure passa a defaultValue il valore che deve sopravvivere a un remount. In sviluppo StrictMode monta il componente due volte e rende il sintomo più frequente: non lo crea, ma lo mostra. Se il form vive dentro una scheda che si smonta, lo stesso effetto torna anche in produzione.

Tre form di accesso da confrontare: login-form, sign-in-form e login-01. Per sfogliare per categoria parti da blocchi login.

La limitazione

Non esiste un evento standard per l'autofill: input arriva nella maggior parte dei browser, ma non in tutti e non sempre. La correzione robusta è lasciare non controllati i campi che il browser compila, oppure leggere il valore dal DOM al submit.

Dove continuare

Il confronto fra i due schemi è in form controllati e non; il valore del campo è in ref, DOM e stato; le librerie misurate sono in librerie form React.

Domande frequenti

Posso disattivare l'autofill?

In parte. autoComplete uguale off è ignorato da quasi tutti i browser, quindi la strada giusta è convivere con l'autofill, non spegnerlo.

Perché solo la password resta vuota?

Il gestore compila i campi in ordine e alcuni browser emettono l'evento per il primo e non per il secondo. Va letto il valore dal DOM al submit.

Un campo non controllato risolve il problema?

Sì, perché il valore vive nel DOM e il submit lo legge con FormData. Perdi la validazione immediata, che torna al momento dell'invio.

Il problema esiste anche con react-hook-form?

Meno, perché i campi sono non controllati e il valore si legge al submit. Resta da gestire il primo render e i campi dipendenti.

Come lo testo senza compilare a mano?

Con Playwright si riproduce l'invio e si riesegue il test dopo la correzione, così la verifica resta ripetibile.