I need to restrict when the user types 1.. like this. i'm using text input form field. I need input like 1.23 with decimal input text formatter
-
Please provide some code as well. So this will be a better reference for others. See [this](https://stackoverflow.com/help/minimal-reproducible-example) to understand why. – om-ha Dec 30 '19 at 13:32
-
how about marking the answer as accepted? – om-ha Jan 07 '20 at 08:38
6 Answers
With WhitelistingTextInputFormatter deprecated
TextField(
keyboardType: TextInputType.numberWithOptions(decimal: true),
inputFormatters: <TextInputFormatter>[
FilteringTextInputFormatter.allow(RegExp(r'^\d+\.?\d*')),
], // Only numbers can be entered
),

- 530
- 5
- 7
-
Cool answer!! I've just copied and pasted this formatter and all things went well on version 2.0.6! Thank you [: – tsitixe May 16 '21 at 09:18
-
Why does it not allow . at the start and what changes do we need to make to make it allow that? – Shahood ul Hassan Nov 30 '22 at 04:33
We can create our own TextInputFormatter
.
Check this
import 'package:flutter/services.dart';
class DecimalTextInputFormatter extends TextInputFormatter {
@override
TextEditingValue formatEditUpdate(TextEditingValue oldValue, TextEditingValue newValue) {
final regEx = RegExp(r"^\d*\.?\d*");
String newString = regEx.stringMatch(newValue.text) ?? "";
return newString == newValue.text ? newValue : oldValue;
}
}
Usage:
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
home: FirstPage(),
debugShowCheckedModeBanner: false,
);
}
}
class FirstPage extends StatefulWidget {
@override
_FirstPageState createState() => _FirstPageState();
}
class _FirstPageState extends State<FirstPage> {
@override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: TextField(
inputFormatters: [DecimalTextInputFormatter()],
),
),
);
}
}

- 13,595
- 4
- 30
- 54
Flutter 1.20 update
As the user @ZaH mentioned, WhitelistingTextInputFormatter
has been deprecated as of Flutter 1.20, instead FilteringTextInputFormatter.allow()
should be used. Check out ZaH's answer here and give em an upvote. You can find the docs for the class and constructor.
TextFormField(
inputFormatters: [
FilteringTextInputFormatter.allow(RegExp(r"\d+([\.]\d+)?")),
],
);
Solution
Here is what you need to do for your specific use case:
TextFormField(
inputFormatters: [
WhitelistingTextInputFormatter(RegExp(r"\d+([\.]\d+)?")),
],
);
Explanation
You need to use TextInputFormatter
class. Specifically WhitelistingTextInputFormatter.
The above code only allows numbers of the pattern you provided in your question. Numbers with optionally any number of decimal digits with one decimal point allowed.
The r
prefix before the string as in r""
makes the string a raw string
. This prevents filtering and treatment of special characters within the string. From the docs:
Note the use of a raw string (a string prefixed with r) in the example above. Use a raw string to treat each character in a string as a literal character.
Regex Dissection
Here's a dissection of the regex pattern ^\d+([\.]\d+)?$
:
\d
digit -- allows digits from all languages.+
one or more occurrence.(PATTERN)?
zero or one occurrences -- this allows numbers without decimal dot/digits.[\.]
allows dot character -- the \ is used to escape it since it's a control character in regex.
Sources
- How to use InputFormatter on Flutter TextField?
- Flutter: Formatting TextField with TextInputFormatter
- TextFormField class
- Use regexr as a playground for the regex expressions.

- 3,102
- 24
- 37
-
1Just as an additional note ```(PATTERN)?``` means zero or **one** ocurrence of ```(PATTERN)```. – Naslausky Sep 25 '21 at 13:12
-
1Correct, `*` means **zero or more**, `?` means **zero or one**. `(PATTERN)?` is a correct expression to use here but the explanation is incorrect as you mentioned. Thanks I just updated it. – om-ha Sep 25 '21 at 15:28
-
`\.` is redundant and if we don't escape, decimal dot is not allowed. Seems like a wrong answer. – Shahood ul Hassan Nov 30 '22 at 04:30
-
Thanks for your comment @ShahoodulHassan If it's redundant then what part of the regex already allows the dot? – om-ha Nov 30 '22 at 10:07
-
Ah well, the Android Studio says it is redundant is what I meant. Removing it didn't serve the purpose either. `RegExp(r'^\d+\.?\d*'))` suggested by @Mathulan worked perfect. – Shahood ul Hassan Nov 30 '22 at 12:53
-
Weird, I just tried the regex on regexr.com. `123` and `12.3` are correct. `1..23` is incorrect (doesn't get a match). So my answer here should be correct. – om-ha Nov 30 '22 at 16:32
the answer from om-ha is correct, however for future reference, WhitelistingTextInputFormatter is deprecated in Flutter as of 1.20, now we should use FilteringTextInputFormatter.allow() instead.
or use FilteringTextInputFormatter.deny instead of BlacklistingTextInputFormatter if that is what you want.
above code should become:
TextFormField(
inputFormatters: [
FilteringTextInputFormatter.allow(RegExp(r"\d+([\.]\d+)?")),
],
);

- 106
- 5
-
Thanks for the update ZaH! I updated my answer accordingly & linked yours. https://stackoverflow.com/a/59531639/10830091 – om-ha Sep 25 '21 at 12:04
you can also try decimal validation on form submit.
bool isValidDecimal(String value){
String regex = r'^[0-9]+[.]{1}[0-9]+$';
RegExp regExp = RegExp(regex);
return regExp.hasMatch(value);
}

- 1,372
- 2
- 5
- 12
This will allow any number, using the locale specific decimal separator (afaik always either ',' or '.'). The intl
package is used to get that separator.
import 'package:intl/intl.dart';
...
TextFormField(
inputFormatters: [
TextInputFormatter.withFunction((oldValue, newValue) {
var decimalSeparator = NumberFormat().symbols.DECIMAL_SEP;
var r = RegExp(r'^\d*(\' + decimalSeparator + r'\d*)?$');
return r.hasMatch(newValue.text) ? newValue : oldValue;
})
],
...
As an aside, the answers using FilteringTextInputFormatter
will work to validate initial input but will show strange behavior when trying to edit a valid number to an invalid one - some characters will get overwritten, others deleted.
As per the docs:
Consider using a different TextInputFormatter ... for accepting/rejecting new input based on a predicate on the full string. As an example, FilteringTextInputFormatter typically shouldn't be used with RegExps that contain positional matchers (^ or $) since these patterns are usually meant for matching the whole string.

- 199
- 1
- 8