Skip to content

Latest commit

 

History

History
105 lines (83 loc) · 4.68 KB

File metadata and controls

105 lines (83 loc) · 4.68 KB

Autofill Controls

Whenever possible, supply previously entered data values to text input fields to reduce redundant data entry. This is done in support of the WCAG Success Criterion 1.3.5 Identify Input Purpose and Success Criterion 3.3.7 Redundant Entry.

Two approaches to auto-filling input field values are to connect TextField data to an Autofill Service and to supply known application data.

Connect TextField data to an Autofill Service

Text input fields can have their content autofilled by providing a semantic contentType. By doing so, any installed Autofill Service can provide suggested data values to those fields.

For example:

@Composable
fun AutofilledEmailTextField(
    email: String,
    setEmail: (String) -> Unit
) = OutlinedTextField(
        value = email,
        onValueChange = setEmail,
        modifier = Modifier
            // ... handle keyboard trap, etc. ...
            // Key technique: Apply the appropriate autofill contentType to a TextField.
            .semantics {
                contentType = ContentType.EmailAddress
            },
        // Always label TextFields...
        label = { Text("Email")},
        // Use KeyboardType.Email to enter email addresses.
        keyboardOptions = KeyboardOptions.Default.copy(
            keyboardType = KeyboardType.Email,
            imeAction = ImeAction.Next
        ),
        // ... other TextField properties ...
    )

Multiple autofill content types can be set by adding ContentType values. For example, contentType = ContentType.EmailAddress + ContentType.UserName.

When a form is complete, commit autofill values using the current LocalAutofillManager instance's .commit() method. For example:

val autofillManager = LocalAutofillManager.current
Button(
  onClick = {
    autofillManager?.commit()
    // submit the form...
  },
) {
  Text("Submit")
}

Semantic autofill content type can be tested in Compose UI tests using SemanticsMatcher functions.

fun hasAnyContentType(): SemanticsMatcher =
    SemanticsMatcher.keyIsDefined(SemanticsProperties.ContentType)

fun hasNoContentType(): SemanticsMatcher =
    SemanticsMatcher.keyNotDefined(SemanticsProperties.ContentType)

fun hasContentType(value: ContentType): SemanticsMatcher {
    return SemanticsMatcher("SemanticsProperties.ContentType == {$value}") {
        value == it.config.getOrNull(SemanticsProperties.ContentType)
    }
}
// ...
@Test
fun verifyNameTextFieldAutofillContentType() {
    composeTestRule
        .onNode(
            hasTestTag(nameTextFieldTestTag) 
            and
            hasContentType(ContentType.PersonFullName)
        )
        .assertExists()
}

Supply known application data

Input fields can also be auto-populated by supplying default data values from known application data. For example, shipping address fields can be filled from previously-entered billing address data, which will simplify data entry when the billing and shipping addresses are the same.

(Note: The hard-coded text shown in these examples is only used for simplicity. Always use externalized string resource references in actual code.)


Copyright 2024-2025 CVS Health and/or one of its affiliates

Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

See the License for the specific language governing permissions and limitations under the License.