I am trying to create a TextFormField
with a label that can wrap to multiple lines if the text is long. However, I want to keep the floating label behavior, which is the default behavior where the label moves above the field when the user focuses on it.
- The label to wrap when the text is long.
- The floating label behavior, where the label floats above the input field when the user starts typing.
TextFormField(
decoration: InputDecoration(
labelText: label,
labelStyle: TextStyle(
color: Colors.grey.shade700,
fontSize: 16,
),
floatingLabelBehavior: FloatingLabelBehavior.auto,
contentPadding: const EdgeInsets.symmetric(horizontal: 12, vertical: 16),
I attempted using a Column to separate the label and the TextFormField
, but that also didn’t give me the floating label effect.
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
// Label text
Padding(
padding: const EdgeInsets.symmetric(horizontal: 12),
child: Text(
label,
style: TextStyle(
color: Colors.grey.shade700,
fontSize: 16,
),
maxLines: null, // Allow label text to wrap if needed
overflow: TextOverflow.visible,
),
),
// Input field
TextFormField(
controller: controller,
keyboardType: TextInputType.number,
style: const TextStyle(
color: Colors.black,
fontSize: 15,
),
minLines: 1,
maxLines: null,
floatingLabelBehavior: FloatingLabelBehavior.auto,
contentPadding: const EdgeInsets.symmetric(horizontal: 12, vertical: 16),
This only make the label wrap but it does not make it float to the top, and the text input wraps using minLine and maxLine which I don't need.
Basically, I can make the label float and not wrap and I can make it wrap but not float.
I want it to wrap and float.
I am trying to create a TextFormField
with a label that can wrap to multiple lines if the text is long. However, I want to keep the floating label behavior, which is the default behavior where the label moves above the field when the user focuses on it.
- The label to wrap when the text is long.
- The floating label behavior, where the label floats above the input field when the user starts typing.
TextFormField(
decoration: InputDecoration(
labelText: label,
labelStyle: TextStyle(
color: Colors.grey.shade700,
fontSize: 16,
),
floatingLabelBehavior: FloatingLabelBehavior.auto,
contentPadding: const EdgeInsets.symmetric(horizontal: 12, vertical: 16),
I attempted using a Column to separate the label and the TextFormField
, but that also didn’t give me the floating label effect.
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
// Label text
Padding(
padding: const EdgeInsets.symmetric(horizontal: 12),
child: Text(
label,
style: TextStyle(
color: Colors.grey.shade700,
fontSize: 16,
),
maxLines: null, // Allow label text to wrap if needed
overflow: TextOverflow.visible,
),
),
// Input field
TextFormField(
controller: controller,
keyboardType: TextInputType.number,
style: const TextStyle(
color: Colors.black,
fontSize: 15,
),
minLines: 1,
maxLines: null,
floatingLabelBehavior: FloatingLabelBehavior.auto,
contentPadding: const EdgeInsets.symmetric(horizontal: 12, vertical: 16),
This only make the label wrap but it does not make it float to the top, and the text input wraps using minLine and maxLine which I don't need.
Basically, I can make the label float and not wrap and I can make it wrap but not float.
I want it to wrap and float.
Share Improve this question asked Mar 11 at 11:42 disaldisal 111 silver badge2 bronze badges2 Answers
Reset to default 1To create a TextFormField
with a label that can wrap to multiple lines if the text is long You can build a custom border
=> Demo Video of the provided solution: CustomLable_with_UnderlineInputBorder
Step 1: Define the FocusNode
and isFocused
Declare a FocusNode
and a isFocused
to track the focus state, then initialize it in the initState
late final FocusNode _focusNode;
bool isFocused = false;
@override
void initState() {
_focusNode = FocusNode();
_focusNode.addListener(
() {
setState(
() {
isFocused = _focusNode.hasFocus;
log("Is Field Focued : $isFocused");
},
);
},
);
super.initState();
}
Step 2: Define the Label you want
String label = "This very very very very very long lable to test the custom label widget";
Step 3: Create the TextFormField
with a Custom Border
Scaffold(
resizeToAvoidBottomInset: false,
appBar: AppBar(
title: const Text("Custom Lable"),
centerTitle: true,
automaticallyImplyLeading: false,
backgroundColor: Colors.green,
),
body: Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
Container(
margin: const EdgeInsets.symmetric(horizontal: 10.0),
decoration: BoxDecoration(
border: Border(
bottom: isFocused
? const BorderSide(color: Colors.blue, width: 2.0)
: const BorderSide(color: Colors.black),
),
),
child: TextFormField(
focusNode: _focusNode,
onTapOutside: (event) {
FocusScope.of(context).unfocus();
},
decoration: InputDecoration(
border: InputBorder.none,
label: Text(label),
focusedBorder: const OutlineInputBorder(
borderSide: BorderSide(
color: Colors.transparent,
width: 0.0,
),
),
),
),
)
],
),
);
As You can see :
You can use the
border: Border( bottom: isFocused ? const BorderSide(color: Colors.blue, width: 2.0) : const BorderSide(color: Colors.black), ),
As the
UnderlineInputBorder
and control its decoration usingisFocus
bool
To implement this mechanism the border must be
OutlineInputBorder
To remove the
TextField
border and use theContainer
border useborder: InputBorder.none,
Make sure to give the
OutlineInputBorder
:-
borderSide: BorderSide( color: Colors.transparent, width: 0.0, ),
To display a label above a TextFormField
when it is focused, you can use the Focus
widget along with a bool
isFocused
to manage the focus state
=> Demo Video of the Provided Solution: CustomLable
Step 3: Build the TextField
Widget
Scaffold(
resizeToAvoidBottomInset: false,
appBar: AppBar(
title: const Text("Custom Lable"),
centerTitle: true,
automaticallyImplyLeading: false,
backgroundColor: Colors.green,
),
body: Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
if (isFocused) ...{
Row(
children: <Widget>[
Expanded(
child: Padding(
padding: const EdgeInsets.all(8.0),
child: Text(
label,
style: TextStyle(
color: Colors.grey.shade700,
fontSize: 16,
),
),
),
),
],
),
},
Padding(
padding: const EdgeInsets.symmetric(horizontal: 10),
child: TextFormField(
focusNode: _focusNode,
onTapOutside: (event) {
// Use this to unFocus the Field when user Tap any where
FocusScope.of(context).unfocus();
},
decoration: InputDecoration(
enabledBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(20),
borderSide: const BorderSide(color: Colors.grey),
),
focusedBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(20),
borderSide: const BorderSide(color: Colors.green),
),
fillColor: Colors.grey.shade100,
filled: true,
label: isFocused
? null
: Text(
label,
style: TextStyle(
color: Colors.grey.shade700,
fontSize: 16,
),
),
),
),
),
],
),
);
As you can see:
The label is null when the
isFocued
istrue
And the label will positioned above the
TextField
when theisFocus
true
Use label
instead of labelText
. Because label
accepts the widget.
This is the output for the below code
TextFormField(
decoration: InputDecoration(
label: Text(
"This is a long label that should wrap and float above the input field",
softWrap: true, // Allow the text to wrap
style: TextStyle(color: Colors.grey.shade700, fontSize: 16),
),
floatingLabelBehavior:
FloatingLabelBehavior.auto, // Enable floating label
contentPadding: const EdgeInsets.symmetric(
horizontal: 12,
vertical: 16,
),
border: OutlineInputBorder(borderRadius: BorderRadius.circular(8)),
),
),
);