# Autofill that breaks the form

Autofill breaks the form when the browser writes into the field without a React event: state stays empty, the field looks full, and submit sends nothing.

> Page: https://ui.eneawork.it/blog/autofill-form-problemi
> Markdown: https://ui.eneawork.it/blog/autofill-form-problemi.md

*2026-11-01*

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.

Misurato il 1 novembre 2026: data/blocks.json elenca 1.556 blocchi, di cui 35 con login nell’id e 111 con form, login, sign-in o auth nel nome o nelle categorie; il catalogo conta 111.985 componenti da 1.472 librerie, letti da /api/stats lo stesso giorno. Metodo: JSON.parse del file e filtro con espressione regolare su id, nome, titolo e categorie.

## 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

## 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.

## Record vivi nel catalogo

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.

## FAQ

### 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.
