Toggle password entry in Xamarin.Forms

November 20th 2020 Xamarin

The Xamarin.Forms Entry view has a flag for password input:

<Entry Placeholder="Password"
       IsPassword="True"
       Text="{Binding Password}" />

However, there's no built-in way to allow the user to look at the password to make sure it was entered correctly. This is becoming a norm in mobile applications:

Visibility toggle for password input field

Fortunately, it's not too difficult to implement. The password entry can be accompanied by an ImageButton view that toggles the IsPassword flag (as well as its icon from the Font Awesome collection):

<Grid>
  <Grid.ColumnDefinitions>
    <ColumnDefinition Width="*"/>
    <ColumnDefinition Width="30"/>
  </Grid.ColumnDefinitions>
  <Entry Placeholder="Password"
         IsPassword="{Binding HidePassword}"
         Text="{Binding Password}" />
  <ImageButton Command="{Binding TogglePasswordCommand}"
               BackgroundColor="Transparent"
               Grid.Column="1">
      <ImageButton.Triggers>
        <DataTrigger TargetType="ImageButton"
                     Binding="{Binding HidePassword}"
                     Value="True">
          <Setter Property="Source">
            <Setter.Value>
              <FontImageSource FontFamily="FontAwesome5Regular"
                               Color="Black"
                               Glyph="&#xf06e;" />
            </Setter.Value>
          </Setter>
        </DataTrigger>
        <DataTrigger TargetType="ImageButton"
                     Binding="{Binding HidePassword}"
                     Value="False">
          <Setter Property="Source">
            <Setter.Value>
              <FontImageSource FontFamily="FontAwesome5Regular"
                               Color="Black"
                               Glyph="&#xf070;" />
            </Setter.Value>
          </Setter>
        </DataTrigger>
      </ImageButton.Triggers>
  </ImageButton>
</Grid>

I described the use of Font Awesome in Xamarin.Forms in my previous blog post. So, I'm only going to focus on the view model implementation for this markup. It consists of a property and a command:

private bool hidePassword = true;

public Command TogglePasswordCommand { get; }

public bool HidePassword
{
  get => hidePassword;
  private set => SetProperty(ref hidePassword, value);
}

public LoginViewModel()
{
  // ...
  TogglePasswordCommand = new Command(OnTogglePasswordClicked);
}

private void OnTogglePasswordClicked()
{
  HidePassword = !HidePassword;
}

Despite its simplicity, you still don't want to copy all of this markup and code to every page with a password input. This gets even more inconvenient if there's more than one password input on a page (e.g. for account creation or password reset).

The solution is to wrap everything in a custom view. The markup can remain almost identical, with minor changes in the bindings:

<?xml version="1.0" encoding="UTF-8"?>
<ContentView xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="PasswordToggle.Controls.TogglePasswordEntry"
             x:Name="root">
  <ContentView.Content>
    <Grid BindingContext="{x:Reference root}">
      <Grid.ColumnDefinitions>
        <ColumnDefinition Width="*"/>
        <ColumnDefinition Width="30"/>
      </Grid.ColumnDefinitions>
      <Entry Placeholder="{Binding Placeholder}"
             Text="{Binding Text}"
             IsPassword="{Binding HidePassword}"/>
      <ImageButton Clicked="OnImageButtonClicked"
                   BackgroundColor="Transparent"
                   Grid.Column="1">
          <ImageButton.Triggers>
            <DataTrigger TargetType="ImageButton"
                         Binding="{Binding HidePassword}"
                         Value="True">
              <Setter Property="Source">
                <Setter.Value>
                  <FontImageSource FontFamily="FontAwesome5Regular"
                                   Color="Black"
                                   Glyph="&#xf06e;" />
                </Setter.Value>
              </Setter>
            </DataTrigger>
            <DataTrigger TargetType="ImageButton"
                         Binding="{Binding HidePassword}"
                         Value="False">
              <Setter Property="Source">
                <Setter.Value>
                  <FontImageSource FontFamily="FontAwesome5Regular"
                                   Color="Black"
                                   Glyph="&#xf070;" />
                </Setter.Value>
              </Setter>
            </DataTrigger>
          </ImageButton.Triggers>
      </ImageButton>
    </Grid>
  </ContentView.Content>
</ContentView>

Notice in particular, how I set the BindingContext at the top level Grid layout to the control class with the necessary properties.

Of all the Entry properties I only needed Placeholder and Text to be exposed as bindable properties of my view:

public static readonly BindableProperty PlaceholderProperty =
  BindableProperty.Create(
    nameof(Placeholder),
    typeof(string),
    typeof(TogglePasswordEntry));

public static readonly BindableProperty TextProperty =
  BindableProperty.Create(
    nameof(Text),
    typeof(string),
    typeof(TogglePasswordEntry),
    defaultBindingMode: BindingMode.TwoWay);

public string Placeholder
{
  get => (string)GetValue(PlaceholderProperty);
  set => SetValue(PlaceholderProperty, value);
}

public string Text
{
  get => (string)GetValue(TextProperty);
  set => SetValue(TextProperty, value);
}

I also created a bindable property for HidePassword to allow for setting the starting value and reacting to value change elsewhere on the page:

public static readonly BindableProperty HidePasswordProperty =
  BindableProperty.Create(
    nameof(HidePassword),
    typeof(bool),
    typeof(TogglePasswordEntry),
    defaultValue: true);

public bool HidePassword
{
  get => (bool)GetValue(HidePasswordProperty);
  set => SetValue(HidePasswordProperty, value);
}

For toggling the value, I used an event handler instead of a command:

private void OnImageButtonClicked(object sender, EventArgs e)
{
  HidePassword = !HidePassword;
}

The view can now easily be reused across pages without any supporting code:

<controls:TogglePasswordEntry Placeholder="Password"
                              Text="{Binding Password}"
                              HidePassword="True"/>

You can try it out on the login page of my sample application. You can find it in my GitHub repository.

To create a password entry with toggleable password visibility in Xamarin.Forms, an image button can be added to the entry field which toggles the flag for password input. To make the implementation reusable, it can be wrapped in a custom view.

Get notified when a new blog post is published (usually every Friday):

Copyright
Creative Commons License