As discussed above, building a form in Flutter is a simple task. Depending on the requirements of your application, you can easily add validation to the different types of information that you collect.
To put the pieces together, assume you are collecting information to submit to a payment processing backend or application programming interface (API) provider such as Rapyd for processing. The backend requires the name, phone number, email address, street address, and city of the application user. To collect this information, update the _MyHomePageState
class with the following:
class _MyHomePageState extends State<MyHomePage> {
final _formKey = GlobalKey<FormState>();
final _nameController = TextEditingController();
final _emailController = TextEditingController();
final _phoneController = TextEditingController();
final _streetAddressController = TextEditingController();
final _cityController = TextEditingController();
@override
void dispose() {
_nameController.dispose();
_emailController.dispose();
_phoneController.dispose();
_streetAddressController.dispose();
_cityController.dispose();
super.dispose();
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Flutter Forms'),
body: SingleChildScrollView(
padding: EdgeInsets.symmetric(horizontal: 20, vertical: 10),
child: Form(
key: _formKey,
child: Column(
children: [
TextFormField(
controller: _nameController,
keyboardType: TextInputType.name,
decoration: inputDecoration(
prefixIcon: Icon(Icons.account_box_outlined),
hintText: 'John Doe',
labelText: 'Name'),
validator: (value) {
if (value == null || value.isEmpty) {
return 'Please fill this field';
return null;
SizedBox(
height: 10,
TextFormField(
controller: _emailController,
keyboardType: TextInputType.emailAddress,
decoration: inputDecoration(
prefixIcon: Icon(Icons.email_outlined),
hintText: '[email protected]',
labelText: 'Email Address'),
validator: (value) {
if (value == null || value.isEmpty) {
return 'Please fill this field';
return null;
SizedBox(
height: 10,
TextFormField(
controller: _phoneController,
inputFormatters: [FilteringTextInputFormatter.digitsOnly],
keyboardType: TextInputType.number,
decoration: inputDecoration(
prefixIcon: Icon(Icons.phone_android_outlined),
hintText: '12346789',
labelText: 'Phone Number'),
validator: (value) {
if (value == null || value.isEmpty) {
return 'Please fill this field';
return null;
SizedBox(
height: 10,
TextFormField(
controller: _streetAddressController,
keyboardType: TextInputType.streetAddress,
decoration: inputDecoration(
prefixIcon: Icon(Icons.streetview_outlined),
hintText: '123 State Street',
labelText: 'Street Address'),
validator: (value) {
if (value == null || value.isEmpty) {
return 'Please fill this field';
return null;
SizedBox(
height: 10,
TextFormField(
controller: _cityController,
keyboardType: TextInputType.text,
decoration: inputDecoration(
prefixIcon: Icon(Icons.location_city_outlined),
hintText: 'London',
labelText: 'City'),
validator: (value) {
if (value == null || value.isEmpty) {
return 'Please fill this field';
return null;
SizedBox(
height: 20,
ElevatedButton(
style: ElevatedButton.styleFrom(
minimumSize: Size.fromHeight(50)),
onPressed: () {
if (_formKey.currentState!.validate()) {
ScaffoldMessenger.of(context).showSnackBar(SnackBar(
content: Text(
'Hello ${_nameController.text}\nYour details have been submitted and an email sent to ${_emailController.text}.')));
} else {
// The form has some validation errors.
// Do Something...
child: Text('Submit'))
InputDecoration inputDecoration({
InputBorder? enabledBorder,
InputBorder? border,
Color? fillColor,
bool? filled,
Widget? prefixIcon,
String? hintText,
String? labelText,
InputDecoration(
enabledBorder: enabledBorder ??
OutlineInputBorder(
borderSide: BorderSide(color: Colors.blueGrey, width: 2.0)),
border: border ?? OutlineInputBorder(borderSide: BorderSide()),
fillColor: fillColor ?? Colors.white,
filled: filled ?? true,
prefixIcon: prefixIcon,
hintText: hintText,
labelText: labelText);
The inputDecoration
function provides a simple and clean implementation to decorate the TextFormField
widgets without repeating your code in multiple lines.
The variable _nameController
is of type TextEditingController()
, which watches changes in the TextFormField
input and updates its value. You can use the controller to listen to changes in user input as well as fetch their text value. To improve the performance of the app, you need to dispose of this controller using the override dispose
method.
You can refer to this GitHub repository for the full code implementation. After running the above code, you should have something similar to this when interacting with the form:
Collecting user information is a necessity for smooth operation in today’s application development. Leveraging Flutter forms makes it easy to collect this data while maintaining a great user experience. Furthermore, you can validate the provided data for correctness before it is submitted for processing.
Submitting correctly formatted and validated data is especially important when processing payments. To accept payments in your application, consider Rapyd, a solution with all the tools you need for payments, payouts, and business everywhere.
You can get started in generating a fully PCI-DSS certified hosted page and payment form that can handle personal identifying information for cards. Sign up at Rapyd Client Portal now.
Post any thoughts or related questions here in the Rapyd Developer Community.