import 'package:flutter/material.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Form Demo',
theme: ThemeData(
colorScheme: ColorScheme.fromSeed(seedColor: Colors.blue),
useMaterial3: true,
),
home: const FormDemoScreen(),
);
}
}
class FormDemoScreen extends StatefulWidget {
const FormDemoScreen({super.key});
@override
State<FormDemoScreen> createState() => _FormDemoState();
}
class _FormDemoState extends State<FormDemoScreen> {
final _formKey = GlobalKey<FormState>();
final _nameController = TextEditingController();
final _emailController = TextEditingController();
final ValueKey<String> _key = const ValueKey("value");
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text('Form Demo')),
body: Form(
key: _formKey,
child: Padding(
padding: const EdgeInsets.all(16.0),
child: Column(
children: [
Text('Hello: ${_nameController.text}'),
// Text fields (already FormField widgets)
TextFormField(
controller: _emailController,
decoration: const InputDecoration(labelText: 'Email'),
validator: (value) =>
value?.isEmpty ?? true ? 'Required' : null,
),
TextFormField(
key: _key,
controller: _nameController,
decoration: const InputDecoration(labelText: 'Name'),
onChanged: (String value) {
setState(() {});
},
validator: (value) =>
value?.isEmpty ?? true ? 'Required' : null,
),
// Radio buttons wrapped in FormField
FormField<String>(
initialValue: null,
builder: (FormFieldState<String> state) {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const Text('Gender:'),
RadioListTile<String>(
title: const Text('Male'),
value: 'male',
groupValue: state.value,
onChanged: state.didChange,
),
RadioListTile<String>(
title: const Text('Female'),
value: 'female',
groupValue: state.value,
onChanged: state.didChange,
),
RadioListTile<String>(
title: const Text('Other'),
value: 'other',
groupValue: state.value,
onChanged: state.didChange,
),
],
);
},
),
// Checkboxes wrapped in FormField
FormField<bool>(
initialValue: false,
builder: (FormFieldState<bool> state) {
return CheckboxListTile(
title: const Text('Subscribe to Newsletter'),
value: state.value ?? false,
onChanged: state.didChange,
);
},
),
FormField<bool>(
initialValue: false,
builder: (FormFieldState<bool> state) {
return CheckboxListTile(
title: const Text('Agree to Terms & Conditions'),
value: state.value ?? false,
onChanged: state.didChange,
);
},
),
const SizedBox(height: 20),
ElevatedButton(
onPressed: () {
_formKey.currentState?.reset();
},
child: const Text('Reset Form'),
),
],
),
),
),
);
}
}
Steps to reproduce
Expected results
That TextFormField should revert to the initial empty value.
Actual results
TextFormField stays at the value before setState is called.
Code sample
Minimal repro...
Detailed sample
Screenshots or Video
Screenshots / Video demonstration
[Upload media here]
Logs
Logs
[Paste your logs here]Flutter Doctor output
Doctor output