Amplify UI

Customization

Override and customize your Authenticator.

The Authenticator has several "slots" that you can customize to add messaging & functionality to meet your app's needs.

The Authenticator itself has the following optional slots which are rendered on each subcomponent:

  • Container - Wraps the Authenticator. Can be overridden by extending Authenticator.Container or with a View component
  • Footer - renders below subcomponent content, no default provided
  • Header - renders above subcomponent content, no default provided

The default Container component contains keyboard aware scroll behavior.

import React from 'react';
import { Button, StyleSheet, Text, View } from 'react-native';

import { Amplify } from 'aws-amplify';
import {
  Authenticator,
  useAuthenticator,
  useTheme,
} from '@aws-amplify/ui-react-native';

import awsconfig from './aws-exports';
Amplify.configure(awsconfig);

const MyAppHeader = () => {
  const {
    tokens: { space, fontSizes },
  } = useTheme();
  return (
    <View>
      <Text style={{ fontSize: fontSizes.xxxl, padding: space.xl }}>
        My Header
      </Text>
    </View>
  );
};

function SignOutButton() {
  const { signOut } = useAuthenticator();
  return <Button onPress={signOut} title="Sign Out" />;
}

function App() {
  const {
    tokens: { colors },
  } = useTheme();

  return (
    <Authenticator.Provider>
      <Authenticator
        // will wrap every subcomponent
        Container={(props) => (
          // reuse default `Container` and apply custom background
          <Authenticator.Container
            {...props}
            style={{ backgroundColor: colors.pink[20] }}
          />
        )}
        // will render on every subcomponent
        Header={MyAppHeader}
      >
        <View style={style.container}>
          <SignOutButton />
        </View>
      </Authenticator>
    </Authenticator.Provider>
  );
}

const style = StyleSheet.create({
  container: { flex: 1, alignItems: 'center', justifyContent: 'center' },
});

export default App;

Addtionally, the subcomponents themselves have Header and Footer slots specific to a subcomponent:

  • Footer - renders below subcomponent buttons, above top level Footer, no default provided
  • Header - renders above subcomponent content, below top level Header, default renders subcomponent title
import React from 'react';
import { Button, StyleSheet, Text, View } from 'react-native';

import { Amplify } from 'aws-amplify';
import { Authenticator, useAuthenticator } from '@aws-amplify/ui-react-native';

import awsconfig from './aws-exports';
Amplify.configure(awsconfig);

const MySignInFooter = () => <Text>My Footer</Text>;

function SignOutButton() {
  const { signOut } = useAuthenticator();
  return <Button onPress={signOut} title="Sign Out" />;
}

function App() {
  return (
    <Authenticator.Provider>
      <Authenticator
        components={{
          SignUp: (props) => (
            // will render only on the SignIn subcomponent
            <Authenticator.SignUp {...props} Footer={MySignInFooter} />
          ),
        }}
      >
        <View style={style.container}>
          <SignOutButton />
        </View>
      </Authenticator>
    </Authenticator.Provider>
  );
}

const style = StyleSheet.create({
  container: { flex: 1, alignItems: 'center', justifyContent: 'center' },
});

export default App;

Subcomponent Override Slots

The Authenticator subcomponents can be overridden allowing for advanced use cases:

import React from 'react';
import { Button, StyleSheet, Text, View } from 'react-native';

import { Amplify } from 'aws-amplify';
import { Authenticator, useAuthenticator } from '@aws-amplify/ui-react-native';

import awsconfig from './aws-exports';
Amplify.configure(awsconfig);

function SignOutButton() {
  const { signOut } = useAuthenticator();
  return <Button onPress={signOut} title="Sign Out" />;
}

const MySignIn = () => {
  return (
    <View>
      <Text>My Sign In</Text>
    </View>
  );
};

function App() {
  return (
    <Authenticator.Provider>
      <Authenticator
        // render override SignIn subcomponent
        components={{ SignIn: MySignIn }}
      >
        <View style={style.container}>
          <SignOutButton />
        </View>
      </Authenticator>
    </Authenticator.Provider>
  );
}

const style = StyleSheet.create({
  container: { flex: 1, alignItems: 'center', justifyContent: 'center' },
});

export default App;

Override Function Calls

You can override the call to signUp, signIn, confirmSignIn, confirmSignUp, forgotPassword and forgotPasswordSubmit functions. To override a call you must create a new services object with an async handle* function that returns an aws-amplify Auth.* promise.

The service object must then be passed into the authenticator component as a services prop. For example, let's imagine you'd like to lowercase the username and the email attributes during signUp. This would be overriden like so:

