mo_2fa_code
A customizable one-character-per-cell code input for 2FA / OTP screens. Set the length you need, style the cells your way, and get the fiddly parts for free:
- Auto-advance to the next cell while typing, keyboard dismissed when done
- Backspace navigation — jumps back and clears the previous cell, on both soft and hardware keyboards
- Paste & autofill — pasting or SMS/email one-time-code autofill distributes the code across the cells
- Type-over — tapping a filled cell selects its character so typing replaces it
Formintegration — it is aFormField<String>, sovalidatorworks exactly like withTextFormField- Input filtering — numeric, alphanumeric or any characters, with optional upper/lower case transform
- Hint character — a placeholder shown in every empty cell
- Separators — group cells with any widget, e.g.
123 - 456 - Optional haptic feedback on every accepted character
- Optional controller to read, set or clear the code programmatically
Usage
import 'package:mo_2fa_code/mo_2fa_code.dart';
Mo2FACodeField(
length: 6,
onCompleted: (code) => verify(code),
)
That's it — 6 numeric cells with a Material 3 look.
With a Form, validation and a controller
final _formKey = GlobalKey<FormState>();
final _codeController = Mo2FACodeController();
Form(
key: _formKey,
child: Mo2FACodeField(
length: 5,
controller: _codeController,
autoFocus: true,
inputType: Mo2FAInputType.alphanumeric,
caseTransform: Mo2FACaseTransform.upperCase,
validator: (code) =>
(code ?? '').length == 5 ? null : 'Enter the full 5 character code',
onCompleted: (code) => verify(code),
),
)
// Confirm button:
if (_formKey.currentState!.validate()) {
verify(_codeController.code);
}
// After a failed verification:
_codeController.clear();
Styling
Simple tweaks through Mo2FACodeStyle:
Mo2FACodeField(
length: 4,
obscureText: true,
style: const Mo2FACodeStyle(
cellWidth: 56,
cellHeight: 64,
spacing: 8,
hintCharacter: '0', // placeholder shown in every empty cell
textStyle: TextStyle(fontSize: 26, fontWeight: FontWeight.bold),
cursorColor: Colors.indigo,
),
)
Group the cells with a separator widget:
Mo2FACodeField(
length: 6,
style: Mo2FACodeStyle(
// renders 3 cells, a dash, then 3 cells
separatorBuilder: (context, index) =>
index == 2 ? const Text('—') : null,
),
)
Full control per cell with decorationBuilder (focus and error aware):
Mo2FACodeStyle(
decorationBuilder: (context, index, {required hasFocus, required hasError}) {
return InputDecoration(
filled: true,
fillColor: hasFocus ? Colors.indigo.shade50 : Colors.grey.shade100,
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(16),
borderSide: BorderSide.none,
),
);
},
)
API overview
| Parameter | Default | Description |
|---|---|---|
length |
6 |
Number of characters in the code |
inputType |
numeric |
numeric, alphanumeric or any |
caseTransform |
none |
upperCase, lowerCase or none |
onChanged |
— | Fired on every change with the partial code |
onCompleted |
— | Fired once every cell is filled |
controller |
— | Mo2FACodeController to read / set / clear the code |
validator |
— | Standard FormField validator, receives the full code string |
obscureText |
false |
Hide characters (see Mo2FACodeStyle.obscuringCharacter) |
autoFocus |
false |
Focus the first cell on mount |
readOnly |
false |
Show the code without allowing edits |
hapticFeedback |
false |
Light haptic impact on every accepted character |
keyboardType |
derived | Override the keyboard derived from inputType |
autofillHints |
[oneTimeCode] |
Autofill hints for the first cell; pass [] to disable |
style |
Mo2FACodeStyle() |
Cell size, spacing, hint character, text style, decoration, separators, error style |
See the example for a complete 2FA screen.
Libraries
- mo_2fa_code
- A customizable one-character-per-cell code input for 2FA / OTP screens.