# PinCode

> This page is about FlutterFlow Studio (the visual builder), not FlutterFlow (the app builder you use by describing your app).

URL: https://docs.flutterflow.io/resources/ui/widgets/built-in-widgets/pincode

Learn how to collect, validate, and customize PIN and one-time password input with the PinCode widget.

The **PinCode** widget provides a row of individual fields for entering a PIN or one-time password (OTP). Use it for flows such as account verification, sign-in, transaction confirmation, or device pairing.

You can retrieve the entered code and use it in actions or conditions. FlutterFlow Studio stores this value in the PinCode widget's [Widget State](https://docs.flutterflow.io/concepts/state-management/widget-state).

A PinCode widget collects a code, makes it available through Widget State, and sends it to a secure service for verification.

:::caution[Handle Codes Securely]
Do not expose PINs and OTPs outside the intended input and verification flow. Never include them in snackbars, logs, analytics, or error reports, and do not store them as plain text. Send the entered code to the relevant authentication provider or a secure backend for verification. A client-side comparison alone does not securely verify a code.
:::

## Adding a PinCode Widget

1. Open the [Widget Palette](https://docs.flutterflow.io/flutterflow-ui/widget-palette) and add the **PinCode** widget from **Form Elements**.
2. Select the widget and open the [Properties Panel](https://docs.flutterflow.io/flutterflow-ui/builder#properties-panel).
3. Under **Pin Code Properties**, set **Pin Length** to the number of characters users must enter. The maximum length is `8`.
4. Choose a **Keyboard Type** that matches the expected code.

## PinCode Events

The following events are available from the PinCode widget's **Actions** tab.

### On Completed

**On Completed** runs when the number of entered characters reaches **Pin Length**. Use it to start a verification request, enable the next step, or update the interface.

This event only indicates that every field contains a value. It does not confirm that the entered code is valid.

### On Change

**On Change** runs whenever a character is entered or deleted. Use it to update the interface as the value changes. See [On Change](https://docs.flutterflow.io/resources/forms/form-triggers#on-change) for more information.

### On Focus Change

**On Focus Change** runs when the PinCode widget gains or loses focus. Use it to update guidance or run validation when the user moves away from the widget. See [On Focus Change](https://docs.flutterflow.io/resources/forms/form-triggers#on-focus-change) for more information.

## Validation

Validating a PIN or OTP involves three separate checks:

1. Check that the field is not empty.
2. Check that the code contains the required number of characters.
3. Check that the entered code is correct.

### 1. Require a Code

Use a [Form](https://docs.flutterflow.io/resources/forms/form-validation#adding-form-widget) to prevent users from submitting an empty PinCode field:

1. Place the **PinCode** widget inside a **Form** widget.
2. Select the Form and open **Properties Panel > Validation**.
3. Find the PinCode widget, enable its validation, and enter the error message to display when the field is empty.
4. Select the button or control that submits the code and open its **Actions** tab.
5. Add the **Validate Form** action. Under **Select Form to Validate**, choose the Form that contains the PinCode widget.

When the user submits the form without entering a code, FlutterFlow Studio displays the error message.

### 2. Confirm the Code Is Complete

Before requesting verification, ensure that the user entered every character required by **Pin Length**. You can continue the flow from [**On Completed**](#on-completed), or add a condition that checks whether the entered value contains the required number of characters.

### 3. Verify the Code

Send the complete value to your authentication provider or secure backend. Continue the flow only when that service confirms that the code is correct.

:::caution
Form validation only checks whether the PinCode field is empty. It does not confirm that every field is complete or that the PIN or OTP is correct.
:::

## Customizing

Select the **PinCode** widget and open **Pin Code Properties** in the [Properties Panel](https://docs.flutterflow.io/flutterflow-ui/builder#properties-panel).

### Configuring Input

- **Pin Length:** Sets the number of characters in the code, up to `8`.
- **Keyboard Type:** Uses a numeric keyboard by default. Select **Visible Password** when the code can contain letters and numbers. The keyboard layout can vary by platform.

### Configuring the Entry Animation

- **Animation:** Selects the animation used when a character is entered, such as **Slide**.
- **Animation Curve:** Controls how the animation speeds up or slows down. Leave it **Unset** to use the default curve.
- **Animation Duration (ms):** Sets how long the animation takes in milliseconds.

### Hiding Entered Characters

- **Obscure Text:** Replaces each entered character with the selected **Obscuring Character**.
- **Obscuring Character:** Selects the character used to hide the entered value.
- **Blink When Obscuring:** Adds a brief blink effect when a newly entered character is obscured.
- **Blink Duration:** Sets the duration of the obscuring blink in milliseconds.

### Configuring Input Behavior

- **Hint Text:** Displays the selected **Hint Character** in each empty field.
- **Hint Character:** Selects the character displayed in empty fields when **Hint Text** is enabled.
- **Auto Focus:** Focuses the PinCode widget and opens the keyboard when the page loads. Disable it when another element should receive focus first.
- **Auto Fill:** Allows supported operating systems to suggest a received verification code. Availability depends on the platform, device settings, and message format.
- **Read Only:** Displays the PinCode value without allowing the user to edit it.
- **Haptic Feedback:** Provides haptic feedback on supported devices when the user enters a character.

### Aligning the Fields

Use **Pin Code Alignment** to position the fields within the available width:

- **Start:** Places the fields at the beginning.
- **Center:** Centers the fields.
- **End:** Places the fields at the end.
- **Space Evenly:** Adds equal space before, between, and after the fields.
- **Space Around:** Adds space around each field, with smaller spaces at the beginning and end.
- **Space Between:** Places equal space between the fields without adding space at the beginning or end.

### Changing Field Shape and Size

- Use **Pin Field Shape** to select **Box**, **Circle**, or **Underline**.
- Use **Field Width** and **Field Height** to set the dimensions of each field.
- When using **Box**, use **Border Radius** to round its corners and **Border Width** to adjust its outline.

### Changing Colors, Fills, and Error Borders

Use the following properties to distinguish field states:

- **Active Color:** Sets the border color of a field that contains a value.
- **Inactive Color:** Sets the border color of an empty field.
- **Selected Color:** Sets the border color of the field that currently has focus.
- **Background Color:** Sets the background color of the overall PinCode widget, including the area around the individual fields.
- **Enable Active Fill:** Determines whether the background of pin fields containing input is filled. When enabled, the next three fill-color properties become available.
- **Active Fill Color:** Sets the fill color of a field that contains a value.
- **Inactive Fill Color:** Sets the fill color of an empty field.
- **Selected Fill Color:** Sets the fill color of the field that currently has focus.
- **Error Text Height:** Reserves vertical space for a validation error message.
- **Error Border Width:** Sets the width of the field border when validation fails.
- **Error Border Color:** Sets the field border color when validation fails.

Do not rely on color alone to communicate an error or status. Include clear text guidance or an error message.

### Customizing the Cursor

Use **Show Cursor** to show or hide the text cursor and **Cursor Color** to change its color.

### Styling the Entered Text

Expand **Pin Code Text Style** to change how entered characters appear:

- **Theme Text Style:** Starts with a text style from the project theme.
- **Font Family:** Selects the font used for entered characters.
- **Font Weight:** Controls the thickness of the characters.
- **Styling:** Applies italic, underline, or strikethrough formatting.
- **Font Size:** Sets the character size.
- **Text Color:** Sets the character color.
- **Line Height:** Controls the vertical spacing within each field.
- **Letter Spacing:** Adjusts the space around each character.
- **Text Align:** Aligns the character inside each field.
- **Add Shadow:** Adds and configures a shadow behind the characters.
- **Text Overflow Replacement:** Controls how a character is handled when it does not fit inside its field.

## Accessing and Clearing the Value

To use the entered code in an action, select **Set from Variable > Widget State**, then choose the PinCode widget.

To clear the entered code, the **PinCode** widget must be inside a **Form** widget. You can then add the [Reset Form Field](https://docs.flutterflow.io/resources/forms/reset-form-field) action and select the PinCode widget. Clear sensitive values after verification and when the user requests a new code.

## Best Practices

- Verify PINs and OTPs through the relevant authentication provider or a secure backend.
- Never expose sensitive codes in snackbars, logs, analytics, or error reports.
- Use **Obscure Text** when the code must remain private while it is entered.
- Use a numeric keyboard unless the code can contain letters.
- Provide clear instructions and validation messages, and do not rely on color alone.
- Prevent duplicate verification requests while an earlier request is still in progress.
- Clear the value after successful verification, after too many failed attempts, or when the code expires.