Sign Up Auto Sign In

When overriding signUp you must include the autoSignIn key and set enabled to true, as show in the example below.

import React from 'react';
import { Button } from 'react-native';

import { Authenticator, useAuthenticator } from '@aws-amplify/ui-react-native';
import { Amplify } from 'aws-amplify';
import { SignUpInput, signUp } from 'aws-amplify/auth';

import awsconfig from './aws-exports';

Amplify.configure(awsconfig);

function SignOutButton() {
  const { signOut } = useAuthenticator();
  return <Button title="Sign Out" onPress={signOut} />;
}

function App() {
  return (
    <Authenticator.Provider>
      <Authenticator
        services={{
          handleSignUp: ({ username, password, options }: SignUpInput) =>
            signUp({
              username: username.toLowerCase(),
              password,
              options: {
                ...options,
                userAttributes: {
                  ...options?.userAttributes,
                  email: options?.userAttributes?.email?.toLowerCase(),
                },
              },
            }),
        }}
      >
        <SignOutButton />
      </Authenticator>
    </Authenticator.Provider>
  );
}

export default App;

Each handle* function accepts as input the expected input of its corresponding Auth function, allowing you to override the Auth function call from within the handle* function. Here is a table of each override function name, and the values passed as input.

Auth Function CallOverride Nameinput Properties
signUphandleSignUp{username, password}
signInhandleSignIn{username, password}
confirmSignInhandleConfirmSignIn{challengeResponse}
confirmSignUphandleConfirmSignUp{username, confirmationCode}
resetPasswordhandleResetPassword{username}
confirmResetPasswordhandleConfirmResetPassword{username, newPassword, confirmationCode}
Function CallOverride NameformData Properties
Auth.signUphandleSignUp{username, password, attributes}
Auth.signInhandleSignIn{username, password}
Auth.confirmSignInhandleConfirmSignIn{user, code, mfaType}
Auth.confirmSignUphandleConfirmSignUp{username, code}
Auth.forgotPasswordhandleForgotPassword{username}
Auth.forgotPasswordSubmithandleForgotPasswordSubmit{username, code, password}

Internationalization (I18n)

The Authenticator ships with translations for:

  • en – English (default)
  • zh – Chinese
  • nl – Dutch
  • fr – French
  • de – German
  • id – Indonesian
  • it – Italian
  • ja – Japanese
  • ko – Korean
  • pl – Polish
  • pt – Portuguese
  • ru – Russian
  • es – Spanish
  • sv – Swedish
  • tr – Turkish

These translations can be customized using the Amplify JS' I18n module:

Note: The import path for i18n changed from aws-amplify to aws-amplify/utils in aws-amplify@6

import { I18n } from 'aws-amplify/utils';
import { translations } from '@aws-amplify/ui';
I18n.putVocabularies(translations);
I18n.setLanguage('fr');

I18n.putVocabularies({
  fr: {
    'Sign In': 'Se connecter',
    'Sign Up': "S'inscrire",
  },
  es: {
    'Sign In': 'Registrarse',
    'Sign Up': 'Regístrate',
  },
});

The list of available keys are available here.

Confirm Sign Up Page Translations

The confirm sign up page has a few specialized strings that can be translated. These include:

`Your code is on the way. To log in, enter the code we emailed to`

`Your code is on the way. To log in, enter the code we texted to`

`Your code is on the way. To log in, enter the code we sent you. It may take a minute to arrive.`

`It may take a minute to arrive.`
Translations Needed 📖

If you see any missing translations or would like to contribute a new language, we greatly appreciate contributions to translations we have here.

Labels & Text

Using the same techniques as Internationalization (I18n), you can customize the labels and text of the components:

Sign In

I18n.putVocabulariesForLanguage('en', {
  'Sign In': 'Login', // Tab header
  'Sign in': 'Log in', // Button label
  'Sign in to your account': 'Welcome Back!',
  Username: 'Enter your username', // Username label
  Password: 'Enter your password', // Password label
  'Forgot your password?': 'Reset Password',
});

Sign Up

I18n.putVocabulariesForLanguage('en', {
  'Create Account': 'Register', // Link text
  'Create a new account': 'New User', // Header text
  'Confirm Password': 'Confirm your password', // Confirm Password label
  Email: 'Enter your email',
  'Phone Number': 'Enter your phone number',
});

Forgot Password

I18n.putVocabulariesForLanguage('en', {
  'Reset your password': 'Forgot your password?',
  'Enter your username': 'Username or Email',
  'Send code': 'Reset my password',
  'Back to Sign In': 'Back to Login',
});

