Skip to content

[web] Hidden autofill form inputs are exposed to assistive technology without a label #195174

Closed

Description

@flutter-zl

Steps to reproduce

  1. Run any Flutter Web app with semantics enabled, for example a page with
    TextField(decoration: InputDecoration(labelText: 'Password'), obscureText: true).
    The a11y_assessments test app in flutter/packages works: open #/text-field-password.
  2. Focus the text field, then move focus away or navigate to another route.
  3. Inspect <flt-text-editing-host>, or run an automated accessibility checker such as axe on the page.

Expected results

The hidden autofill form that the engine keeps in the DOM is not exposed to assistive technology, and automated checkers report no unlabeled form controls.

Actual results

The dormant autofill form stays in <flt-text-editing-host> for the rest of the session, and it contains a synthetic <input> with no accessible name:

<form id="flt-af-EditableText-753320914" class="transparentTextEditing" ...>
  <input tabindex="-1" class="submitBtn" type="submit" ...>
  <input autocomplete="on" class="transparentTextEditing" ...>
</form>

The synthetic input has no aria-label, no <label>, and no aria-hidden. It only gets a placeholder if the field has hintText. axe reports it under "Form elements must have labels" on whatever page is open afterwards, even though that page's own fields are labeled. Unlike the submit button next to it, it also has no tabindex="-1".

Reproduced on the a11y_assessments app: focus the password field on #/text-field-password, navigate to #/auto-complete, and the leftover unlabeled <input autocomplete="on"> is still in the page.

Cause

In engine/src/flutter/lib/web_ui/lib/src/engine/text_editing/text_editing.dart:

  • EngineAutofillForm.demoteFocusedToSynthetic creates a synthetic placeholder when a field blurs in semantics mode, so the field still takes part in credential save. Added in [web] Autofill all AutofillGroup fields in semantics mode #187108.
  • EngineAutofillForm._createFormElementAndFields creates synthetic elements for the non-focused fields of an autofill group.
  • goDormant() intentionally keeps the form in the DOM so the browser can autofill and submit it later.

Neither creation site hides the synthetic elements from assistive technology.

Proposed fix

Set aria-hidden="true" and tabIndex = -1 on synthetic autofill elements at both creation sites. They exist for the browser's autofill and form submission, not as controls a user should reach. Browser autofill does not read ARIA, so autofill and credential save should be unaffected. The focused element must stay untouched; in non-semantics mode it is the real input receiving keystrokes.

Related: #190126 also changes this form's lifecycle and adds aria-hidden to the submit button, so the fix should be coordinated with it.

Code sample

Code sample
import 'package:flutter/material.dart';

void main() => runApp(const MaterialApp(home: Demo()));

class Demo extends StatelessWidget {
  const Demo({super.key});

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: ListView(
        children: const <Widget>[
          TextField(decoration: InputDecoration(labelText: 'Password'), obscureText: true),
          TextField(decoration: InputDecoration(labelText: 'Other')),
        ],
      ),
    );
  }
}

Enable semantics, focus Password, then focus Other, then run
document.querySelector('flt-text-editing-host').innerHTML in the console.

Flutter Doctor output

Doctor output

Observed on flutter/packages main at 63bc5cd with the Flutter SDK at 6564794 (2026-10-01), Chrome on macOS.

Activity

  1. added
    a: text inputEntering text in a text field or keyboard related problems
    engineflutter/engine related. See also e: labels.
    a: accessibilityAccessibility, e.g. VoiceOver or TalkBack. (aka a11y)
    platform-webWeb applications specifically
    triaged-webTriaged by Web platform team
    on Oct 23, 2026
  2. self-assigned this
    on Oct 23, 2026
  3. flutter-triage-bot commented on Oct 23, 2026

    @flutter-triage-bot

    The triaged-web label is irrelevant if there is no team-web label or fyi-web label.

  4. flutter-triage-bot commented on Oct 23, 2026

    @flutter-triage-bot

    This issue is missing a priority label. Please set a priority label when adding the triaged-web label.

  5. added
    P2Important issues not at the top of the work list
    triaged-webTriaged by Web platform team
    on Oct 23, 2026
  6. added a commit that references this issue on Nov 2, 2026
    2fd8904
  7. added a commit that references this issue on Nov 3, 2026
    4a8e7d7
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

P2Important issues not at the top of the work lista: accessibilityAccessibility, e.g. VoiceOver or TalkBack. (aka a11y)a: text inputEntering text in a text field or keyboard related problemsassigned for triageissue is assigned to a domain expert for further triageengineflutter/engine related. See also e: labels.platform-webWeb applications specificallyteam-webOwned by Web platform teamtriaged-webTriaged by Web platform team

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions