Handling Different Text Input Types in TextField in Flutter

Flutter’s TextField widget is a versatile tool for accepting user input. However, the types of input users can enter vary widely—from simple text and numbers to emails, passwords, and more. Properly handling different text input types enhances user experience, ensures data integrity, and optimizes keyboard layouts. This article explores how to effectively manage different text input types using Flutter’s TextField widget.

Understanding the TextField Widget

The TextField widget in Flutter is used to capture text input from the user. It provides several properties to configure the input method, styling, and validation. A key property for handling different input types is keyboardType.

Why Handle Different Text Input Types?

  • Improved User Experience: Tailored keyboard layouts for specific input types make data entry faster and more accurate.
  • Data Validation: Enforcing specific input types ensures data conforms to expected formats.
  • Accessibility: Correct input types aid assistive technologies in understanding and processing user input.

Setting the keyboardType Property

The keyboardType property in TextField is of type TextInputType. Here’s how to use it for different input types:

1. Basic Text Input

For general text input, use TextInputType.text. This displays a standard keyboard layout.


TextField(
  keyboardType: TextInputType.text,
  decoration: InputDecoration(
    labelText: 'Enter text',
  ),
)

2. Numeric Input

To display a numeric keypad, use TextInputType.number. This is ideal for accepting numerical data like ages, quantities, or IDs.


TextField(
  keyboardType: TextInputType.number,
  decoration: InputDecoration(
    labelText: 'Enter number',
  ),
)

3. Decimal Input

For input that requires decimal numbers, use TextInputType.numberWithOptions(decimal: true). This provides a numeric keypad with a decimal point.


TextField(
  keyboardType: const TextInputType.numberWithOptions(decimal: true),
  decoration: InputDecoration(
    labelText: 'Enter decimal number',
  ),
)

4. Phone Number Input

Use TextInputType.phone for accepting phone numbers. This displays a numeric keypad optimized for phone number entry, often including symbols like * and #.


TextField(
  keyboardType: TextInputType.phone,
  decoration: InputDecoration(
    labelText: 'Enter phone number',
  ),
)

5. Email Address Input

For email addresses, use TextInputType.emailAddress. This presents a standard keyboard layout but typically suggests email addresses from the user’s device.


TextField(
  keyboardType: TextInputType.emailAddress,
  decoration: InputDecoration(
    labelText: 'Enter email address',
  ),
)

6. Date and Time Input

For entering dates and times, consider using a combination of showDatePicker or showTimePicker with text input fields. While there isn’t a specific TextInputType for dates and times, you can use TextInputType.datetime to assist with formatting and validation after input.


import 'package:flutter/material.dart';

class DateTimeInput extends StatefulWidget {
  @override
  _DateTimeInputState createState() => _DateTimeInputState();
}

class _DateTimeInputState extends State {
  TextEditingController dateController = TextEditingController();
  TextEditingController timeController = TextEditingController();

  Future _selectDate(BuildContext context) async {
    final DateTime? picked = await showDatePicker(
      context: context,
      initialDate: DateTime.now(),
      firstDate: DateTime(2000),
      lastDate: DateTime(2025),
    );
    if (picked != null) {
      setState(() {
        dateController.text = "${picked.toLocal()}".split(' ')[0];
      });
    }
  }

  Future _selectTime(BuildContext context) async {
    final TimeOfDay? picked = await showTimePicker(
      context: context,
      initialTime: TimeOfDay.now(),
    );
    if (picked != null) {
      setState(() {
        timeController.text = picked.format(context);
      });
    }
  }

  @override
  Widget build(BuildContext context) {
    return Column(
      children: [
        TextField(
          controller: dateController,
          keyboardType: TextInputType.datetime,
          decoration: InputDecoration(
            labelText: 'Select Date',
            suffixIcon: IconButton(
              icon: Icon(Icons.calendar_today),
              onPressed: () => _selectDate(context),
            ),
          ),
          readOnly: true,
          onTap: () => _selectDate(context),
        ),
        TextField(
          controller: timeController,
          keyboardType: TextInputType.datetime,
          decoration: InputDecoration(
            labelText: 'Select Time',
            suffixIcon: IconButton(
              icon: Icon(Icons.access_time),
              onPressed: () => _selectTime(context),
            ),
          ),
          readOnly: true,
          onTap: () => _selectTime(context),
        ),
      ],
    );
  }
}

7. URL Input

For URLs, use TextInputType.url. This configures the keyboard for easy URL entry and might suggest previously entered URLs.


TextField(
  keyboardType: TextInputType.url,
  decoration: InputDecoration(
    labelText: 'Enter URL',
  ),
)

Masking and Formatting Text Input

For more complex formatting requirements, such as phone numbers or currency values, consider using input formatters.

Using Input Formatters

Input formatters allow you to transform user input as it’s being typed. You can create custom formatters or use existing ones from packages like flutter_masked_text2 or mask_text_input_formatter.

Here’s an example of using an input formatter for phone number masking:


import 'package:flutter/material.dart';
import 'package:mask_text_input_formatter/mask_text_input_formatter.dart';

class PhoneNumberInput extends StatelessWidget {
  final maskFormatter = MaskTextInputFormatter(
      mask: '+# (###) ###-##-##',
      filter: { "#": RegExp(r'[0-9]') },
      type: MaskAutoCompletionType.lazy
  );

  @override
  Widget build(BuildContext context) {
    return Padding(
      padding: const EdgeInsets.all(16.0),
      child: TextField(
        keyboardType: TextInputType.phone,
        inputFormatters: [maskFormatter],
        decoration: InputDecoration(
          labelText: 'Phone Number',
          hintText: '+1 (555) 555-5555',
          border: OutlineInputBorder(),
        ),
      ),
    );
  }
}

Password Input

For password fields, set obscureText: true to hide the entered text. Combine this with TextInputType.visiblePassword or TextInputType.text for the keyboard.


TextField(
  keyboardType: TextInputType.visiblePassword,
  obscureText: true,
  decoration: InputDecoration(
    labelText: 'Enter password',
  ),
)

Custom Keyboard Layouts

In some advanced cases, you may need a completely custom keyboard layout. While Flutter doesn’t natively support custom keyboard layouts in TextField, you can build one using a combination of custom widgets and overlaying them on the screen.

Validation

Validating input ensures data integrity. You can use the validator property in TextField to define validation rules.


TextFormField(
  keyboardType: TextInputType.emailAddress,
  decoration: InputDecoration(
    labelText: 'Email',
  ),
  validator: (value) {
    if (value == null || value.isEmpty) {
      return 'Please enter your email';
    }
    if (!value.contains('@')) {
      return 'Please enter a valid email';
    }
    return null;
  },
)

Conclusion

Handling different text input types in Flutter’s TextField enhances the user experience, ensures data integrity, and improves accessibility. By using the appropriate keyboardType and combining it with input formatters and validation, you can effectively manage various input scenarios and build robust, user-friendly applications.