Setup TOTP

I18n.putVocabulariesForLanguage('en', {
  Code: '2FA Code',
  Confirm: 'Confirm 2FA',
  'Back to Sign In': 'Back to Login',
});

Form Field Customization

Extend or override the existing fields for an Authenticator subcomponent by passing an array of field option objects to the fields prop:

import React from 'react';
import { Button, StyleSheet, View } from 'react-native';

import { Authenticator, useAuthenticator } from '@aws-amplify/ui-react-native';
import { Amplify } from 'aws-amplify';

import awsconfig from './aws-exports';
Amplify.configure(awsconfig);

function SignOutButton() {
  const { signOut } = useAuthenticator();
  return <Button onPress={signOut} title="Sign Out" />;
}

function App() {
  return (
    <Authenticator.Provider>
      <Authenticator
        components={{
          SignUp: ({ fields, ...props }) => (
            <Authenticator.SignUp
              {...props}
              fields={[
                ...fields,
                {
                  name: 'preferred_username',
                  label: 'Preferred Username',
                  type: 'default',
                  placeholder: 'Enter your preferred username',
                },
              ]}
            />
          ),
        }}
      >
        <View style={style.container}>
          <SignOutButton />
        </View>
      </Authenticator>
    </Authenticator.Provider>
  );
}

const style = StyleSheet.create({
  container: { flex: 1, alignItems: 'center', justifyContent: 'center' },
});

export default App;

Label hidden

Default fields include label values. To render the fields without labels:

import React from 'react';
import { Button, StyleSheet, View } from 'react-native';

import { Authenticator, useAuthenticator } from '@aws-amplify/ui-react-native';
import { Amplify } from 'aws-amplify';

import awsconfig from './aws-exports';
Amplify.configure(awsconfig);

function SignOutButton() {
  const { signOut } = useAuthenticator();
  return <Button onPress={signOut} title="Sign Out" />;
}

function App() {
  return (
    <Authenticator.Provider>
      <Authenticator
        components={{
          SignIn: ({ fields, ...props }) => (
            <Authenticator.SignIn
              {...props}
              fields={fields.map((field) => ({ ...field, labelHidden: true }))}
            />
          ),
        }}
      >
        <View style={style.container}>
          <SignOutButton />
        </View>
      </Authenticator>
    </Authenticator.Provider>
  );
}

const style = StyleSheet.create({
  container: { flex: 1, alignItems: 'center', justifyContent: 'center' },
});

export default App;

Styling

Theme Provider

You can update the style of the Authenticator by wrapping it with a ThemeProvider. Then create a theme object, with all your font customizations.

import React from 'react';

import { Authenticator, ThemeProvider } from '@aws-amplify/ui-react-native';
import { Amplify } from 'aws-amplify';

import config from './aws-exports';

Amplify.configure(config);

function App() {
  return (
    <ThemeProvider
      theme={{
        tokens: {
          colors: {
            primary: {
              10: '{colors.pink.10}',
              20: '{colors.pink.20}',
              40: '{colors.pink.40}',
              60: '{colors.pink.60}',
              80: '{colors.pink.80}',
              90: '{colors.pink.90}',
              100: '{colors.pink.100}',
            },
          },
        },
      }}
    >
      <Authenticator.Provider>
        <Authenticator />
      </Authenticator.Provider>
    </ThemeProvider>
  );
}

export default App;

If you have TypeScript enabled, all the object keys will be present when creating the theme object. This will help speed up your development time while creating themes.

Dark mode

Amplify UI comes with a default dark mode implementation

import React from 'react';
import { useColorScheme } from 'react-native';

import {
  Authenticator,
  defaultDarkModeOverride,
  ThemeProvider,
} from '@aws-amplify/ui-react-native';
import { Amplify } from 'aws-amplify';

import config from './aws-exports';

Amplify.configure(config);

function App() {
  const colorMode = useColorScheme();
  return (
    <ThemeProvider
      colorMode={colorMode}
      theme={{
        tokens: {
          colors: {
            primary: {
              10: '{colors.pink.10}',
              20: '{colors.pink.20}',
              40: '{colors.pink.40}',
              60: '{colors.pink.60}',
              80: '{colors.pink.80}',
              90: '{colors.pink.90}',
              100: '{colors.pink.100}',
            },
          },
        },
        overrides: [defaultDarkModeOverride],
      }}
    >
      <Authenticator.Provider>
        <Authenticator />
      </Authenticator.Provider>
    </ThemeProvider>
  );
}

export default App;

Learn more about dark mode

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.