Amplify UI

Customization

Override and customize your Authenticator.

Headers & Footers

There are two ways you can add custom headers and footers to your Android Authenticator.

First, you can add a single header/footer to every screen in the Authenticator. The following example adds an image to the header and a copyright to the footer:

Authenticator(
    headerContent = {
        Box(
            modifier = Modifier.size(80.dp).align(Alignment.CenterHorizontally)
        ) {
            Image(
                painter = painterResource(R.drawable.amplify),
                contentDescription = null,
            )
        }
    },
    footerContent = {
        Text(
            "© All Rights Reserved",
            modifier = Modifier.align(Alignment.CenterHorizontally)
        )
    }
) {
  // ...
} 

Alternatively, you can add a header or a footer to an individual screen. More detail on fully customizing the UI of individual screens is in Full UI Customization. This example uses an inline lambda to add a Divider component to the header on the sign up screen.

Authenticator(
    signUpContent = { signUpState ->
        SignUp(
            state = signUpState,
            headerContent = {
                Column {
                    Text(
                        style = MaterialTheme.typography.titleLarge,
                        text = stringResource(R.string.amplify_ui_authenticator_title_signup)
                    )
                    Divider()
                }
            }
        )
    }
) {
 // ...
}

or by using a @Composable function:

Authenticator(
    signUpContent = { SignUpWithCustomHeader() },
    signInContent = { CustomSignIn() }
    // ...etc
) {
    // ...
}

Internationalization (I18n)

The Android Authenticator component uses string resources for all of its labels, so internationalization can be accomplished by providing a custom strings.xml file. For example, in a values-fr/strings.xml file you can have lines like the following to provide custom translations for all Authenticator strings:

<string name="amplify_ui_authenticator_field_warn_existing">Désolé, c\'est déjà pris</string>

Labels & Text

Using the same techniques as Internationalization (I18n), you can customize the labels (hints) and text of the components. Every string defined by the library is prefixed with amplify_ui_authenticator_ and strings adhere to a hierarchical naming convention to help identify its usage. All such strings can be found in the authenticator/src/main/res/values folder.

For example, here's a string from the library:

<string name="amplify_ui_authenticator_field_warn_existing">%s already exists</string>

You can change this string by overriding the string in your application's default resources:

<string name="amplify_ui_authenticator_field_warn_existing">Sorry, this is already taken</string>

Sign Up Field Order

The Authenticator allows a custom order of sign up fields on the Sign Up page.

Order is determined by a signUpForm @Compose block that is passed into the Authenticator state.

In the example below the order will be set as email, username, password and finally confirm_password.

val state = rememberAuthenticatorState(
    signUpForm = {
        email()
        username()
        password()
        confirmPassword()
    }
)

Form Field Customization

The Authenticator allows for customization of multiple aspects of the form fields. The sections below will describe several use cases and how to modify the appropriate fields.

Overall, you can customize the hint or label of any input as described in the labels and placeholder section.

Additionally, when using a custom Sign Up form as described in Sign Up Field Order, you can create fields with custom labels and hints, as well as specify whether the field is required, or pass your own custom validator.

Updating labels, hints, setting required and adding validators

The following example customizes the Sign Up page by:

  • Making the profile field optional.
  • Customizing the website field (by adding a text() field and giving it the key FieldKey.Website):
    • Adding a custom label.
    • Adding a custom hint.
    • Adding a custom validator.
  • Adding a custom bio text field.
  • Adding a custom terms of service checkbox.

Note: On the sign in page the input name is always username, regardless of the login mechanism type.

val state = rememberAuthenticatorState(
    signUpForm = {
        username()
        password()
        confirmPassword()
        email()

        profile(required = false)

        text(
            key = FieldKey.Website,
            label = "Website",
            hint = "Put your website here",
            required = true,
            validator = {
                if (!content.contains("example.com")) {
                    FieldError.Custom("Your website must have a domain of example.com")
                } else {
                    null
                }
            }
        )

        text(
            key = FieldKey.Custom("bio"),
            label = "Bio",
            maxLines = 3
        )

        custom(
            key = FieldKey.Custom("terms"),
            label = "Service Terms",
            validator = {
                if (!content.toBoolean()) {
                    FieldError.Custom("You must agree to the terms of service")
                } else null
            }
        ) {
            Row(
                modifier = Modifier.fillMaxWidth(),
                verticalAlignment = Alignment.CenterVertically,
                horizontalArrangement = Arrangement.spacedBy(8.dp)
            ) {
                Checkbox(
                    checked = fieldState.content.toBoolean(),
                    onCheckedChange = { fieldState.content = it.toString() },
                )
                Text("I agree to the terms of service")
            }
        }
    }
)

Theming

By default, the Amplify Authenticator uses your app's Material theme for its styling. Any customizations you make to colors, buttons, input widgets, etc. will be reflected in the Authenticator.

Below is an example with custom themes for the page titles, form fields, and elevated buttons.

private val DarkColorScheme = darkColorScheme(
    primary = Purple80,
    secondary = PurpleGrey80,
    tertiary = Pink80
)

private val LightColorScheme = lightColorScheme(
    primary = Purple40,
    secondary = PurpleGrey40,
    tertiary = Pink40

    /* Other default colors to override
    background = Color(0xFFFFFBFE),
    surface = Color(0xFFFFFBFE),
    onPrimary = Color.White,
    onSecondary = Color.White,
    onTertiary = Color.White,
    onBackground = Color(0xFF1C1B1F),
    onSurface = Color(0xFF1C1B1F),
    */
)

@Composable
fun AppTheme(
    useDarkTheme: Boolean = isSystemInDarkTheme(),
    content: @Composable () -> Unit
) {
    val colors = if (!useDarkTheme) {
        LightColorScheme
    } else {
        DarkColorScheme
    }

    MaterialTheme(
        colorScheme = colors,
        content = content
    )
}

With usage:

AppTheme() {
  Authenticator(...) {
    ...
  }
}

Full UI Customization

In addition to customizing form fields and theming, you can also build a custom UI for one or more of the authenticator steps using a combination of prebuilt widgets from the amplify_authenticator package, and widgets that you build yourself. This can be used for simple use cases, such as adding a logo to the sign in screen, as well as more complex use cases.

The Authenticator supports fully replacing the UI for any particular screen. Every screen has an associated State instance that can be used to implement custom UI. Below is an example of how you can use signInContent to customize the Sign In screen, replacing the username and password text fields, as well as the submit button.

Authenticator(
    signInContent = { state ->
        val scope = rememberCoroutineScope()
        Column {
            val username = state.form.fields[FieldKey.Username]!!
            val password = state.form.fields[FieldKey.Password]!!

            // Replace default UI with completely custom UI
            TextField(
                placeholder = { Text("Username") },
                value = username.state.content,
                onValueChange = { userName.state.content = it }
            )
            TextField(
                placeholder = { Text("Password") },
                value = password.state.content,
                onValueChange = { password.state.content = it }
            )

            Button(onClick = { scope.launch { state.signIn() } }) {
                Text("Sign In")
            }

            // Or reuse Authenticator's composables
            SignInFooter(state)
        }
    }
) {
    // ...
}

Amplify open source software, documentation and community are supported by Amazon Web Services.

© 2024 Amazon Web Services, Inc. and its affiliates. All rights reserved. View the site terms and privacy policy.

Flutter and the related logo are trademarks of Google LLC. We are not endorsed by or affiliated with Google LLC.