Flutter TextField widget is one of the most fundamental and widely used input widgets in Flutter app development. The Flutter TextField widget allows users to enter text input, making it essential for forms, search functionality, and user interactions. Whether you’re building a login form, registration page, or any app requiring user input, mastering the Flutter TextField widget properties and customization options is crucial for creating professional Flutter applications.
The Flutter TextField widget provides extensive customization capabilities, from basic text input to advanced features like input validation, text formatting, and interactive behaviors. Understanding how to implement and customize the Flutter TextField widget will significantly enhance your Flutter development skills and help you create more engaging user interfaces.
The Flutter TextField widget is a stateful widget that creates a material design text input field. This Flutter TextField widget handles user text input and provides various properties to control its appearance, behavior, and functionality. The TextField widget in Flutter is highly customizable and supports different input types, decorations, and validation mechanisms.
TextField(
decoration: InputDecoration(
hintText: 'Enter your text here',
),
)
The basic Flutter TextField widget implementation requires minimal code but offers maximum flexibility for customization. You can control every aspect of the TextField widget appearance and behavior through its comprehensive property system.
The controller property in Flutter TextField widget manages the text being edited. The TextEditingController allows you to programmatically control the TextField widget content, retrieve current text, and listen to text changes.
class MyTextField extends StatefulWidget {
@override
_MyTextFieldState createState() => _MyTextFieldState();
}
class _MyTextFieldState extends State<MyTextField> {
final TextEditingController _controller = TextEditingController();
@override
Widget build(BuildContext context) {
return TextField(
controller: _controller,
decoration: InputDecoration(
labelText: 'Username',
),
);
}
@override
void dispose() {
_controller.dispose();
super.dispose();
}
}
The controller property enables you to get and set text programmatically in your Flutter TextField widget. This is particularly useful when you need to clear the field, pre-populate data, or validate input before submission.
The decoration property transforms the Flutter TextField widget appearance using InputDecoration. This property controls borders, labels, hints, icons, and overall visual styling of your TextField widget.
TextField(
decoration: InputDecoration(
labelText: 'Email Address',
hintText: 'Enter your email',
prefixIcon: Icon(Icons.email),
suffixIcon: Icon(Icons.visibility),
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(10),
),
filled: true,
fillColor: Colors.grey[200],
),
)
The InputDecoration class provides numerous properties to customize your Flutter TextField widget appearance. You can add borders, colors, icons, and text styling to create visually appealing input fields that match your app’s design theme.
The keyboardType property in Flutter TextField widget determines which keyboard layout appears when users focus on the input field. Different keyboard types optimize user experience for specific input scenarios.
// Email keyboard
TextField(
keyboardType: TextInputType.emailAddress,
decoration: InputDecoration(labelText: 'Email'),
)
// Number keyboard
TextField(
keyboardType: TextInputType.number,
decoration: InputDecoration(labelText: 'Phone Number'),
)
// Multiline keyboard
TextField(
keyboardType: TextInputType.multiline,
maxLines: 4,
decoration: InputDecoration(labelText: 'Description'),
)
The Flutter TextField widget supports various keyboard types including text, number, email, phone, datetime, multiline, and more. Choosing the appropriate keyboard type improves user experience and input accuracy.
The obscureText property in Flutter TextField widget hides the entered text, making it perfect for password fields and sensitive information input. When enabled, the TextField widget displays dots or asterisks instead of actual characters.
class PasswordField extends StatefulWidget {
@override
_PasswordFieldState createState() => _PasswordFieldState();
}
class _PasswordFieldState extends State<PasswordField> {
bool _obscureText = true;
@override
Widget build(BuildContext context) {
return TextField(
obscureText: _obscureText,
decoration: InputDecoration(
labelText: 'Password',
suffixIcon: IconButton(
icon: Icon(_obscureText ? Icons.visibility : Icons.visibility_off),
onPressed: () {
setState(() {
_obscureText = !_obscureText;
});
},
),
),
);
}
}
The obscureText property enhances security in your Flutter TextField widget by hiding sensitive input. Combined with a visibility toggle, users can choose to reveal or hide their password while typing.
The maxLength property in Flutter TextField widget limits the number of characters users can enter, while maxLines controls the height of the input field. These properties help maintain consistent UI layout and prevent excessive input.
// Single line with character limit
TextField(
maxLength: 50,
decoration: InputDecoration(
labelText: 'Title',
counterText: '', // Hides the counter
),
)
// Multi-line text area
TextField(
maxLines: 5,
maxLength: 500,
decoration: InputDecoration(
labelText: 'Comments',
alignLabelWithHint: true,
border: OutlineInputBorder(),
),
)
These properties give you precise control over Flutter TextField widget input constraints. The maxLength property prevents users from entering excessive text, while maxLines creates expandable text areas for longer content.
The textInputAction property in Flutter TextField widget customizes the action button on the software keyboard. This property improves navigation flow and user experience in forms with multiple TextField widgets.
TextField(
textInputAction: TextInputAction.next,
decoration: InputDecoration(labelText: 'First Name'),
onSubmitted: (value) {
// Move focus to next field
FocusScope.of(context).nextFocus();
},
)
TextField(
textInputAction: TextInputAction.done,
decoration: InputDecoration(labelText: 'Last Name'),
onSubmitted: (value) {
// Submit form or hide keyboard
FocusScope.of(context).unfocus();
},
)
The textInputAction property enhances form navigation in Flutter TextField widget implementations. Users can quickly move between fields or submit forms using keyboard actions, creating a smoother user experience.
The onChanged callback in Flutter TextField widget executes whenever users modify the text content. This real-time callback enables input validation, search functionality, and dynamic UI updates.
class SearchField extends StatefulWidget {
@override
_SearchFieldState createState() => _SearchFieldState();
}
class _SearchFieldState extends State<SearchField> {
String _searchText = '';
List<String> _filteredResults = [];
@override
Widget build(BuildContext context) {
return TextField(
onChanged: (value) {
setState(() {
_searchText = value;
_filteredResults = performSearch(value);
});
},
decoration: InputDecoration(
labelText: 'Search',
prefixIcon: Icon(Icons.search),
),
);
}
List<String> performSearch(String query) {
// Implement search logic
return [];
}
}
The onChanged callback makes your Flutter TextField widget reactive and interactive. You can implement real-time search, input validation, or dynamic content filtering based on user input.
The onSubmitted callback in Flutter TextField widget triggers when users submit their input by pressing the action button on the keyboard. This callback is essential for form submission and navigation control.
TextField(
onSubmitted: (value) {
if (value.isNotEmpty) {
// Process the submitted value
processUserInput(value);
}
},
decoration: InputDecoration(
labelText: 'Enter command',
suffixIcon: Icon(Icons.send),
),
)
The onSubmitted callback provides a clear user interaction point in your Flutter TextField widget. Users understand that pressing the keyboard action button will process their input.
Input formatters in Flutter TextField widget control and modify user input in real-time. These formatters ensure data consistency and prevent invalid input patterns.
import 'package:flutter/services.dart';
TextField(
inputFormatters: [
FilteringTextInputFormatter.digitsOnly,
LengthLimitingTextInputFormatter(10),
],
keyboardType: TextInputType.number,
decoration: InputDecoration(
labelText: 'Phone Number',
prefixText: '+1 ',
),
)
// Custom formatter for currency
class CurrencyInputFormatter extends TextInputFormatter {
@override
TextEditingValue formatEditUpdate(
TextEditingValue oldValue,
TextEditingValue newValue,
) {
String formatted = '\$${newValue.text}';
return TextEditingValue(
text: formatted,
selection: TextSelection.collapsed(offset: formatted.length),
);
}
}
Input formatters enhance your Flutter TextField widget by ensuring data quality and consistency. You can use built-in formatters or create custom ones for specific input requirements.
Focus management in Flutter TextField widget controls which field receives keyboard input and how users navigate between multiple input fields. Proper focus handling improves form usability significantly.
class FocusDemo extends StatefulWidget {
@override
_FocusDemoState createState() => _FocusDemoState();
}
class _FocusDemoState extends State<FocusDemo> {
final FocusNode _firstFieldFocus = FocusNode();
final FocusNode _secondFieldFocus = FocusNode();
@override
Widget build(BuildContext context) {
return Column(
children: [
TextField(
focusNode: _firstFieldFocus,
textInputAction: TextInputAction.next,
onSubmitted: (value) {
_secondFieldFocus.requestFocus();
},
decoration: InputDecoration(labelText: 'First Field'),
),
TextField(
focusNode: _secondFieldFocus,
textInputAction: TextInputAction.done,
decoration: InputDecoration(labelText: 'Second Field'),
),
],
);
}
@override
void dispose() {
_firstFieldFocus.dispose();
_secondFieldFocus.dispose();
super.dispose();
}
}
Focus management transforms your Flutter TextField widget forms into professional, user-friendly interfaces. Users can navigate smoothly between fields using keyboard actions.
Here’s a comprehensive example demonstrating multiple Flutter TextField widget properties and customizations in a registration form:
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter TextField Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: RegistrationForm(),
);
}
}
class RegistrationForm extends StatefulWidget {
@override
_RegistrationFormState createState() => _RegistrationFormState();
}
class _RegistrationFormState extends State<RegistrationForm> {
final _formKey = GlobalKey<FormState>();
final TextEditingController _nameController = TextEditingController();
final TextEditingController _emailController = TextEditingController();
final TextEditingController _phoneController = TextEditingController();
final TextEditingController _passwordController = TextEditingController();
final TextEditingController _bioController = TextEditingController();
final FocusNode _nameFocus = FocusNode();
final FocusNode _emailFocus = FocusNode();
final FocusNode _phoneFocus = FocusNode();
final FocusNode _passwordFocus = FocusNode();
final FocusNode _bioFocus = FocusNode();
bool _obscurePassword = true;
String _searchText = '';
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Flutter TextField Widget Demo'),
backgroundColor: Colors.blue[600],
),
body: Padding(
padding: const EdgeInsets.all(16.0),
child: Form(
key: _formKey,
child: SingleChildScrollView(
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
// Name TextField with basic decoration
TextField(
controller: _nameController,
focusNode: _nameFocus,
textInputAction: TextInputAction.next,
keyboardType: TextInputType.text,
onSubmitted: (value) {
_emailFocus.requestFocus();
},
decoration: InputDecoration(
labelText: 'Full Name',
hintText: 'Enter your full name',
prefixIcon: Icon(Icons.person),
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(10),
),
filled: true,
fillColor: Colors.grey[100],
),
),
SizedBox(height: 16),
// Email TextField with email keyboard
TextField(
controller: _emailController,
focusNode: _emailFocus,
textInputAction: TextInputAction.next,
keyboardType: TextInputType.emailAddress,
onSubmitted: (value) {
_phoneFocus.requestFocus();
},
decoration: InputDecoration(
labelText: 'Email Address',
hintText: 'your.email@example.com',
prefixIcon: Icon(Icons.email),
suffixIcon: Icon(Icons.alternate_email),
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(10),
),
filled: true,
fillColor: Colors.blue[50],
),
),
SizedBox(height: 16),
// Phone TextField with number keyboard and formatter
TextField(
controller: _phoneController,
focusNode: _phoneFocus,
textInputAction: TextInputAction.next,
keyboardType: TextInputType.phone,
inputFormatters: [
FilteringTextInputFormatter.digitsOnly,
LengthLimitingTextInputFormatter(10),
],
onSubmitted: (value) {
_passwordFocus.requestFocus();
},
decoration: InputDecoration(
labelText: 'Phone Number',
hintText: '1234567890',
prefixIcon: Icon(Icons.phone),
prefixText: '+1 ',
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(10),
),
filled: true,
fillColor: Colors.green[50],
),
),
SizedBox(height: 16),
// Password TextField with obscure text and toggle
TextField(
controller: _passwordController,
focusNode: _passwordFocus,
textInputAction: TextInputAction.next,
obscureText: _obscurePassword,
onSubmitted: (value) {
_bioFocus.requestFocus();
},
decoration: InputDecoration(
labelText: 'Password',
hintText: 'Enter secure password',
prefixIcon: Icon(Icons.lock),
suffixIcon: IconButton(
icon: Icon(_obscurePassword
? Icons.visibility
: Icons.visibility_off),
onPressed: () {
setState(() {
_obscurePassword = !_obscurePassword;
});
},
),
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(10),
),
filled: true,
fillColor: Colors.red[50],
),
),
SizedBox(height: 16),
// Multi-line bio TextField
TextField(
controller: _bioController,
focusNode: _bioFocus,
textInputAction: TextInputAction.newline,
keyboardType: TextInputType.multiline,
maxLines: 4,
maxLength: 200,
decoration: InputDecoration(
labelText: 'Bio',
hintText: 'Tell us about yourself...',
prefixIcon: Icon(Icons.description),
alignLabelWithHint: true,
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(10),
),
filled: true,
fillColor: Colors.purple[50],
),
),
SizedBox(height: 16),
// Search TextField with onChanged
TextField(
onChanged: (value) {
setState(() {
_searchText = value;
});
},
decoration: InputDecoration(
labelText: 'Search',
hintText: 'Search for something...',
prefixIcon: Icon(Icons.search),
suffixIcon: _searchText.isNotEmpty
? IconButton(
icon: Icon(Icons.clear),
onPressed: () {
setState(() {
_searchText = '';
});
},
)
: null,
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(10),
),
filled: true,
fillColor: Colors.orange[50],
),
),
SizedBox(height: 20),
if (_searchText.isNotEmpty)
Container(
padding: EdgeInsets.all(12),
decoration: BoxDecoration(
color: Colors.grey[200],
borderRadius: BorderRadius.circular(8),
),
child: Text(
'Searching for: $_searchText',
style: TextStyle(
fontSize: 16,
fontStyle: FontStyle.italic,
),
),
),
SizedBox(height: 32),
// Submit button
ElevatedButton(
onPressed: () {
_submitForm();
},
style: ElevatedButton.styleFrom(
backgroundColor: Colors.blue[600],
padding: EdgeInsets.symmetric(vertical: 16),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(10),
),
),
child: Text(
'Register',
style: TextStyle(
fontSize: 18,
fontWeight: FontWeight.bold,
color: Colors.white,
),
),
),
],
),
),
),
),
);
}
void _submitForm() {
String name = _nameController.text;
String email = _emailController.text;
String phone = _phoneController.text;
String password = _passwordController.text;
String bio = _bioController.text;
if (name.isNotEmpty && email.isNotEmpty && password.isNotEmpty) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text('Registration submitted successfully!'),
backgroundColor: Colors.green,
),
);
// Clear all fields
_nameController.clear();
_emailController.clear();
_phoneController.clear();
_passwordController.clear();
_bioController.clear();
// Hide keyboard
FocusScope.of(context).unfocus();
} else {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text('Please fill in all required fields'),
backgroundColor: Colors.red,
),
);
}
}
@override
void dispose() {
_nameController.dispose();
_emailController.dispose();
_phoneController.dispose();
_passwordController.dispose();
_bioController.dispose();
_nameFocus.dispose();
_emailFocus.dispose();
_phoneFocus.dispose();
_passwordFocus.dispose();
_bioFocus.dispose();
super.dispose();
}
}
This comprehensive Flutter TextField widget example demonstrates practical implementation of multiple properties and features. The registration form showcases different keyboard types, input formatters, focus management, decoration options, and event handling. Each TextField widget serves a specific purpose while maintaining consistent styling and user experience.
The example includes proper resource management by disposing controllers and focus nodes, preventing memory leaks in your Flutter application. You can customize this Flutter TextField widget implementation further by adding validation, custom themes, or integration with state management solutions like Provider or Bloc.