OTP Field
Collect a verification code through one accessible input rendered as individual slots.
Collect a verification code through one accessible input rendered as individual slots.
Contract
| Axis | Contract |
|---|---|
| Value | The default constructor is uncontrolled: seed it with defaultValue, or pass a TROtpFieldController to read and clear the code from outside. TROtpField.controlled takes value instead and expects you to store the next code from onValueChange. |
| Input | One hidden TextField sits under the slots, so typing, pasting a whole code, deleting, and platform autofill through AutofillHints.oneTimeCode all act on the full value. Entry always appends at the end; there is no per-slot caret to move between. |
| Accepted characters | allowedPattern defaults to RegExp("[0-9]") and is enforced by a FilteringTextInputFormatter, so anything else is dropped as it arrives. Rejection is silent: there is no invalid-input callback, so state the expected format in helperText. |
| Length and size | length clamps the value and decides when onCompleted fires. uiSize scales the square slots along the shared control height scale, so md and lg line up with a neighboring TRTextField or TRButton of the same size. |
Reach for TROtpField when the reader transcribes a short fixed-length code from another device. Use TRTextField for anything longer or free-form.
Install
Add the package, then import its public library.
flutter pub add tinyrack_uiimport 'package:tinyrack_ui/tinyrack_ui.dart';Playground
Usage
import 'package:material_ui/material_ui.dart';
import 'package:tinyrack_ui/tinyrack_ui.dart';
TROtpField(
label: 'Verification code',
length: 6,
helperText: 'Enter the code we sent to your device.',
onCompleted: verifyCode,
)Examples
Sizes permalink
Choose `uiSize` so the slots line up with the `TRTextField`, `TRButton`, or `TRNumberField` beside them. The digit style stays the same at every size; only the square slots and the default gap change.
Length and availability permalink
`length` sets the slot count and decides when `onCompleted` fires. `readOnly` keeps a code visible and focusable but rejects edits, while `enabled: false` mutes the whole field and blocks focus.
Required code and recovery permalink
`TROtpFieldFormField` joins the surrounding `Form`, so `validator` output lands in `errorText` and turns the slot borders red. `AutovalidateMode.onUserInteraction` reports a short code while the reader is still typing rather than only on submit.
Masked entry and reset permalink
`obscureText` replaces each digit with a bullet and stops the value from reaching `Semantics`, so use it only for a code that stays secret after entry. A `TROtpFieldController` clears the field from a Retry action, and `separatorBuilder` replaces the gap after the slot at `index` — return a plain `SizedBox` for the seams that should stay empty.
API
TROtpField properties
| Prop | Type / default | Purpose |
|---|---|---|
length | int · 6 | Sets the slot count, clamps the value to that many characters, and gates onCompleted. Must be greater than zero. |
defaultValue | String · '' | Seeds the uncontrolled default constructor. Ignored by TROtpField.controlled. |
value | String · required on .controlled | Drives the rendered code in the controlled constructor. Pair it with onValueChange and store the next code yourself. |
controller | TROtpFieldController? · null | Reads, replaces, or clears the code from outside the widget without switching to the controlled constructor. |
onValueChange | ValueChanged<String>? · null | Fires on every accepted edit with the clamped value. Filtered-out characters never reach it. |
onCompleted | ValueChanged<String>? · null | Fires when the value reaches length, including when a paste fills the field in one step. It runs on every edit that leaves the field full, so make the callback safe to repeat. |
allowedPattern | Pattern? · RegExp("[0-9]") | Restricts accepted characters. Widen it for alphanumeric codes, for example RegExp("[A-Z0-9]"). |
obscureText | bool · false | Replaces each filled slot with a bullet and stops the value from being exposed through Semantics. |
uiSize | TRUiSize · TRUiSize.md | Scales the square slots and the default gap to the md or lg control height. A separatorBuilder replaces the gap entirely, so size it yourself there. |
label | String? · null | Renders an uppercased caption above the slots and names the field for assistive technology unless semanticLabel overrides it. |
semanticLabel | String? · null | Takes precedence over label for assistive technology. Use it when the visible caption is too terse to stand alone. |
helperText | String? · null | Shows muted supporting text below the slots. errorText replaces it while an error is present. |
errorText | String? · null | Switches the slot borders to the danger color and replaces the supporting line. A non-null value marks the field invalid on its own; validation stays yours to run. |
enabled | bool · true | When false, mutes the slots, blocks tap-to-focus and editing, and dims the label. |
readOnly | bool · false | Keeps the field focusable and its value visible while rejecting edits. Use it for a code the reader should see but not change. |
autofocus | bool · false | Focuses the field on first build. Use it only when the code entry is the sole purpose of the screen. |
separatorBuilder | TROtpSeparatorBuilder? · null | Replaces the gap after slot index. Return a plain SizedBox for the seams that should stay empty; returning nothing is not an option. |
TROtpFieldController
| Prop | Type / default | Purpose |
|---|---|---|
value | String | Reads or replaces the current code. Assigning notifies listeners and re-renders the slots; assigning the same string is a no-op. |
clear() | void | Empties the field. Pair it with a Retry action after a rejected code. |
TROtpFieldFormField
| Prop | Type / default | Purpose |
|---|---|---|
initialValue | String · '' | Seeds the FormField state, which owns the value from then on. |
validator | FormFieldValidator<String>? · null | Returns the message to show as errorText. Return null once the code is acceptable. |
autovalidateMode | AutovalidateMode? · null | Chooses when the validator runs. onUserInteraction reports a short code as soon as the reader edits it. |
onSaved | FormFieldSetter<String>? · null | Receives the code when the surrounding Form is saved. |
restorationId | String? · null | Restores the entered code after the platform recreates the route. |