1. Introduction
This section is non-normative.
Autofill is a key feature of the web that reduces friction for millions of users everyday. It is widely used on login screens, e-commerce, and contact forms, to name a few examples. For commerce and checkout flows in particular, autofill provides significant benefit to both the buyer experience and merchant outcomes.
At the same time, autofill on the web has several deficiencies: partial or incomplete fill, cross-browser interoperability issues, and high cost to implement and maintain for developers.
One key example is address autofill which, when implemented correctly, is a dynamic form: different geographies have different shapes and requirements for address input. Selecting a country requires changing the form (re-ordering fields, adding and removing fields) and depends on input from the user, but autofill mediates this interaction and may not respond correctly to the rendered form.
The current 'industry standard' solution requires use of hidden form fields that try to anticipate and capture the right information and then surface it to the user. This solution is brittle and complex. Worse, it entrenches use of hidden fields to power legitimate use cases, but the same technique can be and is also abused by bad actors.
This specification introduces an AutofillEvent that fires before autofill values are
committed to form fields, allowing developers to:
-
Inspect the values that are about to be autofilled
-
Adapt the form dynamically based on those values (e.g., showing country-specific address fields)
-
Signal to the user agent when the form is ready to accept the autofill values
1.1. Goals
-
Users: Make autofill more reliable and pave the path for potential future deprecation of filling hidden fields
-
Site developers: Reduce complexity required to tackle address autofill using hidden fields, and reduce the need for implementation-specific hacks.
-
Autofill providers: Give third-party autofill providers hooks that work seamlessly with the new API
1.2. Example
< form id = "checkout" > < input autocomplete = "name" placeholder = "Full name" > < input autocomplete = "street-address" placeholder = "Street address" > < input autocomplete = "address-level2" placeholder = "City" > < input autocomplete = "postal-code" placeholder = "Postal code" > < input autocomplete = "country" placeholder = "Country" > <!-- State/province field will be added dynamically for countries that need it --> </ form > < script > document. addEventListener( 'autofill' , async function ( event) { // Find the country value in the autofill values let countryValue= null ; let formElement= null ; // Find the country element and value for ( const [ element, value] of event. values) { if ( element. autocomplete=== 'country' ) { countryValue= value; formElement= element. form; break ; } } // If filling a US address, we need to add a state selector if ( event. refill!== null ) { if ( countryValue=== 'US' ) { // Check if we already have a state field const existingState= formElement. querySelector( '[autocomplete="address-level1"]' ); if ( ! existingState) { // Create and insert a state selector for US addresses const stateSelect= document. createElement( 'select' ); stateSelect. autocomplete= 'address-level1' ; stateSelect. name= 'state' ; stateSelect. innerHTML= ` <option value="">Select state...</option> <option value="AL">Alabama</option> <option value="AK">Alaska</option> <option value="AZ">Arizona</option> <option value="CA">California</option> <option value="CO">Colorado</option> <!-- ... other states ... --> <option value="WY">Wyoming</option> ` ; // Insert before the postal code field const postalCode= formElement. querySelector( '[autocomplete="postal-code"]' ); postalCode. parentNode. insertBefore( stateSelect, postalCode); // Signal that the form has been modified and autofill should be refilled await event. refill(); } } else if ( countryValue=== 'UK' ) { ... Add UK- specific logic} } else { // The UA doesn't support refilling. Extract values from hidden fields, // or notify the user they need to complete values manually. } }); </ script >
The values attribute returns a list of autofill value entries, where each
entry is a tuple of the target HTMLElement and the value to be filled. The developer can
iterate over these entries to inspect the pending autofill data and determine if the form needs
to be adapted.
Once the form structure was changed (e.g., to add country-specific fields, potentially asynchronously),
the developer calls refill. This signals to the user agent that the form has been
modified and that it should retry the autofill operation with the updated form structure.
Note: The refill attribute is null on the second dispatch of the event
(after form modifications), preventing infinite loops.
2. Concepts
2.1. Autofill Value Entries
An autofill value entry is a tuple consisting of:
-
An
HTMLElement— the form control that will receive the autofilled value -
A
DOMString— the value from the user’s autofill profile to be filled
The user agent matches form controls to autofill data based on the control’s
autocomplete attribute (see autofill field name in [HTML]).
It may also use implementation-defined heuristics.
2.2. Refill Operation
A refill operation allows the developer to signal that the form structure was modified in response to the autofill values, and that the user agent should attempt to fill the form again.
3. The AutofillEvent Interface
[Exposed =Window ]interface :AutofillEvent Event {(constructor DOMString ,type optional AutofillEventInit = {});eventInitDict readonly attribute FrozenArray <AutofillValueEntry >values ;readonly attribute RefillCallback ?refill ; };callback =RefillCallback Promise <undefined > ();dictionary :AutofillEventInit EventInit {sequence <AutofillValueEntry >= [];values boolean =allowRefill true ; };typedef sequence <any >; // AutofillValueEntry is a tuple of [HTMLElement, DOMString] // where the first element is the form control and the second is the value to fillAutofillValueEntry
The AutofillEvent interface represents an event that is dispatched when the
user agent is about to autofill form fields.
3.1. Attributes
The values attribute returns a list of
autofill value entries. Each entry is a tuple where the first element is an HTMLElement
(the form control to be filled) and the second element is a DOMString (the value to fill).
The refill attribute returns a RefillCallback or
null. When not null, calling this callback returns a Promise that, when awaited, signals
to the user agent that the form structure has been modified and autofill should be retried.
The refill attribute is null when:
-
The event is dispatched as a retry after a previous call to
refill, or -
The user agent determines that refilling is not appropriate for this autofill operation.
This prevents infinite loops where a page continuously modifies the form and requests refills.
Each AutofillEvent has an associated values list
(a list of autofill value entries), initially an empty list.
Each AutofillEvent has an associated allow refill flag
(a boolean), initially true.
Each AutofillEvent has an associated dispatch timestamp
(a DOMHighResTimeStamp), initially 0.
Each AutofillEvent has an associated refill pending flag
(a boolean), initially false.
4. Processing Model
4.1. Firing the Autofill Event
-
Let event be the result of creating an event using
AutofillEvent. -
Initialize event’s
typeattribute to "autofill". -
Initialize event’s
bubblesattribute to true. -
Initialize event’s
cancelableattribute to false. -
Set event’s values list to entries.
-
Set event’s allow refill flag to allowRefill.
-
Set event’s dispatch timestamp to the current high resolution time.
-
Dispatch event at document.
-
Perform the autofill operation on document with entries.
Note: The autofill operation is performed immediately after the event is dispatched. The
refill callback allows the page to request an additional autofill pass
after modifying the form structure, within an implementation-defined timeout window.
4.2. Processing a Refill Request
AutofillEvent event:
-
Let now be the current high resolution time.
-
Let elapsed be now minus event’s dispatch timestamp.
-
Let refillTimeout be an implementation-defined duration.
-
If elapsed is greater than refillTimeout, return a promise rejected with an "
InvalidStateError"DOMException. -
If event’s allow refill flag is false, return a promise rejected with an "
InvalidStateError"DOMException. -
If event’s refill pending flag is true, return a promise rejected with an "
InvalidStateError"DOMException. -
Set event’s refill pending flag to true.
-
Let promise be a new promise.
-
Let document be event’s relevant document.
-
Return promise and in parallel:
-
Let entries be the updated autofill value entries (re-matching the user’s autofill data against the modified form).
-
Queue a task to:
-
Fire an autofill event with document, entries, and false.
-
Perform the autofill operation on document with entries.
-
Resolve promise with undefined.
-
-
Note: The timeout is implementation-defined to allow user agents flexibility in balancing
responsiveness with giving pages adequate time to call refill. User agents
SHOULD choose a timeout that provides a good user experience.
Note: On the retry dispatch (after refill was called), the
refill attribute is null, preventing infinite loops.
4.3. Integration with HTML Autofill
When a user agent’s autofill mechanism is triggered (e.g., by user interaction with an autofill UI), and the user selects values to fill, the user agent MUST fire an autofill event before committing those values to form fields.
5. The "full-address" Autocomplete Token
This specification introduces a new autofill field name: "full-address".
When a form control has the autocomplete attribute set to "full-address",
the user agent SHOULD request permission to access the user’s complete address data, including
fields that may not be present in the current form.
This enables forms to receive comprehensive address information via the AutofillEvent,
allowing them to dynamically adapt their structure to accommodate all relevant fields for the
user’s address.
full-address to enable comprehensive address autofill:
< form autocomplete = "full-address" > < input name = "country" autocomplete = "country" > < div id = "dynamic-address-fields" ></ div > </ form >
6. Security and Privacy Considerations
6.1. Timing Attacks
The AutofillEvent exposes autofill values to JavaScript before they are committed to form
fields. User agents SHOULD ensure that the event is only fired after explicit user consent to
autofill has been given (e.g., by selecting an autofill suggestion from a dropdown).
6.2. Third-Party Autofill Providers
Browser extensions and third-party autofill providers (such as password managers) can
utilize this API by constructing and dispatching AutofillEvents with the same structure,
ensuring consistent behavior regardless of the autofill source.