Repository: flutter-form-builder-ecosystem/flutter_form_builder

Issue:
FormBuilderDate[Time|Range]Picker: Web/Accessibility: Comply with WCAG 2.1 A-level criterion "On Focus"
### Is there an existing issue for this?

- [X] I have searched the existing issues

### Package/Plugin version

9.1.1

### What you'd like to happen

Date pickers should not open automatically when the field receives tab focus. On Web, the current behavior (opens automatically when field receives tab focus) presents a couple of accessibility/usability issues (see Additional Information).

Instead, the user should be able to focus the field and separately trigger the prompt by interacting with it (say, by pressing space or enter?).

It is quite possible that this is happening with other FormBuilder widgets too, but I am unable to test them myself at this time.

### Additional information

When tabbing through the fields of the Flutter web app I am testing, the FormBuilderDateTimePicker and FormBuilderDateRangePicker widgets initiate a change of context when they receives focus (the picker dialog constitutes a change of context).

This fails [WCAG success criterion 3.2.1](https://www.w3.org/TR/UNDERSTANDING-WCAG20/consistent-behavior-receive-focus.html) stating that "any component [which may also be called a 'user interface element'] that is able to trigger an event when it receives focus must not change the context." 

The following is given as an example of failing this criterion:

> When a field receives focus, a help dialog window describing the field and providing options opens. As a keyboard user tabs through the Web page, the dialog opens, moving the keyboard focus away from the control every time the user attempts to tab past the field.

I believe that this is analogous to the datetime/daterange picker's behavior, as you cannot tab past the field without triggering the popup. Compounding this problem is the fact that regardless of whether one selects a datetime/range and hits OK or cancels the dialog using the cancel button/Escape key, the focus is set back to the first element on the page--so you can't tab past it at all. It's a wall that prevents keyboard-only users from accessing all of the fields on the form.

This is an "A"-level success criterion of the WCAG 2.0/2.1 accessibility standard, meaning it's one of the most critical aspects of accessible web content.

### Documentation error?
The documentation says that the FormBuilderDateTimePicker class has a "[format](https://pub.dev/documentation/flutter_form_builder/latest/flutter_form_builder/FormBuilderDateTimePicker/format.html)" property, but its description seems to be related to a property, "editable", that no longer exists (or never existed and was copied/pasted from other documentation). Coincidentally, the description implies an ability to NOT open the picker automatically when the field is focused, which I believe should be implemented!

[General]: Focus behaviour navigating using tab on conditional fields
### Is there an existing issue for this?

- [X] I have searched the existing issues

### Package/Plugin version

9.1.0

### Platforms

- [ ] Android
- [X] iOS
- [ ] Linux
- [X] MacOS
- [ ] Web
- [X] Windows

### Flutter doctor

<details>
  <summary>Flutter doctor</summary>

<!-- Paste the output below inside ``` and ``` -->
```bash
[✓] Flutter (Channel stable, 3.13.1, on macOS 13.4.1 22F770820d darwin-arm64, locale de-DE)
[✓] Android toolchain - develop for Android devices (Android SDK version 34.0.0)
[✓] Xcode - develop for iOS and macOS (Xcode 14.3.1)
[✓] Chrome - develop for the web
[✓] Android Studio (version 2022.2)
[✓] VS Code (version 1.81.1)
[✓] Connected device (2 available)
[✓] Network resources

• No issues found!
```

</details>


### Minimal code example

<details>
  <summary>Code sample</summary>

<!-- Paste the output below inside ``` and ``` -->

```dart

```

</details>


### Current Behavior

When conditional rendering a FormField it messes up Somehow the order of the `tab` navigation. See video and forked repo.

Age2 should focus to Age3 but Appointment Time gets focused instead 

### Expected Behavior

The correct widget should be focused when navigating with `tab`

### Steps To Reproduce

1. Get forked [repo](https://github.com/marcosgcd/flutter_form_builder.git)
2. See Video for detailed reproduction

### Aditional information


https://github.com/flutter-form-builder-ecosystem/flutter_form_builder/assets/137309939/3cce4341-1d2d-4123-b50f-015ec13eee2e


[General] FocusNode not passed to FormBuilderCheckbox, FormBuilderRadioGroup
### Is there an existing issue for this?

- [X] I have searched the existing issues

### Package/Plugin version

9.1.0

### Platforms

- [X] Android
- [X] iOS
- [ ] Linux
- [ ] MacOS
- [X] Web
- [ ] Windows

### Flutter doctor

<details>
  <summary>Flutter doctor</summary>

<!-- Paste the output below inside ``` and ``` -->
```bash

```

</details>


### Minimal code example

<details>
  <summary>Code sample</summary>

<!-- Paste the output below inside ``` and ``` -->

```dart
// The focusNode parameter is present in the constructor

  FormBuilderCheckbox({
  // ...
  required this.title,
  this.focusNode, 
  // ...
: super(
          builder: (FormFieldState<bool?> field) {
            final state = field as _FormBuilderCheckboxState;
           return InputDecorator(
              decoration: state.decoration,
              child: CheckboxListTile(
              .... //observe focusNode is not passed here
              ),
            );
})
```

</details>


### Current Behavior

I found a bug in the FormBuilderCheckbox, FormBuilderRadioGroup classes where the focusNode is not being passed correctly. When using this widget, it should accept a focusNode parameter and pass it to the underlying CheckboxListTile. However, the focusNode parameter not being passed to CheckboxListTile, GroupedRadio. Hence the respective widgets are not getting focused.

### Expected Behavior

The FormBuilderCheckbox , FormBuilderRadioGroup widgets should accept and correctly pass a focusNode parameter to the CheckboxListTile, this will lead to proper working of the focus in above mentioned widgets.

### Steps To Reproduce

Steps to Reproduce:

1.Create a FormBuilderCheckbox or FormBuilderRadioGroup widget.
2.Set a focusNode for the widget.
3.Observe that the focusNode is not being applied to the Checkbox or RadioButton

### Aditional information

_No response_
[FormBuilderTextField]: Clicking on another form should close the opened keyboard if it is not needed
### Is there an existing issue for this?

- [X] I have searched the existing issues

### Package/Plugin version

9.1.0

### What you'd like to happen

```Markdown
The keyboard from editing a TextField should be closed if the user clicks on another form (for example a checkbox) that does not need a keyboard.
```


### Alternatives you've considered

_No response_

### Aditional information

_No response_
FormBuilderDateTimePicker: Picker always showing when field is required and empty
### Is there an existing issue for this?

- [X] I have searched the existing issues

### Package/Plugin version

9.1.1

### Platforms

- [X] Android
- [X] iOS
- [ ] Linux
- [ ] MacOS
- [ ] Web
- [ ] Windows

### Flutter doctor

<details>
  <summary>Flutter doctor</summary>

```bash
[✓] Flutter (Channel stable, 3.13.7, on macOS 14.0 23A344 darwin-arm64, locale es-ES)
    • Flutter version 3.13.7 on channel stable at /Users/miguel/bin/flutter
    • Upstream repository https://github.com/flutter/flutter.git
    • Framework revision 2f708eb839 (4 days ago), 2023-10-09 09:58:08 -0500
    • Engine revision a794cf2681
    • Dart version 3.1.3
    • DevTools version 2.25.0

[✓] Android toolchain - develop for Android devices (Android SDK version 33.0.0)
    • Android SDK at /Users/miguel/Library/Android/sdk
    • Platform android-33, build-tools 33.0.0
    • Java binary at: /Applications/Android Studio.app/Contents/jbr/Contents/Home/bin/java
    • Java version OpenJDK Runtime Environment (build 17.0.6+0-17.0.6b829.9-10027231)
    • All Android licenses accepted.

[✓] Xcode - develop for iOS and macOS (Xcode 15.0)
    • Xcode at /Applications/Xcode.app/Contents/Developer
    • Build 15A240d
    • CocoaPods version 1.13.0

[✓] Chrome - develop for the web
    • Chrome at /Applications/Google Chrome.app/Contents/MacOS/Google Chrome

[✓] Android Studio (version 2022.3)
    • Android Studio at /Applications/Android Studio.app/Contents
    • Flutter plugin can be installed from:
      🔨 https://plugins.jetbrains.com/plugin/9212-flutter
    • Dart plugin can be installed from:
      🔨 https://plugins.jetbrains.com/plugin/6351-dart
    • Java version OpenJDK Runtime Environment (build 17.0.6+0-17.0.6b829.9-10027231)

[✓] VS Code (version 1.83.1)
    • VS Code at /Applications/Visual Studio Code.app/Contents
    • Flutter extension version 3.56.0

[✓] Connected device (3 available)
    • iPhone de Miguel Angel (mobile) • 00008110-000414892152401E • ios            • iOS 17.0.3 21A360
    • macOS (desktop)                 • macos                     • darwin-arm64   • macOS 14.0 23A344 darwin-arm64
    • Chrome (web)                    • chrome                    • web-javascript • Google Chrome 117.0.5938.149
    ! Error: Browsing on the local area network for iPad de Miguel Angel Alvarez Rivero. Ensure the device is unlocked and attached with a cable or associated with the same local area network as this
      Mac.
      The device must be opted into Developer Mode to connect wirelessly. (code -27)

[✓] Network resources
    • All expected network resources are available.

• No issues found!

```

</details>


### Minimal code example

<details>
  <summary>Code</summary>

```dart
FormBuilderDateTimePicker(
      validator: FormBuilderValidators.required(),
      autovalidateMode: AutovalidateMode.onUserInteraction,
      name: 'test',
      inputType: InputType.time,
);
```

</details>

### Current Behavior

When validation is fired and field is empty and required, picker is randomly opened.

### Expected Behavior

Picker dialog should not open when validation is fired and field is invalid.

### Steps To Reproduce

1. Tap on field to display picker dialog
2. Press cancel to close dialog without setting a value
3. Dialog never hides

### Aditional information

_No response_


Discussion: Please join our discussion about keyboard navigation in forms at https://github.com/flutter-form-builder-ecosystem/flutter_form_builder/discussions/1297
Have a look at our demo app linked in the discussion. It showcases exactly your desired behavior. 
+1 - we must use a fork of this widget until this issue has been fixed as it's a significant usability issue for our users.
@Adam-Langley I recently reworked the date_field package [here](https://github.com/GaspardMerten/date_field) which adresses proper keyboard navigation now. Maybe you can get inspired by the implementation
Seams to be a Flutter issue and not FormBuilder. I replaced FormBuilderTextField with TextField and the issue still persists. 


If I only use TextFields and nothing else it works fine. So maybe it is show how related to the FormBuilder widgets?
We are trying to solve similar problems.
Please join our discussion at https://github.com/flutter-form-builder-ecosystem/flutter_form_builder/discussions/1297 regarding this topic.
We are trying to solve similar problems.
Please join our discussion at https://github.com/flutter-form-builder-ecosystem/flutter_form_builder/discussions/1297 regarding this topic.
Hi!
This is a behavior that's happens with native Flutter forms?
Hi im working with @khirsig on improving this library and the user experience.
After looking at the native Flutter form components we can only see two form fields that extend from the FormField<T> class: TextFormField and DropdownButtonFormField. We build a simple demo app and when you switch from the TextFormField to the DropdownButtonFormField the focus switches as well and the keyboard disappears.
So we can assume that this is the desired behavior in the Flutter forms and also as a user we always have the urge to get rid of the keyboard once we start interacting with form components that do not need it.
We think that a good form should offer a consistent look and feel. So entering a text field should show a keyboard and leaving a text field should hide it.
What do you think?

I agree with @grundid (thanks for the comment by the way)
Can confirm. 
For me Resolved by setting focusOnInvalid: false, the default is focusOnInvalid: true
`yourExpiryDateFieldKey.currentState!.validate(focusOnInvalid: false)`
> For me Resolved by setting focusOnInvalid: false, the default is focusOnInvalid: true `yourExpiryDateFieldKey.currentState!.validate(focusOnInvalid: false)`

This doesn't work if the field is inside a form and is validated with the generic form key. The previous version didn't need this setting. 
I also have the same problem, any solution?
> For me Resolved by setting focusOnInvalid: false, the default is focusOnInvalid: true `yourExpiryDateFieldKey.currentState!.validate(focusOnInvalid: false)`

This worked for me :)

Fix patch:
diff --git a/example/lib/minimal_code_example.dart b/example/lib/minimal_code_example.dart
new file mode 100644
index 0000000000..4164b5b986
--- /dev/null
+++ b/example/lib/minimal_code_example.dart
@@ -0,0 +1,95 @@
+import 'package:flutter/material.dart';
+import 'package:flutter_form_builder/flutter_form_builder.dart';
+import 'package:flutter_localizations/flutter_localizations.dart';
+import 'package:form_builder_validators/form_builder_validators.dart';
+
+void main() => runApp(const MyApp());
+
+class MyApp extends StatelessWidget {
+  const MyApp({super.key});
+
+  @override
+  Widget build(BuildContext context) {
+    return MaterialApp(
+      title: 'Flutter FormBuilder Example',
+      debugShowCheckedModeBanner: false,
+      localizationsDelegates: const [
+        FormBuilderLocalizations.delegate,
+        ...GlobalMaterialLocalizations.delegates,
+        GlobalWidgetsLocalizations.delegate,
+      ],
+      supportedLocales: FormBuilderLocalizations.supportedLocales,
+      home: const _ExamplePage(),
+    );
+  }
+}
+
+class _ExamplePage extends StatefulWidget {
+  const _ExamplePage();
+
+  @override
+  State<_ExamplePage> createState() => _ExamplePageState();
+}
+
+class _ExamplePageState extends State<_ExamplePage> {
+  final _formKey = GlobalKey<FormBuilderState>();
+
+  @override
+  Widget build(BuildContext context) {
+    return Scaffold(
+      appBar: AppBar(title: const Text('Minimal code example')),
+      body: Padding(
+        padding: const EdgeInsets.all(16),
+        child: FormBuilder(
+          key: _formKey,
+          child: Column(
+            children: [
+              FormBuilderFilterChip<String>(
+                decoration: const InputDecoration(
+                  labelText: 'The language of my people',
+                  enabled: false,
+                ),
+                name: 'languages_filter',
+                selectedColor: Colors.red,
+                options: const [
+                  FormBuilderChipOption(
+                    value: 'Dart',
+                    avatar: CircleAvatar(child: Text('D')),
+                  ),
+                  FormBuilderChipOption(
+                    value: 'Kotlin',
+                    avatar: CircleAvatar(child: Text('K')),
+                  ),
+                  FormBuilderChipOption(
+                    value: 'Java',
+                    avatar: CircleAvatar(child: Text('J')),
+                  ),
+                  FormBuilderChipOption(
+                    value: 'Swift',
+                    avatar: CircleAvatar(child: Text('S')),
+                  ),
+                  FormBuilderChipOption(
+                    value: 'Objective-C',
+                    avatar: CircleAvatar(child: Text('O')),
+                  ),
+                ],
+                validator: FormBuilderValidators.compose([
+                  FormBuilderValidators.minLength(1),
+                  FormBuilderValidators.maxLength(3),
+                ]),
+              ),
+              const SizedBox(height: 10),
+              ElevatedButton(
+                onPressed: () {
+                  _formKey.currentState?.saveAndValidate();
+                  debugPrint(_formKey.currentState?.value.toString());
+                },
+                child: const Text('Print'),
+              )
+            ],
+          ),
+        ),
+      ),
+    );
+  }
+}
diff --git a/lib/src/fields/form_builder_checkbox.dart b/lib/src/fields/form_builder_checkbox.dart
index 6e1ceca5a2..c3939fb703 100644
--- a/lib/src/fields/form_builder_checkbox.dart
+++ b/lib/src/fields/form_builder_checkbox.dart
@@ -125,9 +125,11 @@ class FormBuilderCheckbox extends FormBuilderFieldDecoration<bool> {
 
             return InputDecorator(
               decoration: state.decoration,
+              isFocused: state.effectiveFocusNode.hasFocus,
               child: CheckboxListTile(
                 dense: true,
                 isThreeLine: false,
+                focusNode: state.effectiveFocusNode,
                 title: title,
                 subtitle: subtitle,
                 value: tristate ? state.value : (state.value ?? false),
@@ -158,4 +160,26 @@ class FormBuilderCheckbox extends FormBuilderFieldDecoration<bool> {
 }
 
 class _FormBuilderCheckboxState
-    extends FormBuilderFieldDecorationState<FormBuilderCheckbox, bool> {}
+    extends FormBuilderFieldDecorationState<FormBuilderCheckbox, bool> {
+  void handleFocusChange() {
+    setState(() {});
+  }
+
+  @override
+  void initState() {
+    super.initState();
+    effectiveFocusNode.addListener(handleFocusChange);
+  }
+
+  @override
+  void dispose() {
+    effectiveFocusNode.removeListener(handleFocusChange);
+    super.dispose();
+  }
+
+  @override
+  void didChange(bool? value) {
+    focus();
+    super.didChange(value);
+  }
+}
diff --git a/lib/src/fields/form_builder_checkbox_group.dart b/lib/src/fields/form_builder_checkbox_group.dart
index f5ee8a687f..95ac918a29 100644
--- a/lib/src/fields/form_builder_checkbox_group.dart
+++ b/lib/src/fields/form_builder_checkbox_group.dart
@@ -69,36 +69,43 @@ class FormBuilderCheckboxGroup<T> extends FormBuilderFieldDecoration<List<T>> {
           builder: (FormFieldState<List<T>?> field) {
             final state = field as _FormBuilderCheckboxGroupState<T>;
 
-            return InputDecorator(
-              decoration: state.decoration,
-              child: GroupedCheckbox<T>(
-                orientation: orientation,
-                value: state.value,
-                options: options,
-                onChanged: (val) {
-                  field.didChange(val);
-                },
-                disabled: state.enabled
-                    ? disabled
-                    : options.map((e) => e.value).toList(),
-                activeColor: activeColor,
-                visualDensity: visualDensity,
-                focusColor: focusColor,
-                checkColor: checkColor,
-                materialTapTargetSize: materialTapTargetSize,
-                hoverColor: hoverColor,
-                tristate: tristate,
-                wrapAlignment: wrapAlignment,
-                wrapCrossAxisAlignment: wrapCrossAxisAlignment,
-                wrapDirection: wrapDirection,
-                wrapRunAlignment: wrapRunAlignment,
-                wrapRunSpacing: wrapRunSpacing,
-                wrapSpacing: wrapSpacing,
-                wrapTextDirection: wrapTextDirection,
-                wrapVerticalDirection: wrapVerticalDirection,
-                separator: separator,
-                controlAffinity: controlAffinity,
-                itemDecoration: itemDecoration,
+            return Focus(
+              focusNode: state.effectiveFocusNode,
+              skipTraversal: true,
+              canRequestFocus: state.enabled,
+              debugLabel: 'FormBuilderCheckboxGroup-$name',
+              child: InputDecorator(
+                decoration: state.decoration,
+                isFocused: state.effectiveFocusNode.hasFocus,
+                child: GroupedCheckbox<T>(
+                  orientation: orientation,
+                  value: state.value,
+                  options: options,
+                  onChanged: (val) {
+                    field.didChange(val);
+                  },
+                  disabled: state.enabled
+                      ? disabled
+                      : options.map((e) => e.value).toList(),
+                  activeColor: activeColor,
+                  visualDensity: visualDensity,
+                  focusColor: focusColor,
+                  checkColor: checkColor,
+                  materialTapTargetSize: materialTapTargetSize,
+                  hoverColor: hoverColor,
+                  tristate: tristate,
+                  wrapAlignment: wrapAlignment,
+                  wrapCrossAxisAlignment: wrapCrossAxisAlignment,
+                  wrapDirection: wrapDirection,
+                  wrapRunAlignment: wrapRunAlignment,
+                  wrapRunSpacing: wrapRunSpacing,
+                  wrapSpacing: wrapSpacing,
+                  wrapTextDirection: wrapTextDirection,
+                  wrapVerticalDirection: wrapVerticalDirection,
+                  separator: separator,
+                  controlAffinity: controlAffinity,
+                  itemDecoration: itemDecoration,
+                ),
               ),
             );
           },
diff --git a/lib/src/fields/form_builder_choice_chips.dart b/lib/src/fields/form_builder_choice_chips.dart
index 14a4851cbe..d0c444a499 100644
--- a/lib/src/fields/form_builder_choice_chips.dart
+++ b/lib/src/fields/form_builder_choice_chips.dart
@@ -395,56 +395,63 @@ class FormBuilderChoiceChip<T> extends FormBuilderFieldDecoration<T> {
   }) : super(builder: (FormFieldState<T?> field) {
           final state = field as _FormBuilderChoiceChipState<T>;
 
-          return InputDecorator(
-            decoration: state.decoration,
-            child: Wrap(
-              direction: direction,
-              alignment: alignment,
-              crossAxisAlignment: crossAxisAlignment,
-              runAlignment: runAlignment,
-              runSpacing: runSpacing,
-              spacing: spacing,
-              textDirection: textDirection,
-              verticalDirection: verticalDirection,
-              children: <Widget>[
-                for (FormBuilderChipOption<T> option in options)
-                  ChoiceChip(
-                    label: option,
-                    side: side,
-                    shape: shape,
-                    selected: field.value == option.value,
-                    onSelected: state.enabled
-                        ? (selected) {
-                            final choice = selected ? option.value : null;
-                            state.didChange(choice);
-                          }
-                        : null,
-                    avatar: option.avatar,
-                    selectedColor: selectedColor,
-                    disabledColor: disabledColor,
-                    backgroundColor: backgroundColor,
-                    shadowColor: shadowColor,
-                    selectedShadowColor: selectedShadowColor,
-                    elevation: elevation,
-                    pressElevation: pressElevation,
-                    materialTapTargetSize: materialTapTargetSize,
-                    labelStyle: labelStyle,
-                    labelPadding: labelPadding,
-                    padding: padding,
-                    visualDensity: visualDensity,
-                    avatarBorder: avatarBorder,
-                    showCheckmark: showCheckmark,
-                    surfaceTintColor: surfaceTintColor,
-                    clipBehavior: clipBehavior,
-                    checkmarkColor: checkmarkColor,
-                    autofocus: autofocus,
-                    avatarBoxConstraints: avatarBoxConstraints,
-                    chipAnimationStyle: chipAnimationStyle,
-                    color: color,
-                    iconTheme: iconTheme,
-                    tooltip: tooltip,
-                  ),
-              ],
+          return Focus(
+            focusNode: state.effectiveFocusNode,
+            skipTraversal: true,
+            canRequestFocus: state.enabled,
+            debugLabel: 'FormBuilderChoiceChip-$name',
+            child: InputDecorator(
+              decoration: state.decoration,
+              isFocused: state.effectiveFocusNode.hasFocus,
+              child: Wrap(
+                direction: direction,
+                alignment: alignment,
+                crossAxisAlignment: crossAxisAlignment,
+                runAlignment: runAlignment,
+                runSpacing: runSpacing,
+                spacing: spacing,
+                textDirection: textDirection,
+                verticalDirection: verticalDirection,
+                children: <Widget>[
+                  for (FormBuilderChipOption<T> option in options)
+                    ChoiceChip(
+                      label: option,
+                      side: side,
+                      shape: shape,
+                      selected: field.value == option.value,
+                      onSelected: state.enabled
+                          ? (selected) {
+                              final choice = selected ? option.value : null;
+                              state.didChange(choice);
+                            }
+                          : null,
+                      avatar: option.avatar,
+                      selectedColor: selectedColor,
+                      disabledColor: disabledColor,
+                      backgroundColor: backgroundColor,
+                      shadowColor: shadowColor,
+                      selectedShadowColor: selectedShadowColor,
+                      elevation: elevation,
+                      pressElevation: pressElevation,
+                      materialTapTargetSize: materialTapTargetSize,
+                      labelStyle: labelStyle,
+                      labelPadding: labelPadding,
+                      padding: padding,
+                      visualDensity: visualDensity,
+                      avatarBorder: avatarBorder,
+                      showCheckmark: showCheckmark,
+                      surfaceTintColor: surfaceTintColor,
+                      clipBehavior: clipBehavior,
+                      checkmarkColor: checkmarkColor,
+                      autofocus: autofocus,
+                      avatarBoxConstraints: avatarBoxConstraints,
+                      chipAnimationStyle: chipAnimationStyle,
+                      color: color,
+                      iconTheme: iconTheme,
+                      tooltip: tooltip,
+                    ),
+                ],
+              ),
             ),
           );
         });
@@ -455,4 +462,27 @@ class FormBuilderChoiceChip<T> extends FormBuilderFieldDecoration<T> {
 }
 
 class _FormBuilderChoiceChipState<T>
-    extends FormBuilderFieldDecorationState<FormBuilderChoiceChip<T>, T> {}
+    extends FormBuilderFieldDecorationState<FormBuilderChoiceChip<T>, T> {
+  void handleFocusChange() {
+    setState(() {});
+  }
+
+  @override
+  void initState() {
+    super.initState();
+    effectiveFocusNode.addListener(handleFocusChange);
+  }
+
+  @override
+  void dispose() {
+    effectiveFocusNode.removeListener(handleFocusChange);
+    super.dispose();
+  }
+
+  @override
+  void didChange(T? value) {
+    focus();
+    // effectiveFocusNode.requestFocus();
+    super.didChange(value);
+  }
+}
diff --git a/lib/src/fields/form_builder_date_range_picker.dart b/lib/src/fields/form_builder_date_range_picker.dart
index 3b71c75e65..5217da3127 100644
--- a/lib/src/fields/form_builder_date_range_picker.dart
+++ b/lib/src/fields/form_builder_date_range_picker.dart
@@ -134,40 +134,44 @@ class FormBuilderDateRangePicker
           builder: (FormFieldState<DateTimeRange?> field) {
             final state = field as _FormBuilderDateRangePickerState;
 
-            return TextField(
-              enabled: state.enabled,
-              style: style,
-              focusNode: state.effectiveFocusNode,
-              decoration: state.decoration,
-              // initialValue: "${_initialValue ?? ''}",
-              maxLines: maxLines,
-              keyboardType: keyboardType,
-              obscureText: obscureText,
-              onEditingComplete: onEditingComplete,
-              controller: state._effectiveController,
-              autocorrect: autocorrect,
-              autofocus: autofocus,
-              buildCounter: buildCounter,
-              mouseCursor: mouseCursor,
-              cursorColor: cursorColor,
-              cursorRadius: cursorRadius,
-              cursorWidth: cursorWidth,
-              enableInteractiveSelection: enableInteractiveSelection,
-              maxLength: maxLength,
-              inputFormatters: inputFormatters,
-              keyboardAppearance: keyboardAppearance,
-              maxLengthEnforcement: maxLengthEnforcement,
-              scrollPadding: scrollPadding,
-              textAlign: textAlign,
-              textCapitalization: textCapitalization,
-              textDirection: textDirection,
-              textInputAction: textInputAction,
-              textAlignVertical: textAlignVertical,
-              strutStyle: strutStyle,
-              readOnly: true,
-              expands: expands,
-              minLines: minLines,
-              showCursor: showCursor,
+            return FocusTraversalGroup(
+              policy: ReadingOrderTraversalPolicy(),
+              child: TextField(
+                onTap: () => state.showPicker(),
+                enabled: state.enabled,
+                style: style,
+                focusNode: state.effectiveFocusNode,
+                decoration: state.decoration,
+                // initialValue: "${_initialValue ?? ''}",
+                maxLines: maxLines,
+                keyboardType: keyboardType,
+                obscureText: obscureText,
+                onEditingComplete: onEditingComplete,
+                controller: state._effectiveController,
+                autocorrect: autocorrect,
+                autofocus: autofocus,
+                buildCounter: buildCounter,
+                mouseCursor: mouseCursor,
+                cursorColor: cursorColor,
+                cursorRadius: cursorRadius,
+                cursorWidth: cursorWidth,
+                enableInteractiveSelection: enableInteractiveSelection,
+                maxLength: maxLength,
+                inputFormatters: inputFormatters,
+                keyboardAppearance: keyboardAppearance,
+                maxLengthEnforcement: maxLengthEnforcement,
+                scrollPadding: scrollPadding,
+                textAlign: textAlign,
+                textCapitalization: textCapitalization,
+                textDirection: textDirection,
+                textInputAction: textInputAction,
+                textAlignVertical: textAlignVertical,
+                strutStyle: strutStyle,
+                readOnly: true,
+                expands: expands,
+                minLines: minLines,
+                showCursor: showCursor,
+              ),
             );
           },
         );
@@ -195,12 +199,21 @@ class _FormBuilderDateRangePickerState extends FormBuilderFieldDecorationState<
     super.initState();
     _effectiveController =
         widget.controller ?? TextEditingController(text: _valueToText());
-    effectiveFocusNode.addListener(_handleFocus);
+
+    effectiveFocusNode.onKeyEvent = (node, event) {
+      if (enabled &&
+          event is KeyDownEvent &&
+          event.logicalKey == LogicalKeyboardKey.space &&
+          node.hasFocus) {
+        showPicker();
+        return KeyEventResult.handled;
+      }
+      return KeyEventResult.ignored;
+    };
   }
 
   @override
   void dispose() {
-    effectiveFocusNode.removeListener(_handleFocus);
     // Dispose the _effectiveController when initState created it
     if (null == widget.controller) {
       _effectiveController.dispose();
@@ -208,42 +221,35 @@ class _FormBuilderDateRangePickerState extends FormBuilderFieldDecorationState<
     super.dispose();
   }
 
-  Future<void> _handleFocus() async {
-    if (effectiveFocusNode.hasFocus && enabled) {
-      effectiveFocusNode.unfocus();
-      /*final initialFirstDate = value?.isEmpty ?? true
-          ? (widget.initialFirstDate ?? DateTime.now())
-          : value[0];
-      final initialLastDate = value?.isEmpty ?? true
-          ? (widget.initialLastDate ?? initialFirstDate)
-          : (value.length < 2 ? initialFirstDate : value[1]);*/
-      final picked = await showDateRangePicker(
-        context: context,
-        firstDate: widget.firstDate,
-        lastDate: widget.lastDate,
-        locale: widget.locale,
-        textDirection: widget.textDirection,
-        cancelText: widget.cancelText,
-        confirmText: widget.confirmText,
-        currentDate: widget.currentDate,
-        errorFormatText: widget.errorFormatText,
-        builder: widget.pickerBuilder,
-        errorInvalidRangeText: widget.errorInvalidRangeText,
-        errorInvalidText: widget.errorInvalidText,
-        fieldEndHintText: widget.fieldEndHintText,
-        fieldEndLabelText: widget.fieldEndLabelText,
-        fieldStartHintText: widget.fieldStartHintText,
-        fieldStartLabelText: widget.fieldStartLabelText,
-        helpText: widget.helpText,
-        initialDateRange: value,
-        initialEntryMode: widget.initialEntryMode,
-        routeSettings: widget.routeSettings,
-        saveText: widget.saveText,
-        useRootNavigator: widget.useRootNavigator,
-      );
-      if (picked != null) {
-        didChange(picked);
-      }
+  Future<void> showPicker() async {
+    effectiveFocusNode.requestFocus();
+
+    final picked = await showDateRangePicker(
+      context: context,
+      firstDate: widget.firstDate,
+      lastDate: widget.lastDate,
+      locale: widget.locale,
+      textDirection: widget.textDirection,
+      cancelText: widget.cancelText,
+      confirmText: widget.confirmText,
+      currentDate: widget.currentDate,
+      errorFormatText: widget.errorFormatText,
+      builder: widget.pickerBuilder,
+      errorInvalidRangeText: widget.errorInvalidRangeText,
+      errorInvalidText: widget.errorInvalidText,
+      fieldEndHintText: widget.fieldEndHintText,
+      fieldEndLabelText: widget.fieldEndLabelText,
+      fieldStartHintText: widget.fieldStartHintText,
+      fieldStartLabelText: widget.fieldStartLabelText,
+      helpText: widget.helpText,
+      initialDateRange: value,
+      initialEntryMode: widget.initialEntryMode,
+      routeSettings: widget.routeSettings,
+      saveText: widget.saveText,
+      useRootNavigator: widget.useRootNavigator,
+    );
+    if (picked != null) {
+      didChange(picked);
     }
   }
 
@@ -277,14 +283,15 @@ class _FormBuilderDateRangePickerState extends FormBuilderFieldDecorationState<
   @override
   InputDecoration get decoration => widget.allowClear
       ? super.decoration.copyWith(
-          suffix: IconButton(
+            suffix: IconButton(
               padding: EdgeInsets.zero,
               constraints: const BoxConstraints(maxWidth: 24, maxHeight: 24),
               onPressed: () {
                 focus();
                 didChange(null);
-                effectiveFocusNode.unfocus();
               },
-              icon: widget.clearIcon ?? const Icon(Icons.clear)))
+              icon: widget.clearIcon ?? const Icon(Icons.clear),
+            ),
+          )
       : super.decoration;
 }
diff --git a/lib/src/fields/form_builder_date_time_picker.dart b/lib/src/fields/form_builder_date_time_picker.dart
index 46c3ba422e..782002229e 100644
--- a/lib/src/fields/form_builder_date_time_picker.dart
+++ b/lib/src/fields/form_builder_date_time_picker.dart
@@ -201,39 +201,43 @@ class FormBuilderDateTimePicker extends FormBuilderFieldDecoration<DateTime> {
           builder: (FormFieldState<DateTime?> field) {
             final state = field as _FormBuilderDateTimePickerState;
 
-            return TextField(
-              textDirection: textDirection,
-              textAlign: textAlign,
-              textAlignVertical: textAlignVertical,
-              maxLength: maxLength,
-              autofocus: autofocus,
-              decoration: state.decoration,
-              readOnly: true,
-              enabled: state.enabled,
-              autocorrect: autocorrect,
-              controller: state._textFieldController,
-              focusNode: state.effectiveFocusNode,
-              inputFormatters: inputFormatters,
-              keyboardType: keyboardType,
-              maxLines: maxLines,
-              obscureText: obscureText,
-              showCursor: showCursor,
-              minLines: minLines,
-              expands: expands,
-              style: style,
-              onEditingComplete: onEditingComplete,
-              buildCounter: buildCounter,
-              mouseCursor: mouseCursor,
-              cursorColor: cursorColor,
-              cursorRadius: cursorRadius,
-              cursorWidth: cursorWidth,
-              enableInteractiveSelection: enableInteractiveSelection,
-              keyboardAppearance: keyboardAppearance,
-              scrollPadding: scrollPadding,
-              strutStyle: strutStyle,
-              textCapitalization: textCapitalization,
-              textInputAction: textInputAction,
-              maxLengthEnforcement: maxLengthEnforcement,
+            return FocusTraversalGroup(
+              policy: ReadingOrderTraversalPolicy(),
+              child: TextField(
+                onTap: () => state.showPicker(),
+                textDirection: textDirection,
+                textAlign: textAlign,
+                textAlignVertical: textAlignVertical,
+                maxLength: maxLength,
+                autofocus: autofocus,
+                decoration: state.decoration,
+                readOnly: true,
+                enabled: state.enabled,
+                autocorrect: autocorrect,
+                controller: state._textFieldController,
+                focusNode: state.effectiveFocusNode,
+                inputFormatters: inputFormatters,
+                keyboardType: keyboardType,
+                maxLines: maxLines,
+                obscureText: obscureText,
+                showCursor: showCursor,
+                minLines: minLines,
+                expands: expands,
+                style: style,
+                onEditingComplete: onEditingComplete,
+                buildCounter: buildCounter,
+                mouseCursor: mouseCursor,
+                cursorColor: cursorColor,
+                cursorRadius: cursorRadius,
+                cursorWidth: cursorWidth,
+                enableInteractiveSelection: enableInteractiveSelection,
+                keyboardAppearance: keyboardAppearance,
+                scrollPadding: scrollPadding,
+                strutStyle: strutStyle,
+                textCapitalization: textCapitalization,
+                textInputAction: textInputAction,
+                maxLengthEnforcement: maxLengthEnforcement,
+              ),
             );
           },
         );
@@ -258,12 +262,20 @@ class _FormBuilderDateTimePickerState extends FormBuilderFieldDecorationState<
     final initVal = value;
     _textFieldController.text =
         initVal == null ? '' : _dateFormat.format(initVal);
-    effectiveFocusNode.addListener(_handleFocus);
+
+    effectiveFocusNode.onKeyEvent = (node, event) {
+      if (event is KeyDownEvent &&
+          event.logicalKey == LogicalKeyboardKey.space &&
+          node.hasFocus) {
+        showPicker();
+        return KeyEventResult.handled;
+      }
+      return KeyEventResult.ignored;
+    };
   }
 
   @override
   void dispose() {
-    effectiveFocusNode.removeListener(_handleFocus);
     // Dispose the _textFieldController when initState created it
     if (null == widget.controller) {
       _textFieldController.dispose();
@@ -271,23 +283,17 @@ class _FormBuilderDateTimePickerState extends FormBuilderFieldDecorationState<
     super.dispose();
   }
 
-  Future<void> _handleFocus() async {
-    if (effectiveFocusNode.hasFocus && enabled) {
-      effectiveFocusNode.unfocus();
-      await onShowPicker(value);
-    }
-  }
-
   DateFormat _getDefaultDateTimeFormat() {
     final languageCode = widget.locale?.languageCode;
-    switch (widget.inputType) {
-      case InputType.time:
-        return DateFormat.Hm(languageCode);
-      case InputType.date:
-        return DateFormat.yMd(languageCode);
-      case InputType.both:
-        return DateFormat.yMd(languageCode).add_Hms();
-    }
+    return switch (widget.inputType) {
+      InputType.time => DateFormat.Hm(languageCode),
+      InputType.date => DateFormat.yMd(languageCode),
+      InputType.both => DateFormat.yMd(languageCode).add_Hms()
+    };
+  }
+
+  Future<void> showPicker() async {
+    await onShowPicker(value);
   }
 
   Future<DateTime?> onShowPicker(DateTime? currentValue) async {
diff --git a/lib/src/fields/form_builder_filter_chips.dart b/lib/src/fields/form_builder_filter_chips.dart
index e30d8aa4b7..058804d69e 100644
--- a/lib/src/fields/form_builder_filter_chips.dart
+++ b/lib/src/fields/form_builder_filter_chips.dart
@@ -81,56 +81,62 @@ class FormBuilderFilterChip<T> extends FormBuilderFieldDecoration<List<T>> {
           builder: (FormFieldState<List<T>?> field) {
             final state = field as _FormBuilderFilterChipState<T>;
             final fieldValue = field.value ?? [];
+            return Focus(
+              focusNode: state.effectiveFocusNode,
+              skipTraversal: true,
+              canRequestFocus: state.enabled,
+              debugLabel: 'FormBuilderFilterChip-$name',
+              child: InputDecorator(
+                decoration: state.decoration,
+                isFocused: state.effectiveFocusNode.hasFocus,
+                child: Wrap(
+                  direction: direction,
+                  alignment: alignment,
+                  crossAxisAlignment: crossAxisAlignment,
+                  runAlignment: runAlignment,
+                  runSpacing: runSpacing,
+                  spacing: spacing,
+                  textDirection: textDirection,
+                  verticalDirection: verticalDirection,
+                  children: <Widget>[
+                    for (FormBuilderChipOption<T> option in options)
+                      FilterChip(
+                        label: option,
+                        selected: fieldValue.contains(option.value),
+                        avatar: option.avatar,
+                        onSelected: state.enabled &&
+                                (null == maxChips ||
+                                    fieldValue.length < maxChips ||
+                                    fieldValue.contains(option.value))
+                            ? (selected) {
+                                final currentValue = [...fieldValue];
+                                selected
+                                    ? currentValue.add(option.value)
+                                    : currentValue.remove(option.value);
 
-            return InputDecorator(
-              decoration: state.decoration,
-              child: Wrap(
-                direction: direction,
-                alignment: alignment,
-                crossAxisAlignment: crossAxisAlignment,
-                runAlignment: runAlignment,
-                runSpacing: runSpacing,
-                spacing: spacing,
-                textDirection: textDirection,
-                verticalDirection: verticalDirection,
-                children: <Widget>[
-                  for (FormBuilderChipOption<T> option in options)
-                    FilterChip(
-                      label: option,
-                      selected: fieldValue.contains(option.value),
-                      avatar: option.avatar,
-                      onSelected: state.enabled &&
-                              (null == maxChips ||
-                                  fieldValue.length < maxChips ||
-                                  fieldValue.contains(option.value))
-                          ? (selected) {
-                              final currentValue = [...fieldValue];
-                              selected
-                                  ? currentValue.add(option.value)
-                                  : currentValue.remove(option.value);
-
-                              field.didChange(currentValue);
-                            }
-                          : null,
-                      selectedColor: selectedColor,
-                      disabledColor: disabledColor,
-                      backgroundColor: backgroundColor,
-                      shadowColor: shadowColor,
-                      selectedShadowColor: selectedShadowColor,
-                      elevation: elevation,
-                      pressElevation: pressElevation,
-                      materialTapTargetSize: materialTapTargetSize,
-                      padding: padding,
-                      side: side,
-                      shape: shape,
-                      checkmarkColor: checkmarkColor,
-                      clipBehavior: clipBehavior,
-                      labelStyle: labelStyle,
-                      showCheckmark: showCheckmark,
-                      labelPadding: labelPadding,
-                      avatarBorder: avatarBorder,
-                    ),
-                ],
+                                field.didChange(currentValue);
+                              }
+                            : null,
+                        selectedColor: selectedColor,
+                        disabledColor: disabledColor,
+                        backgroundColor: backgroundColor,
+                        shadowColor: shadowColor,
+                        selectedShadowColor: selectedShadowColor,
+                        elevation: elevation,
+                        pressElevation: pressElevation,
+                        materialTapTargetSize: materialTapTargetSize,
+                        padding: padding,
+                        side: side,
+                        shape: shape,
+                        checkmarkColor: checkmarkColor,
+                        clipBehavior: clipBehavior,
+                        labelStyle: labelStyle,
+                        showCheckmark: showCheckmark,
+                        labelPadding: labelPadding,
+                        avatarBorder: avatarBorder,
+                      ),
+                  ],
+                ),
               ),
             );
           },
diff --git a/lib/src/fields/form_builder_radio_group.dart b/lib/src/fields/form_builder_radio_group.dart
index 8e08de3e18..94119d8727 100644
--- a/lib/src/fields/form_builder_radio_group.dart
+++ b/lib/src/fields/form_builder_radio_group.dart
@@ -63,33 +63,40 @@ class FormBuilderRadioGroup<T> extends FormBuilderFieldDecoration<T> {
           builder: (FormFieldState<T?> field) {
             final state = field as _FormBuilderRadioGroupState<T>;
 
-            return InputDecorator(
-              decoration: state.decoration,
-              child: GroupedRadio<T>(
-                activeColor: activeColor,
-                controlAffinity: controlAffinity,
-                disabled: state.enabled
-                    ? disabled
-                    : options.map((option) => option.value).toList(),
-                focusColor: focusColor,
-                hoverColor: hoverColor,
-                materialTapTargetSize: materialTapTargetSize,
-                onChanged: (value) {
-                  state.didChange(value);
-                },
-                options: options,
-                orientation: orientation,
-                separator: separator,
-                value: state.value,
-                wrapAlignment: wrapAlignment,
-                wrapCrossAxisAlignment: wrapCrossAxisAlignment,
-                wrapDirection: wrapDirection,
-                wrapRunAlignment: wrapRunAlignment,
-                wrapRunSpacing: wrapRunSpacing,
-                wrapSpacing: wrapSpacing,
-                wrapTextDirection: wrapTextDirection,
-                wrapVerticalDirection: wrapVerticalDirection,
-                itemDecoration: itemDecoration,
+            return Focus(
+              focusNode: state.effectiveFocusNode,
+              skipTraversal: true,
+              canRequestFocus: state.enabled,
+              debugLabel: 'FormBuilderRadioGroup-$name',
+              child: InputDecorator(
+                decoration: state.decoration,
+                isFocused: state.effectiveFocusNode.hasFocus,
+                child: GroupedRadio<T>(
+                  activeColor: activeColor,
+                  controlAffinity: controlAffinity,
+                  disabled: state.enabled
+                      ? disabled
+                      : options.map((option) => option.value).toList(),
+                  focusColor: focusColor,
+                  hoverColor: hoverColor,
+                  materialTapTargetSize: materialTapTargetSize,
+                  onChanged: (value) {
+                    state.didChange(value);
+                  },
+                  options: options,
+                  orientation: orientation,
+                  separator: separator,
+                  value: state.value,
+                  wrapAlignment: wrapAlignment,
+                  wrapCrossAxisAlignment: wrapCrossAxisAlignment,
+                  wrapDirection: wrapDirection,
+                  wrapRunAlignment: wrapRunAlignment,
+                  wrapRunSpacing: wrapRunSpacing,
+                  wrapSpacing: wrapSpacing,
+                  wrapTextDirection: wrapTextDirection,
+                  wrapVerticalDirection: wrapVerticalDirection,
+                  itemDecoration: itemDecoration,
+                ),
               ),
             );
           },
diff --git a/lib/src/fields/form_builder_range_slider.dart b/lib/src/fields/form_builder_range_slider.dart
index 8a3f57f855..de2293b443 100644
--- a/lib/src/fields/form_builder_range_slider.dart
+++ b/lib/src/fields/form_builder_range_slider.dart
@@ -204,53 +204,62 @@ class FormBuilderRangeSlider extends FormBuilderFieldDecoration<RangeValues> {
               );
             }
           }
-          return InputDecorator(
-            decoration: state.decoration,
-            child: Container(
-              padding: const EdgeInsets.only(top: 10.0),
-              child: Column(
-                crossAxisAlignment: CrossAxisAlignment.start,
-                children: [
-                  RangeSlider(
-                    values: field.value!,
-                    min: min,
-                    max: max,
-                    divisions: divisions,
-                    activeColor: activeColor,
-                    inactiveColor: inactiveColor,
-                    onChangeEnd: onChangeEnd,
-                    onChangeStart: onChangeStart,
-                    labels: labels,
-                    semanticFormatterCallback: semanticFormatterCallback,
-                    onChanged: state.enabled
-                        ? (values) {
-                            field.didChange(values);
-                          }
-                        : null,
-                  ),
-                  Row(
-                    children: <Widget>[
-                      if (displayValues != DisplayValues.none &&
-                          displayValues != DisplayValues.current)
-                        minValueWidget
-                                ?.call(effectiveNumberFormat.format(min)) ??
-                            Text(effectiveNumberFormat.format(min)),
-                      const Spacer(),
-                      if (displayValues != DisplayValues.none &&
-                          displayValues != DisplayValues.minMax)
-                        valueWidget?.call(
-                                '${effectiveNumberFormat.format(field.value!.start)} - ${effectiveNumberFormat.format(field.value!.end)}') ??
-                            Text(
-                                '${effectiveNumberFormat.format(field.value!.start)} - ${effectiveNumberFormat.format(field.value!.end)}'),
-                      const Spacer(),
-                      if (displayValues != DisplayValues.none &&
-                          displayValues != DisplayValues.current)
-                        maxValueWidget
-                                ?.call(effectiveNumberFormat.format(max)) ??
-                            Text(effectiveNumberFormat.format(max)),
-                    ],
-                  ),
-                ],
+          // TODO: Solve focus issue when Flutter team solve this issue
+          // https://github.com/flutter/flutter/issues/53958
+          return Focus(
+            focusNode: state.effectiveFocusNode,
+            skipTraversal: true,
+            canRequestFocus: state.enabled,
+            debugLabel: 'FormBuilderRangeSlider-$name',
+            child: InputDecorator(
+              decoration: state.decoration,
+              isFocused: state.effectiveFocusNode.hasFocus,
+              child: Container(
+                padding: const EdgeInsets.only(top: 10.0),
+                child: Column(
+                  crossAxisAlignment: CrossAxisAlignment.start,
+                  children: [
+                    RangeSlider(
+                      values: field.value!,
+                      min: min,
+                      max: max,
+                      divisions: divisions,
+                      activeColor: activeColor,
+                      inactiveColor: inactiveColor,
+                      onChangeEnd: onChangeEnd,
+                      onChangeStart: onChangeStart,
+                      labels: labels,
+                      semanticFormatterCallback: semanticFormatterCallback,
+                      onChanged: state.enabled
+                          ? (values) {
+                              field.didChange(values);
+                            }
+                          : null,
+                    ),
+                    Row(
+                      children: <Widget>[
+                        if (displayValues != DisplayValues.none &&
+                            displayValues != DisplayValues.current)
+                          minValueWidget
+                                  ?.call(effectiveNumberFormat.format(min)) ??
+                              Text(effectiveNumberFormat.format(min)),
+                        const Spacer(),
+                        if (displayValues != DisplayValues.none &&
+                            displayValues != DisplayValues.minMax)
+                          valueWidget?.call(
+                                  '${effectiveNumberFormat.format(field.value!.start)} - ${effectiveNumberFormat.format(field.value!.end)}') ??
+                              Text(
+                                  '${effectiveNumberFormat.format(field.value!.start)} - ${effectiveNumberFormat.format(field.value!.end)}'),
+                        const Spacer(),
+                        if (displayValues != DisplayValues.none &&
+                            displayValues != DisplayValues.current)
+                          maxValueWidget
+                                  ?.call(effectiveNumberFormat.format(max)) ??
+                              Text(effectiveNumberFormat.format(max)),
+                      ],
+                    ),
+                  ],
+                ),
               ),
             ),
           );
diff --git a/lib/src/fields/form_builder_switch.dart b/lib/src/fields/form_builder_switch.dart
index c6f7b01d07..e83697704c 100644
--- a/lib/src/fields/form_builder_switch.dart
+++ b/lib/src/fields/form_builder_switch.dart
@@ -122,7 +122,9 @@ class FormBuilderSwitch extends FormBuilderFieldDecoration<bool> {
 
             return InputDecorator(
               decoration: state.decoration,
+              isFocused: state.effectiveFocusNode.hasFocus,
               child: SwitchListTile(
+                focusNode: state.effectiveFocusNode,
                 dense: true,
                 isThreeLine: false,
                 contentPadding: contentPadding,
diff --git a/lib/src/form_builder.dart b/lib/src/form_builder.dart
index 0734e4514a..78a35b6c30 100644
--- a/lib/src/form_builder.dart
+++ b/lib/src/form_builder.dart
@@ -370,7 +370,6 @@ class FormBuilderState extends State<FormBuilder> {
       child: _FormBuilderScope(
         formState: this,
         child: FocusTraversalGroup(
-          policy: WidgetOrderTraversalPolicy(),
           child: widget.child,
         ),
       ),
diff --git a/lib/src/form_builder_field.dart b/lib/src/form_builder_field.dart
index 043afffa7a..9d18beea63 100644
--- a/lib/src/form_builder_field.dart
+++ b/lib/src/form_builder_field.dart
@@ -157,7 +157,8 @@ class FormBuilderFieldState<F extends FormBuilderField<T>, T>
     if (widget.focusNode != oldWidget.focusNode) {
       focusAttachment?.detach();
       effectiveFocusNode.removeListener(_touchedHandler);
-      effectiveFocusNode = widget.focusNode ?? FocusNode();
+      effectiveFocusNode =
+          widget.focusNode ?? FocusNode(canRequestFocus: enabled);
       effectiveFocusNode.addListener(_touchedHandler);
       focusAttachment = effectiveFocusNode.attach(context);
     }
diff --git a/lib/src/form_builder_field_decoration.dart b/lib/src/form_builder_field_decoration.dart
index d52fb81018..7fb636caa0 100644
--- a/lib/src/form_builder_field_decoration.dart
+++ b/lib/src/form_builder_field_decoration.dart
@@ -36,6 +36,7 @@ class FormBuilderFieldDecorationState<F extends FormBuilderFieldDecoration<T>,
   F get widget => super.widget as F;
 
   InputDecoration get decoration => widget.decoration.copyWith(
+        // Read only allow show error to support property skipDisabled
         errorText: widget.enabled || readOnly
             ? widget.decoration.errorText ?? errorText
             : null,
diff --git a/lib/src/widgets/grouped_checkbox.dart b/lib/src/widgets/grouped_checkbox.dart
index 992950d5ac..d8d2421e7c 100644
--- a/lib/src/widgets/grouped_checkbox.dart
+++ b/lib/src/widgets/grouped_checkbox.dart
@@ -223,45 +223,41 @@ class GroupedCheckbox<T> extends StatelessWidget {
     for (var i = 0; i < options.length; i++) {
       widgetList.add(buildItem(i));
     }
-    Widget finalWidget;
-    if (orientation == OptionsOrientation.auto) {
-      finalWidget = OverflowBar(
-        alignment: MainAxisAlignment.spaceEvenly,
-        children: widgetList,
-      );
-    } else if (orientation == OptionsOrientation.vertical) {
-      finalWidget = SingleChildScrollView(
-        scrollDirection: Axis.vertical,
-        child: Column(
-          crossAxisAlignment: CrossAxisAlignment.start,
+
+    return switch (orientation) {
+      OptionsOrientation.auto => OverflowBar(
+          alignment: MainAxisAlignment.spaceEvenly,
           children: widgetList,
         ),
-      );
-    } else if (orientation == OptionsOrientation.horizontal) {
-      finalWidget = SingleChildScrollView(
-        scrollDirection: Axis.horizontal,
-        child: Row(
-          children: widgetList.map((item) {
-            return Column(children: <Widget>[item]);
-          }).toList(),
+      OptionsOrientation.vertical => SingleChildScrollView(
+          scrollDirection: Axis.vertical,
+          child: Column(
+            crossAxisAlignment: CrossAxisAlignment.start,
+            children: widgetList,
+          ),
         ),
-      );
-    } else {
-      finalWidget = SingleChildScrollView(
-        child: Wrap(
-          spacing: wrapSpacing,
-          runSpacing: wrapRunSpacing,
-          textDirection: wrapTextDirection,
-          crossAxisAlignment: wrapCrossAxisAlignment,
-          verticalDirection: wrapVerticalDirection,
-          alignment: wrapAlignment,
-          direction: Axis.horizontal,
-          runAlignment: wrapRunAlignment,
-          children: widgetList,
+      OptionsOrientation.horizontal => SingleChildScrollView(
+          scrollDirection: Axis.horizontal,
+          child: Row(
+            children: widgetList.map((item) {
+              return Column(children: <Widget>[item]);
+            }).toList(),
+          ),
         ),
-      );
-    }
-    return finalWidget;
+      OptionsOrientation.wrap => SingleChildScrollView(
+          child: Wrap(
+            spacing: wrapSpacing,
+            runSpacing: wrapRunSpacing,
+            textDirection: wrapTextDirection,
+            crossAxisAlignment: wrapCrossAxisAlignment,
+            verticalDirection: wrapVerticalDirection,
+            alignment: wrapAlignment,
+            direction: Axis.horizontal,
+            runAlignment: wrapRunAlignment,
+            children: widgetList,
+          ),
+        )
+    };
   }
 
   /// the composite of all the components for the option at index
diff --git a/lib/src/widgets/grouped_radio.dart b/lib/src/widgets/grouped_radio.dart
index 855ff9cda9..aaaf642b11 100644
--- a/lib/src/widgets/grouped_radio.dart
+++ b/lib/src/widgets/grouped_radio.dart
@@ -217,27 +217,23 @@ class _GroupedRadioState<T> extends State<GroupedRadio<T?>> {
       widgetList.add(buildItem(i));
     }
 
-    switch (widget.orientation) {
-      case OptionsOrientation.auto:
-        return OverflowBar(
+    return switch (widget.orientation) {
+      OptionsOrientation.auto => OverflowBar(
           alignment: MainAxisAlignment.spaceEvenly,
           children: widgetList,
-        );
-      case OptionsOrientation.vertical:
-        return SingleChildScrollView(
+        ),
+      OptionsOrientation.vertical => SingleChildScrollView(
           scrollDirection: Axis.vertical,
           child: Column(
             crossAxisAlignment: CrossAxisAlignment.start,
             children: widgetList,
           ),
-        );
-      case OptionsOrientation.horizontal:
-        return SingleChildScrollView(
+        ),
+      OptionsOrientation.horizontal => SingleChildScrollView(
           scrollDirection: Axis.horizontal,
           child: Row(children: widgetList),
-        );
-      case OptionsOrientation.wrap:
-        return SingleChildScrollView(
+        ),
+      OptionsOrientation.wrap => SingleChildScrollView(
           child: Wrap(
             spacing: widget.wrapSpacing,
             runSpacing: widget.wrapRunSpacing,
@@ -249,8 +245,8 @@ class _GroupedRadioState<T> extends State<GroupedRadio<T?>> {
             runAlignment: widget.wrapRunAlignment,
             children: widgetList,
           ),
-        );
-    }
+        )
+    };
   }
 
   /// the composite of all the components for the option at index


Test patch:
diff --git a/test/form_builder_checkbox_group_test.dart b/test/form_builder_checkbox_group_test.dart
deleted file mode 100644
index 0e74d588cb..0000000000
--- a/test/form_builder_checkbox_group_test.dart
+++ /dev/null
@@ -1,164 +0,0 @@
-import 'package:flutter/material.dart';
-import 'package:flutter_test/flutter_test.dart';
-import 'package:flutter_form_builder/flutter_form_builder.dart';
-
-import 'form_builder_tester.dart';
-
-void main() {
-  testWidgets('FormBuilderCheckboxGroup -- 1,3', (WidgetTester tester) async {
-    const widgetName = 'cbg1';
-    final testWidget = FormBuilderCheckboxGroup<int>(
-      name: widgetName,
-      options: const [
-        FormBuilderFieldOption(key: ValueKey('1'), value: 1),
-        FormBuilderFieldOption(key: ValueKey('2'), value: 2),
-        FormBuilderFieldOption(key: ValueKey('3'), value: 3),
-      ],
-    );
-    await tester.pumpWidget(buildTestableFieldWidget(testWidget));
-
-    expect(formSave(), isTrue);
-    expect(formValue(widgetName), isNull);
-    await tester.tap(find.byKey(const ValueKey('1')));
-    await tester.pumpAndSettle();
-    expect(formSave(), isTrue);
-    expect(formValue(widgetName), equals(const [1]));
-    await tester.tap(find.byKey(const ValueKey('3')));
-    await tester.pumpAndSettle();
-    expect(formSave(), isTrue);
-    expect(formValue(widgetName), equals(const [1, 3]));
-  });
-
-  testWidgets('FormBuilderCheckboxGroup -- decoration horizontal',
-      (WidgetTester tester) async {
-    const widgetName = 'cbg1';
-    final testWidget = FormBuilderCheckboxGroup<int>(
-      name: widgetName,
-      orientation: OptionsOrientation.horizontal,
-      wrapSpacing: 10.0,
-      options: const [
-        FormBuilderFieldOption(key: ValueKey('1'), value: 1),
-        FormBuilderFieldOption(key: ValueKey('2'), value: 2),
-      ],
-      itemDecoration:
-          BoxDecoration(border: Border.all(color: Colors.blueAccent)),
-    );
-    await tester.pumpWidget(buildTestableFieldWidget(testWidget));
-
-    // this is a brittle test knowing how we use container for a border
-    // there is one container for each option
-    expect(find.byType(Container), findsExactly(2));
-    // same as wrapSpacing
-    Container foo = tester.firstWidget(find.byType(Container));
-    expect(foo.margin, const EdgeInsets.only(right: 10.0));
-    // verify separator counts
-    expect(find.byType(VerticalDivider), findsNothing);
-  });
-
-  testWidgets('FormBuilderCheckboxGroup -- decoration vertical',
-      (WidgetTester tester) async {
-    const widgetName = 'cbg1';
-    final testWidget = FormBuilderCheckboxGroup<int>(
-      name: widgetName,
-      orientation: OptionsOrientation.vertical,
-      wrapSpacing: 10.0,
-      options: const [
-        FormBuilderFieldOption(key: ValueKey('1'), value: 1),
-        FormBuilderFieldOption(key: ValueKey('2'), value: 2),
-      ],
-      itemDecoration:
-          BoxDecoration(border: Border.all(color: Colors.blueAccent)),
-    );
-    await tester.pumpWidget(buildTestableFieldWidget(testWidget));
-
-    // this is a brittle test knowing how we use container for a border
-    // there is one container for each option
-    expect(find.byType(Container), findsExactly(2));
-    // same as wrapSpacing
-    Container foo = tester.firstWidget(find.byType(Container));
-    expect(foo.margin, const EdgeInsets.only(bottom: 10.0));
-    // verify separator counts
-    expect(find.byType(VerticalDivider), findsNothing);
-  });
-
-  testWidgets('FormBuilderCheckboxGroup -- separator horizontal',
-      (WidgetTester tester) async {
-    const widgetName = 'cbg1';
-    final testWidget = FormBuilderCheckboxGroup<int>(
-      name: widgetName,
-      orientation: OptionsOrientation.horizontal,
-      wrapSpacing: 10.0,
-      options: const [
-        FormBuilderFieldOption(key: ValueKey('1'), value: 1),
-        FormBuilderFieldOption(key: ValueKey('2'), value: 2),
-        FormBuilderFieldOption(key: ValueKey('3'), value: 2),
-      ],
-      separator: const VerticalDivider(width: 8.0, color: Colors.red),
-    );
-    await tester.pumpWidget(buildTestableFieldWidget(testWidget));
-
-    // verify separator counts
-    expect(find.byType(VerticalDivider), findsNWidgets(2));
-  });
-
-  testWidgets('FormBuilderCheckboxGroup -- separator vertical',
-      (WidgetTester tester) async {
-    const widgetName = 'cbg1';
-    final testWidget = FormBuilderCheckboxGroup<int>(
-      name: widgetName,
-      orientation: OptionsOrientation.vertical,
-      wrapSpacing: 10.0,
-      options: const [
-        FormBuilderFieldOption(key: ValueKey('1'), value: 1),
-        FormBuilderFieldOption(key: ValueKey('2'), value: 2),
-        FormBuilderFieldOption(key: ValueKey('3'), value: 2),
-      ],
-      separator: const VerticalDivider(width: 8.0, color: Colors.red),
-    );
-    await tester.pumpWidget(buildTestableFieldWidget(testWidget));
-
-    // verify separator counts
-    expect(find.byType(VerticalDivider), findsNWidgets(2));
-  });
-  testWidgets('FormBuilderCheckboxGroup -- didChange',
-      (WidgetTester tester) async {
-    const fieldName = 'cbg1';
-    final testWidget = FormBuilderCheckboxGroup<int>(
-      name: fieldName,
-      options: const [
-        FormBuilderFieldOption(key: ValueKey('1'), value: 1),
-        FormBuilderFieldOption(key: ValueKey('2'), value: 2),
-        FormBuilderFieldOption(key: ValueKey('3'), value: 3),
-      ],
-    );
-    await tester.pumpWidget(buildTestableFieldWidget(testWidget));
-
-    expect(formSave(), isTrue);
-    expect(formValue(fieldName), isNull);
-    formFieldDidChange(fieldName, [1, 3]);
-    await tester.pumpAndSettle();
-    expect(formSave(), isTrue);
-    expect(formValue(fieldName), [1, 3]);
-
-    Checkbox checkbox1 = tester
-        .element(find.byKey(const ValueKey('1')))
-        .findAncestorWidgetOfExactType<Row>()!
-        .children
-        .first as Checkbox;
-    Checkbox checkbox2 = tester
-        .element(find.byKey(const ValueKey('2')))
-        .findAncestorWidgetOfExactType<Row>()!
-        .children
-        .first as Checkbox;
-    Checkbox checkbox3 = tester
-        .element(find.byKey(const ValueKey('3')))
-        .findAncestorWidgetOfExactType<Row>()!
-        .children
-        .first as Checkbox;
-
-    // checkboxes should represent the state of the didChange value
-    expect(checkbox1.value, true);
-    expect(checkbox2.value, false);
-    expect(checkbox3.value, true);
-  });
-}
diff --git a/test/form_builder_checkbox_test.dart b/test/form_builder_checkbox_test.dart
deleted file mode 100644
index 38979d53b7..0000000000
--- a/test/form_builder_checkbox_test.dart
+++ /dev/null
@@ -1,29 +0,0 @@
-import 'package:flutter/material.dart';
-import 'package:flutter_form_builder/src/fields/form_builder_checkbox.dart';
-import 'package:flutter_test/flutter_test.dart';
-import 'form_builder_tester.dart';
-
-void main() {
-  testWidgets('FormBuilderCheckbox -- Off/On/Off', (WidgetTester tester) async {
-    const checkboxName = 'cb1';
-    final testWidget = FormBuilderCheckbox(
-      name: checkboxName,
-      title: const Text('Checkbox 1'),
-      initialValue: false,
-    );
-    final widgetFinder = find.byWidget(testWidget);
-
-    await tester.pumpWidget(buildTestableFieldWidget(testWidget));
-
-    expect(formSave(), isTrue);
-    expect(formValue(checkboxName), isFalse);
-    await tester.tap(widgetFinder);
-    await tester.pumpAndSettle();
-    expect(formSave(), isTrue);
-    expect(formValue(checkboxName), isTrue);
-    await tester.tap(widgetFinder);
-    await tester.pumpAndSettle();
-    expect(formSave(), isTrue);
-    expect(formValue(checkboxName), isFalse);
-  });
-}
diff --git a/test/form_builder_radio_group_test.dart b/test/form_builder_radio_group_test.dart
deleted file mode 100644
index 68dc191095..0000000000
--- a/test/form_builder_radio_group_test.dart
+++ /dev/null
@@ -1,125 +0,0 @@
-import 'package:flutter/material.dart';
-import 'package:flutter_test/flutter_test.dart';
-import 'package:flutter_form_builder/flutter_form_builder.dart';
-import 'form_builder_tester.dart';
-
-void main() {
-  testWidgets('FormBuilderRadioGroup -- 1,3', (WidgetTester tester) async {
-    const widgetName = 'rg1';
-    final testWidget = FormBuilderRadioGroup<int>(
-      name: widgetName,
-      options: const [
-        FormBuilderFieldOption(key: ValueKey('1'), value: 1),
-        FormBuilderFieldOption(key: ValueKey('2'), value: 2),
-        FormBuilderFieldOption(key: ValueKey('3'), value: 3),
-      ],
-    );
-    await tester.pumpWidget(buildTestableFieldWidget(testWidget));
-
-    expect(formSave(), isTrue);
-    expect(formValue(widgetName), isNull);
-    await tester.tap(find.byKey(const ValueKey('1')));
-    await tester.pumpAndSettle();
-    expect(formSave(), isTrue);
-    expect(formValue(widgetName), equals(1));
-    await tester.tap(find.byKey(const ValueKey('3')));
-    await tester.pumpAndSettle();
-    expect(formSave(), isTrue);
-    expect(formValue(widgetName), equals(3));
-  });
-
-  testWidgets('FormBuilderRadioGroup -- decoration horizontal',
-      (WidgetTester tester) async {
-    const widgetName = 'rg1';
-    final testWidget = FormBuilderRadioGroup<int>(
-      name: widgetName,
-      orientation: OptionsOrientation.horizontal,
-      wrapSpacing: 10.0,
-      options: const [
-        FormBuilderFieldOption(key: ValueKey('1'), value: 1),
-        FormBuilderFieldOption(key: ValueKey('2'), value: 2),
-      ],
-      itemDecoration:
-          BoxDecoration(border: Border.all(color: Colors.blueAccent)),
-    );
-    await tester.pumpWidget(buildTestableFieldWidget(testWidget));
-
-    // this is a brittle test knowing how we use container for a border
-    // there is one container for each option
-    expect(find.byType(Container), findsExactly(2));
-    // same as wrapSpacing
-    Container foo = tester.firstWidget(find.byType(Container));
-    expect(foo.margin, const EdgeInsets.only(right: 10.0));
-    // verify separator counts
-    expect(find.byType(VerticalDivider), findsNothing);
-  });
-
-  testWidgets('FormBuilderRadioGroup -- decoration vertical',
-      (WidgetTester tester) async {
-    const widgetName = 'rg1';
-    final testWidget = FormBuilderRadioGroup<int>(
-      name: widgetName,
-      orientation: OptionsOrientation.vertical,
-      wrapSpacing: 10.0,
-      options: const [
-        FormBuilderFieldOption(key: ValueKey('1'), value: 1),
-        FormBuilderFieldOption(key: ValueKey('2'), value: 2),
-      ],
-      itemDecoration:
-          BoxDecoration(border: Border.all(color: Colors.blueAccent)),
-    );
-    await tester.pumpWidget(buildTestableFieldWidget(testWidget));
-
-    // this is a brittle test knowing how we use container for a border
-    // there is one container for each option
-    expect(find.byType(Container), findsExactly(2));
-    // same as wrapSpacing
-    Container foo = tester.firstWidget(find.byType(Container));
-    expect(foo.margin, const EdgeInsets.only(bottom: 10.0));
-    // verify separator counts
-    expect(find.byType(VerticalDivider), findsNothing);
-  });
-
-  testWidgets('FormBuilderRadioGroup -- separators horizontal',
-      (WidgetTester tester) async {
-    const widgetName = 'rg1';
-    final testWidget = FormBuilderRadioGroup<int>(
-      name: widgetName,
-      orientation: OptionsOrientation.horizontal,
-      wrapSpacing: 10.0,
-      options: const [
-        FormBuilderFieldOption(key: ValueKey('1'), value: 1),
-        FormBuilderFieldOption(key: ValueKey('2'), value: 2),
-        FormBuilderFieldOption(key: ValueKey('3'), value: 2),
-      ],
-      separator: const VerticalDivider(width: 8.0, color: Colors.red),
-    );
-    await tester.pumpWidget(buildTestableFieldWidget(testWidget));
-
-    // verify separator counts
-    expect(find.byType(VerticalDivider), findsNWidgets(2));
-  });
-
-  testWidgets('FormBuilderRadioGroup -- separators vertical',
-      (WidgetTester tester) async {
-    const widgetName = 'rg1';
-    final testWidget = FormBuilderRadioGroup<int>(
-      name: widgetName,
-      orientation: OptionsOrientation.vertical,
-      wrapSpacing: 10.0,
-      options: const [
-        FormBuilderFieldOption(key: ValueKey('1'), value: 1),
-        FormBuilderFieldOption(key: ValueKey('2'), value: 2),
-        FormBuilderFieldOption(key: ValueKey('2'), value: 2),
-      ],
-      itemDecoration: BoxDecoration(
-        border: Border.all(color: Colors.blueAccent),
-      ),
-      separator: const VerticalDivider(width: 8.0, color: Colors.red),
-    );
-    await tester.pumpWidget(buildTestableFieldWidget(testWidget));
-
-    // verify separator counts
-    expect(find.byType(VerticalDivider), findsNWidgets(2));
-  });
-}
diff --git a/test/form_builder_slider_test.dart b/test/form_builder_slider_test.dart
deleted file mode 100644
index df51112bd0..0000000000
--- a/test/form_builder_slider_test.dart
+++ /dev/null
@@ -1,28 +0,0 @@
-import 'package:flutter/material.dart';
-import 'package:flutter_form_builder/src/fields/form_builder_slider.dart';
-import 'package:flutter_test/flutter_test.dart';
-import 'form_builder_tester.dart';
-
-void main() {
-  testWidgets('FormBuilderSlider -- 5.0', (WidgetTester tester) async {
-    const widgetName = 'slider1';
-    final testWidget = FormBuilderSlider(
-      name: widgetName,
-      initialValue: 2,
-      min: 0,
-      max: 10,
-      divisions: 20,
-      decoration: const InputDecoration(
-        labelText: 'Number of things',
-      ),
-    );
-    await tester.pumpWidget(buildTestableFieldWidget(testWidget));
-
-    expect(formSave(), isTrue);
-    expect(formValue(widgetName), equals(2.0));
-    await tester.tap(find.byType(Slider));
-    await tester.pumpAndSettle();
-    expect(formSave(), isTrue);
-    expect(formValue(widgetName), equals(5.0));
-  });
-}
diff --git a/test/form_builder_switch_test.dart b/test/form_builder_switch_test.dart
deleted file mode 100644
index 85083343af..0000000000
--- a/test/form_builder_switch_test.dart
+++ /dev/null
@@ -1,29 +0,0 @@
-import 'package:flutter/material.dart';
-import 'package:flutter_form_builder/src/fields/form_builder_switch.dart';
-import 'package:flutter_test/flutter_test.dart';
-import 'form_builder_tester.dart';
-
-void main() {
-  testWidgets('FormBuilderSwitch -- Off/On/Off', (WidgetTester tester) async {
-    const switchName = 'switch1';
-    final testWidget = FormBuilderSwitch(
-      name: switchName,
-      title: const Text('Switch 1'),
-      initialValue: false,
-    );
-    final widgetFinder = find.byWidget(testWidget);
-
-    await tester.pumpWidget(buildTestableFieldWidget(testWidget));
-
-    expect(formSave(), isTrue);
-    expect(formValue(switchName), isFalse);
-    await tester.tap(widgetFinder);
-    await tester.pumpAndSettle();
-    expect(formSave(), isTrue);
-    expect(formValue(switchName), isTrue);
-    await tester.tap(widgetFinder);
-    await tester.pumpAndSettle();
-    expect(formSave(), isTrue);
-    expect(formValue(switchName), isFalse);
-  });
-}
diff --git a/test/form_builder_text_field_test.dart b/test/form_builder_text_field_test.dart
deleted file mode 100644
index 1542016b3a..0000000000
--- a/test/form_builder_text_field_test.dart
+++ /dev/null
@@ -1,100 +0,0 @@
-import 'package:flutter/material.dart';
-import 'package:flutter_form_builder/flutter_form_builder.dart';
-import 'package:flutter_test/flutter_test.dart';
-
-import 'form_builder_tester.dart';
-
-void main() {
-  testWidgets('FormBuilderTextField -- Hello Planet',
-      (WidgetTester tester) async {
-    const newTextValue = 'Hello 🪐';
-    const textFieldName = 'text1';
-    final testWidget = FormBuilderTextField(
-      name: textFieldName,
-    );
-    final widgetFinder = find.byWidget(testWidget);
-
-    await tester.pumpWidget(buildTestableFieldWidget(testWidget));
-    expect(formSave(), isTrue);
-    expect(formValue(textFieldName), isNull);
-    await tester.enterText(widgetFinder, newTextValue);
-    expect(formSave(), isTrue);
-    expect(formValue(textFieldName), equals(newTextValue));
-    await tester.enterText(widgetFinder, '');
-    expect(formSave(), isTrue);
-    expect(formValue(textFieldName), isEmpty);
-  });
-  testWidgets(
-    'FormBuilderTextField without initialValue',
-    (tester) => _testFormBuilderTextFieldWithInitialValue(
-      tester,
-    ),
-  );
-  testWidgets(
-    'FormBuilderTextField has initialValue on Field',
-    (tester) => _testFormBuilderTextFieldWithInitialValue(
-      tester,
-      initialValueOnField: 'ok',
-    ),
-  );
-  testWidgets(
-    'FormBuilderTextField has initialValue on Form',
-    (tester) => _testFormBuilderTextFieldWithInitialValue(
-      tester,
-      initialValueOnForm: 'ok',
-    ),
-  );
-
-  testWidgets(
-    'FormBuilderTextField triggers onTapOutside',
-    (tester) => _testFormBuilderTextFieldOnTapOutsideCallback(tester),
-  );
-}
-
-Future<void> _testFormBuilderTextFieldWithInitialValue(
-  WidgetTester tester, {
-  String? initialValueOnField,
-  String? initialValueOnForm,
-}) async {
-  int changedCount = 0;
-  const newTextValue = 'Hello 🪐';
-  const textFieldName = 'text1';
-
-  var testWidget = FormBuilderTextField(
-    name: textFieldName,
-    initialValue: initialValueOnField,
-    onChanged: (String? value) => changedCount++,
-  );
-  await tester.pumpWidget(buildTestableFieldWidget(
-    testWidget,
-    initialValue: {
-      textFieldName: initialValueOnForm,
-    },
-  ));
-  expect(formSave(), isTrue);
-  expect(formValue(textFieldName), initialValueOnField ?? initialValueOnForm);
-  expect(changedCount, 0);
-
-  await tester.enterText(find.byWidget(testWidget), newTextValue);
-  expect(formSave(), isTrue);
-  expect(formValue(textFieldName), newTextValue);
-
-  expect(changedCount, 1);
-}
-
-Future<void> _testFormBuilderTextFieldOnTapOutsideCallback(
-    WidgetTester tester) async {
-  const textFieldName = 'Hello 🪐';
-  bool triggered = false;
-
-  var testWidget = FormBuilderTextField(
-    name: textFieldName,
-    onTapOutside: (event) => triggered = true,
-  );
-  await tester.pumpWidget(buildTestableFieldWidget(
-    testWidget,
-  ));
-  final textField = tester.firstWidget(find.byType(TextField)) as TextField;
-  textField.onTapOutside?.call(const PointerDownEvent());
-  expect(triggered, true);
-}
diff --git a/test/src/fields/form_builder_checkbox_group_test.dart b/test/src/fields/form_builder_checkbox_group_test.dart
new file mode 100644
index 0000000000..57fd22a294
--- /dev/null
+++ b/test/src/fields/form_builder_checkbox_group_test.dart
@@ -0,0 +1,188 @@
+import 'package:flutter/material.dart';
+import 'package:flutter/services.dart';
+import 'package:flutter_test/flutter_test.dart';
+import 'package:flutter_form_builder/flutter_form_builder.dart';
+
+import '../../form_builder_tester.dart';
+
+void main() {
+  group('FormBuilderCheckboxGroup -', () {
+    testWidgets('1,3', (WidgetTester tester) async {
+      const widgetName = 'cbg1';
+      final testWidget = FormBuilderCheckboxGroup<int>(
+        name: widgetName,
+        options: const [
+          FormBuilderFieldOption(key: ValueKey('1'), value: 1),
+          FormBuilderFieldOption(key: ValueKey('2'), value: 2),
+          FormBuilderFieldOption(key: ValueKey('3'), value: 3),
+        ],
+      );
+      await tester.pumpWidget(buildTestableFieldWidget(testWidget));
+
+      expect(formSave(), isTrue);
+      expect(formValue(widgetName), isNull);
+      await tester.tap(find.byKey(const ValueKey('1')));
+      await tester.pumpAndSettle();
+      expect(formSave(), isTrue);
+      expect(formValue(widgetName), equals(const [1]));
+      await tester.tap(find.byKey(const ValueKey('3')));
+      await tester.pumpAndSettle();
+      expect(formSave(), isTrue);
+      expect(formValue(widgetName), equals(const [1, 3]));
+    });
+
+    testWidgets('decoration horizontal', (WidgetTester tester) async {
+      const widgetName = 'cbg1';
+      final testWidget = FormBuilderCheckboxGroup<int>(
+        name: widgetName,
+        orientation: OptionsOrientation.horizontal,
+        wrapSpacing: 10.0,
+        options: const [
+          FormBuilderFieldOption(key: ValueKey('1'), value: 1),
+          FormBuilderFieldOption(key: ValueKey('2'), value: 2),
+        ],
+        itemDecoration:
+            BoxDecoration(border: Border.all(color: Colors.blueAccent)),
+      );
+      await tester.pumpWidget(buildTestableFieldWidget(testWidget));
+
+      // this is a brittle test knowing how we use container for a border
+      // there is one container for each option
+      expect(find.byType(Container), findsExactly(2));
+      // same as wrapSpacing
+      Container foo = tester.firstWidget(find.byType(Container));
+      expect(foo.margin, const EdgeInsets.only(right: 10.0));
+      // verify separator counts
+      expect(find.byType(VerticalDivider), findsNothing);
+    });
+
+    testWidgets('decoration vertical', (WidgetTester tester) async {
+      const widgetName = 'cbg1';
+      final testWidget = FormBuilderCheckboxGroup<int>(
+        name: widgetName,
+        orientation: OptionsOrientation.vertical,
+        wrapSpacing: 10.0,
+        options: const [
+          FormBuilderFieldOption(key: ValueKey('1'), value: 1),
+          FormBuilderFieldOption(key: ValueKey('2'), value: 2),
+        ],
+        itemDecoration:
+            BoxDecoration(border: Border.all(color: Colors.blueAccent)),
+      );
+      await tester.pumpWidget(buildTestableFieldWidget(testWidget));
+
+      // this is a brittle test knowing how we use container for a border
+      // there is one container for each option
+      expect(find.byType(Container), findsExactly(2));
+      // same as wrapSpacing
+      Container foo = tester.firstWidget(find.byType(Container));
+      expect(foo.margin, const EdgeInsets.only(bottom: 10.0));
+      // verify separator counts
+      expect(find.byType(VerticalDivider), findsNothing);
+    });
+
+    testWidgets('separator horizontal', (WidgetTester tester) async {
+      const widgetName = 'cbg1';
+      final testWidget = FormBuilderCheckboxGroup<int>(
+        name: widgetName,
+        orientation: OptionsOrientation.horizontal,
+        wrapSpacing: 10.0,
+        options: const [
+          FormBuilderFieldOption(key: ValueKey('1'), value: 1),
+          FormBuilderFieldOption(key: ValueKey('2'), value: 2),
+          FormBuilderFieldOption(key: ValueKey('3'), value: 2),
+        ],
+        separator: const VerticalDivider(width: 8.0, color: Colors.red),
+      );
+      await tester.pumpWidget(buildTestableFieldWidget(testWidget));
+
+      // verify separator counts
+      expect(find.byType(VerticalDivider), findsNWidgets(2));
+    });
+
+    testWidgets('separator vertical', (WidgetTester tester) async {
+      const widgetName = 'cbg1';
+      final testWidget = FormBuilderCheckboxGroup<int>(
+        name: widgetName,
+        orientation: OptionsOrientation.vertical,
+        wrapSpacing: 10.0,
+        options: const [
+          FormBuilderFieldOption(key: ValueKey('1'), value: 1),
+          FormBuilderFieldOption(key: ValueKey('2'), value: 2),
+          FormBuilderFieldOption(key: ValueKey('3'), value: 2),
+        ],
+        separator: const VerticalDivider(width: 8.0, color: Colors.red),
+      );
+      await tester.pumpWidget(buildTestableFieldWidget(testWidget));
+
+      // verify separator counts
+      expect(find.byType(VerticalDivider), findsNWidgets(2));
+    });
+    testWidgets('didChange', (WidgetTester tester) async {
+      const fieldName = 'cbg1';
+      final testWidget = FormBuilderCheckboxGroup<int>(
+        name: fieldName,
+        options: const [
+          FormBuilderFieldOption(key: ValueKey('1'), value: 1),
+          FormBuilderFieldOption(key: ValueKey('2'), value: 2),
+          FormBuilderFieldOption(key: ValueKey('3'), value: 3),
+        ],
+      );
+      await tester.pumpWidget(buildTestableFieldWidget(testWidget));
+
+      expect(formSave(), isTrue);
+      expect(formValue(fieldName), isNull);
+      formFieldDidChange(fieldName, [1, 3]);
+      await tester.pumpAndSettle();
+      expect(formSave(), isTrue);
+      expect(formValue(fieldName), [1, 3]);
+
+      Checkbox checkbox1 = tester
+          .element(find.byKey(const ValueKey('1')))
+          .findAncestorWidgetOfExactType<Row>()!
+          .children
+          .first as Checkbox;
+      Checkbox checkbox2 = tester
+          .element(find.byKey(const ValueKey('2')))
+          .findAncestorWidgetOfExactType<Row>()!
+          .children
+          .first as Checkbox;
+      Checkbox checkbox3 = tester
+          .element(find.byKey(const ValueKey('3')))
+          .findAncestorWidgetOfExactType<Row>()!
+          .children
+          .first as Checkbox;
+
+      // checkboxes should represent the state of the didChange value
+      expect(checkbox1.value, true);
+      expect(checkbox2.value, false);
+      expect(checkbox3.value, true);
+    });
+    testWidgets('When press tab, field will be focused',
+        (WidgetTester tester) async {
+      const widgetName = 'cb1';
+      final testWidget = FormBuilderCheckboxGroup<int>(
+        name: widgetName,
+        options: const [
+          FormBuilderFieldOption(key: ValueKey('1'), value: 1),
+          FormBuilderFieldOption(key: ValueKey('2'), value: 2),
+          FormBuilderFieldOption(key: ValueKey('3'), value: 3),
+        ],
+      );
+      final widgetFinder = find.byWidget(testWidget);
+
+      await tester.pumpWidget(buildTestableFieldWidget(testWidget));
+      final focusNode =
+          formKey.currentState?.fields[widgetName]?.effectiveFocusNode;
+
+      expect(formSave(), isTrue);
+      expect(formValue(widgetName), isNull);
+      expect(Focus.of(tester.element(widgetFinder)).hasFocus, false);
+      expect(focusNode?.hasFocus, false);
+      await tester.sendKeyEvent(LogicalKeyboardKey.tab);
+      await tester.pumpAndSettle();
+      expect(Focus.of(tester.element(widgetFinder)).hasFocus, true);
+      expect(focusNode?.hasFocus, true);
+    });
+  });
+}
diff --git a/test/src/fields/form_builder_checkbox_test.dart b/test/src/fields/form_builder_checkbox_test.dart
new file mode 100644
index 0000000000..f08103c8f3
--- /dev/null
+++ b/test/src/fields/form_builder_checkbox_test.dart
@@ -0,0 +1,55 @@
+import 'package:flutter/material.dart';
+import 'package:flutter/services.dart';
+import 'package:flutter_form_builder/src/fields/form_builder_checkbox.dart';
+import 'package:flutter_test/flutter_test.dart';
+import '../../form_builder_tester.dart';
+
+void main() {
+  group('FormBuilderCheckbox -', () {
+    testWidgets('Off/On/Off', (WidgetTester tester) async {
+      const widgetName = 'cb1';
+      final testWidget = FormBuilderCheckbox(
+        name: widgetName,
+        title: const Text('Checkbox 1'),
+        initialValue: false,
+      );
+      final widgetFinder = find.byWidget(testWidget);
+
+      await tester.pumpWidget(buildTestableFieldWidget(testWidget));
+
+      expect(formSave(), isTrue);
+      expect(formValue(widgetName), isFalse);
+      await tester.tap(widgetFinder);
+      await tester.pumpAndSettle();
+      expect(formSave(), isTrue);
+      expect(formValue(widgetName), isTrue);
+      await tester.tap(widgetFinder);
+      await tester.pumpAndSettle();
+      expect(formSave(), isTrue);
+      expect(formValue(widgetName), isFalse);
+    });
+    testWidgets('When press tab, field will be focused',
+        (WidgetTester tester) async {
+      const widgetName = 'cb1';
+      final testWidget = FormBuilderCheckbox(
+        name: widgetName,
+        title: const Text('Checkbox 1'),
+        initialValue: false,
+      );
+      final widgetFinder = find.byWidget(testWidget);
+
+      await tester.pumpWidget(buildTestableFieldWidget(testWidget));
+      final focusNode =
+          formKey.currentState?.fields[widgetName]?.effectiveFocusNode;
+
+      expect(formSave(), isTrue);
+      expect(formValue(widgetName), isFalse);
+      expect(Focus.of(tester.element(widgetFinder)).hasFocus, false);
+      expect(focusNode?.hasFocus, false);
+      await tester.sendKeyEvent(LogicalKeyboardKey.tab);
+      await tester.pumpAndSettle();
+      expect(Focus.of(tester.element(widgetFinder)).hasFocus, true);
+      expect(focusNode?.hasFocus, true);
+    });
+  });
+}
diff --git a/test/form_builder_choice_chips_test.dart b/test/src/fields/form_builder_choice_chips_test.dart
similarity index 72%
rename from test/form_builder_choice_chips_test.dart
rename to test/src/fields/form_builder_choice_chips_test.dart
index 9e1837de34..1cdef27e89 100644
--- a/test/form_builder_choice_chips_test.dart
+++ b/test/src/fields/form_builder_choice_chips_test.dart
@@ -1,9 +1,10 @@
 import 'package:flutter/material.dart';
+import 'package:flutter/services.dart';
 import 'package:flutter_test/flutter_test.dart';
 
 import 'package:flutter_form_builder/flutter_form_builder.dart';
 
-import 'form_builder_tester.dart';
+import '../../form_builder_tester.dart';
 
 void main() {
   group('FormBuilderChoiceChip --', () {
@@ -82,5 +83,32 @@ void main() {
       expect(formSave(), isTrue);
       expect(formValue<int?>(widgetName), equals(3));
     });
+
+    testWidgets('When press tab, field will be focused',
+        (WidgetTester tester) async {
+      const widgetName = 'cb1';
+      final testWidget = FormBuilderChoiceChip<int>(
+        name: widgetName,
+        options: const [
+          FormBuilderChipOption(key: ValueKey('1'), value: 1),
+          FormBuilderChipOption(key: ValueKey('2'), value: 2),
+          FormBuilderChipOption(key: ValueKey('3'), value: 3),
+        ],
+      );
+      final widgetFinder = find.byWidget(testWidget);
+
+      await tester.pumpWidget(buildTestableFieldWidget(testWidget));
+      final focusNode =
+          formKey.currentState?.fields[widgetName]?.effectiveFocusNode;
+
+      expect(formSave(), isTrue);
+      expect(formValue<int?>(widgetName), isNull);
+      expect(Focus.of(tester.element(widgetFinder)).hasFocus, false);
+      expect(focusNode?.hasFocus, false);
+      await tester.sendKeyEvent(LogicalKeyboardKey.tab);
+      await tester.pumpAndSettle();
+      expect(Focus.of(tester.element(widgetFinder)).hasFocus, true);
+      expect(focusNode?.hasFocus, true);
+    });
   });
 }
diff --git a/test/form_builder_date_range_picker_test.dart b/test/src/fields/form_builder_date_range_picker_test.dart
similarity index 57%
rename from test/form_builder_date_range_picker_test.dart
rename to test/src/fields/form_builder_date_range_picker_test.dart
index e5175188d3..479ba82293 100644
--- a/test/form_builder_date_range_picker_test.dart
+++ b/test/src/fields/form_builder_date_range_picker_test.dart
@@ -1,12 +1,13 @@
 import 'package:flutter/material.dart';
+import 'package:flutter/services.dart';
 import 'package:flutter_form_builder/flutter_form_builder.dart';
 import 'package:flutter_test/flutter_test.dart';
 import 'package:intl/intl.dart';
 
-import 'form_builder_tester.dart';
+import '../../form_builder_tester.dart';
 
 void main() {
-  group('FormBuilderDateRangePicker --', () {
+  group('FormBuilderDateRangePicker -', () {
     testWidgets('basic', (WidgetTester tester) async {
       const widgetName = 'formBuilderDateRangePicker';
       final testWidget = FormBuilderDateRangePicker(
@@ -102,4 +103,63 @@ void main() {
       );
     });
   });
+  testWidgets('When press tab, field will be focused',
+      (WidgetTester tester) async {
+    const widgetName = 'cb1';
+    const saveText = 'SAVE THE DATE';
+    final testWidget = FormBuilderDateRangePicker(
+      name: widgetName,
+      firstDate: DateTime(2010),
+      // Using last date < today to make date picker always open on 01/01/2010
+      // If last date >= today, it opens on DateTime.now month, which complicates testing.
+      lastDate: DateTime(2020),
+      saveText: saveText,
+    );
+    final widgetFinder = find.byWidget(testWidget);
+
+    await tester.pumpWidget(buildTestableFieldWidget(testWidget));
+    final focusNode =
+        formKey.currentState?.fields[widgetName]?.effectiveFocusNode;
+
+    expect(formSave(), isTrue);
+    expect(formValue<DateTimeRange?>(widgetName), isNull);
+    expect(Focus.of(tester.element(widgetFinder)).hasFocus, false);
+    expect(focusNode?.hasFocus, false);
+    await tester.sendKeyEvent(LogicalKeyboardKey.tab);
+    await tester.pumpAndSettle();
+    expect(Focus.of(tester.element(widgetFinder)).hasFocus, true);
+    expect(focusNode?.hasFocus, true);
+    expect(find.text(saveText), findsNothing);
+
+    // Open picker
+    await tester.sendKeyEvent(LogicalKeyboardKey.space);
+    await tester.pumpAndSettle();
+    expect(find.text(saveText), findsOneWidget);
+  });
+  testWidgets('When press clear button then clear value text field',
+      (WidgetTester tester) async {
+    const widgetName = 'cb1';
+    final initialValue = DateTimeRange(
+      start: DateTime(2010, 1, 2),
+      end: DateTime(2010, 1, 4),
+    );
+    final testWidget = FormBuilderDateRangePicker(
+      name: widgetName,
+      initialValue: initialValue,
+      allowClear: true,
+      firstDate: DateTime(2010),
+      // Using last date < today to make date picker always open on 01/01/2010
+      // If last date >= today, it opens on DateTime.now month, which complicates testing.
+      lastDate: DateTime(2020),
+    );
+
+    await tester.pumpWidget(buildTestableFieldWidget(testWidget));
+
+    expect(formSave(), isTrue);
+    expect(formValue<DateTimeRange?>(widgetName), equals(initialValue));
+    await tester.tap(find.byType(IconButton));
+    await tester.pumpAndSettle();
+
+    expect(find.widgetWithText(TextField, ''), findsOneWidget);
+  });
 }
diff --git a/test/src/fields/form_builder_date_time_picker_test.dart b/test/src/fields/form_builder_date_time_picker_test.dart
index 077f001f67..961de70cd1 100644
--- a/test/src/fields/form_builder_date_time_picker_test.dart
+++ b/test/src/fields/form_builder_date_time_picker_test.dart
@@ -1,4 +1,5 @@
 import 'package:flutter/material.dart';
+import 'package:flutter/services.dart';
 import 'package:flutter_form_builder/flutter_form_builder.dart';
 import 'package:flutter_test/flutter_test.dart';
 
@@ -147,4 +148,39 @@ void main() {
       });
     });
   });
+
+  testWidgets('When press tab, field will be focused',
+      (WidgetTester tester) async {
+    const widgetName = 'cb1';
+    final widgetKey = UniqueKey();
+    const confirmText = 'OK';
+    const cancelText = 'CANCEL';
+
+    final testWidget = FormBuilderDateTimePicker(
+      key: widgetKey,
+      name: widgetName,
+      confirmText: confirmText,
+      cancelText: cancelText,
+    );
+    final widgetFinder = find.byWidget(testWidget);
+
+    await tester.pumpWidget(buildTestableFieldWidget(testWidget));
+    final focusNode =
+        formKey.currentState?.fields[widgetName]?.effectiveFocusNode;
+
+    expect(formSave(), isTrue);
+    expect(formValue(widgetName), equals(null));
+    expect(Focus.of(tester.element(widgetFinder)).hasFocus, false);
+    expect(focusNode?.hasFocus, false);
+    await tester.sendKeyEvent(LogicalKeyboardKey.tab);
+    await tester.pumpAndSettle();
+    expect(Focus.of(tester.element(widgetFinder)).hasFocus, true);
+    expect(focusNode?.hasFocus, true);
+
+    // Open picker
+    await tester.sendKeyEvent(LogicalKeyboardKey.space);
+    await tester.pumpAndSettle();
+    expect(find.text(confirmText), findsOneWidget);
+    expect(find.text(cancelText), findsOneWidget);
+  });
 }
diff --git a/test/src/fields/form_builder_dropdown_test.dart b/test/src/fields/form_builder_dropdown_test.dart
index a582bb01ea..293399158e 100644
--- a/test/src/fields/form_builder_dropdown_test.dart
+++ b/test/src/fields/form_builder_dropdown_test.dart
@@ -1,4 +1,5 @@
 import 'package:flutter/material.dart';
+import 'package:flutter/services.dart';
 import 'package:flutter_form_builder/src/fields/form_builder_dropdown.dart';
 import 'package:flutter_test/flutter_test.dart';
 
@@ -266,6 +267,42 @@ void main() {
 
     expect(formKey.currentState?.instantValue, equals(initialValue));
   });
+
+  testWidgets('When press tab, field will be focused',
+      (WidgetTester tester) async {
+    const widgetName = 'cb1';
+    final testWidget = FormBuilderDropdown<int>(
+      name: widgetName,
+      items: const [
+        DropdownMenuItem(
+          value: 1,
+          child: Text('One'),
+        ),
+        DropdownMenuItem(
+          value: 2,
+          child: Text('Two'),
+        ),
+        DropdownMenuItem(
+          value: 3,
+          child: Text('Three'),
+        ),
+      ],
+    );
+    final widgetFinder = find.byWidget(testWidget);
+
+    await tester.pumpWidget(buildTestableFieldWidget(testWidget));
+    final focusNode =
+        formKey.currentState?.fields[widgetName]?.effectiveFocusNode;
+
+    expect(formSave(), isTrue);
+    expect(formValue(widgetName), isNull);
+    expect(Focus.of(tester.element(widgetFinder)).hasFocus, false);
+    expect(focusNode?.hasFocus, false);
+    await tester.sendKeyEvent(LogicalKeyboardKey.tab);
+    await tester.pumpAndSettle();
+    expect(Focus.of(tester.element(widgetFinder)).hasFocus, true);
+    expect(focusNode?.hasFocus, true);
+  });
 }
 
 class MyTestWidget<T> extends StatefulWidget {
diff --git a/test/form_builder_filter_chips_test.dart b/test/src/fields/form_builder_filter_chips_test.dart
similarity index 76%
rename from test/form_builder_filter_chips_test.dart
rename to test/src/fields/form_builder_filter_chips_test.dart
index 94e9c788cb..da207b8217 100644
--- a/test/form_builder_filter_chips_test.dart
+++ b/test/src/fields/form_builder_filter_chips_test.dart
@@ -1,8 +1,9 @@
 import 'package:flutter/material.dart';
+import 'package:flutter/services.dart';
 import 'package:flutter_form_builder/flutter_form_builder.dart';
 import 'package:flutter_test/flutter_test.dart';
 
-import 'form_builder_tester.dart';
+import '../../form_builder_tester.dart';
 
 void main() {
   group('FormBuilderFilterChip --', () {
@@ -91,5 +92,31 @@ void main() {
         expect(formValue<List<int>?>(widgetName), equals(<int>[3]));
       });
     });
+    testWidgets('When press tab, field will be focused',
+        (WidgetTester tester) async {
+      const widgetName = 'key';
+      final testWidget = FormBuilderFilterChip<int>(
+        name: widgetName,
+        options: const [
+          FormBuilderChipOption(key: ValueKey('1'), value: 1),
+          FormBuilderChipOption(key: ValueKey('2'), value: 2),
+          FormBuilderChipOption(key: ValueKey('3'), value: 3),
+        ],
+      );
+      final widgetFinder = find.byWidget(testWidget);
+
+      await tester.pumpWidget(buildTestableFieldWidget(testWidget));
+      final focusNode =
+          formKey.currentState?.fields[widgetName]?.effectiveFocusNode;
+
+      expect(formSave(), isTrue);
+      expect(formValue<List<int>?>(widgetName), equals(null));
+      expect(Focus.of(tester.element(widgetFinder)).hasFocus, false);
+      expect(focusNode?.hasFocus, false);
+      await tester.sendKeyEvent(LogicalKeyboardKey.tab);
+      await tester.pumpAndSettle();
+      expect(Focus.of(tester.element(widgetFinder)).hasFocus, true);
+      expect(focusNode?.hasFocus, true);
+    });
   });
 }
diff --git a/test/src/fields/form_builder_radio_group_test.dart b/test/src/fields/form_builder_radio_group_test.dart
new file mode 100644
index 0000000000..18701eef1d
--- /dev/null
+++ b/test/src/fields/form_builder_radio_group_test.dart
@@ -0,0 +1,171 @@
+import 'package:flutter/material.dart';
+import 'package:flutter/services.dart';
+import 'package:flutter_test/flutter_test.dart';
+import 'package:flutter_form_builder/flutter_form_builder.dart';
+import '../../form_builder_tester.dart';
+
+void main() {
+  group('FormBuilderRadioGroup -', () {
+    testWidgets('1,3', (WidgetTester tester) async {
+      const widgetName = 'rg1';
+      final testWidget = FormBuilderRadioGroup<int>(
+        name: widgetName,
+        options: const [
+          FormBuilderFieldOption(key: ValueKey('1'), value: 1),
+          FormBuilderFieldOption(key: ValueKey('2'), value: 2),
+          FormBuilderFieldOption(key: ValueKey('3'), value: 3),
+        ],
+      );
+      await tester.pumpWidget(buildTestableFieldWidget(testWidget));
+
+      expect(formSave(), isTrue);
+      expect(formValue(widgetName), isNull);
+      await tester.tap(find.byKey(const ValueKey('1')));
+      await tester.pumpAndSettle();
+      expect(formSave(), isTrue);
+      expect(formValue(widgetName), equals(1));
+      await tester.tap(find.byKey(const ValueKey('3')));
+      await tester.pumpAndSettle();
+      expect(formSave(), isTrue);
+      expect(formValue(widgetName), equals(3));
+    });
+    testWidgets('When had a disabled option then can not set this value option',
+        (WidgetTester tester) async {
+      const widgetName = 'rg1';
+      final testWidget = FormBuilderRadioGroup<int>(
+        name: widgetName,
+        disabled: [2],
+        options: const [
+          FormBuilderFieldOption(key: ValueKey('1'), value: 1),
+          FormBuilderFieldOption(key: ValueKey('2'), value: 2),
+          FormBuilderFieldOption(key: ValueKey('3'), value: 3),
+        ],
+      );
+      await tester.pumpWidget(buildTestableFieldWidget(testWidget));
+
+      expect(formSave(), isTrue);
+      expect(formValue(widgetName), isNull);
+      await tester.tap(find.byKey(const ValueKey('2')));
+      await tester.pumpAndSettle();
+      expect(formSave(), isTrue);
+      expect(formValue(widgetName), isNull);
+    });
+
+    testWidgets('decoration horizontal', (WidgetTester tester) async {
+      const widgetName = 'rg1';
+      final testWidget = FormBuilderRadioGroup<int>(
+        name: widgetName,
+        orientation: OptionsOrientation.horizontal,
+        wrapSpacing: 10.0,
+        options: const [
+          FormBuilderFieldOption(key: ValueKey('1'), value: 1),
+          FormBuilderFieldOption(key: ValueKey('2'), value: 2),
+        ],
+        itemDecoration:
+            BoxDecoration(border: Border.all(color: Colors.blueAccent)),
+      );
+      await tester.pumpWidget(buildTestableFieldWidget(testWidget));
+
+      // this is a brittle test knowing how we use container for a border
+      // there is one container for each option
+      expect(find.byType(Container), findsExactly(2));
+      // same as wrapSpacing
+      Container foo = tester.firstWidget(find.byType(Container));
+      expect(foo.margin, const EdgeInsets.only(right: 10.0));
+      // verify separator counts
+      expect(find.byType(VerticalDivider), findsNothing);
+    });
+
+    testWidgets('decoration vertical', (WidgetTester tester) async {
+      const widgetName = 'rg1';
+      final testWidget = FormBuilderRadioGroup<int>(
+        name: widgetName,
+        orientation: OptionsOrientation.vertical,
+        wrapSpacing: 10.0,
+        options: const [
+          FormBuilderFieldOption(key: ValueKey('1'), value: 1),
+          FormBuilderFieldOption(key: ValueKey('2'), value: 2),
+        ],
+        itemDecoration:
+            BoxDecoration(border: Border.all(color: Colors.blueAccent)),
+      );
+      await tester.pumpWidget(buildTestableFieldWidget(testWidget));
+
+      // this is a brittle test knowing how we use container for a border
+      // there is one container for each option
+      expect(find.byType(Container), findsExactly(2));
+      // same as wrapSpacing
+      Container foo = tester.firstWidget(find.byType(Container));
+      expect(foo.margin, const EdgeInsets.only(bottom: 10.0));
+      // verify separator counts
+      expect(find.byType(VerticalDivider), findsNothing);
+    });
+
+    testWidgets('separators horizontal', (WidgetTester tester) async {
+      const widgetName = 'rg1';
+      final testWidget = FormBuilderRadioGroup<int>(
+        name: widgetName,
+        orientation: OptionsOrientation.horizontal,
+        wrapSpacing: 10.0,
+        options: const [
+          FormBuilderFieldOption(key: ValueKey('1'), value: 1),
+          FormBuilderFieldOption(key: ValueKey('2'), value: 2),
+          FormBuilderFieldOption(key: ValueKey('3'), value: 2),
+        ],
+        separator: const VerticalDivider(width: 8.0, color: Colors.red),
+      );
+      await tester.pumpWidget(buildTestableFieldWidget(testWidget));
+
+      // verify separator counts
+      expect(find.byType(VerticalDivider), findsNWidgets(2));
+    });
+
+    testWidgets('separators vertical', (WidgetTester tester) async {
+      const widgetName = 'rg1';
+      final testWidget = FormBuilderRadioGroup<int>(
+        name: widgetName,
+        orientation: OptionsOrientation.vertical,
+        wrapSpacing: 10.0,
+        options: const [
+          FormBuilderFieldOption(key: ValueKey('1'), value: 1),
+          FormBuilderFieldOption(key: ValueKey('2'), value: 2),
+          FormBuilderFieldOption(key: ValueKey('2'), value: 2),
+        ],
+        itemDecoration: BoxDecoration(
+          border: Border.all(color: Colors.blueAccent),
+        ),
+        separator: const VerticalDivider(width: 8.0, color: Colors.red),
+      );
+      await tester.pumpWidget(buildTestableFieldWidget(testWidget));
+
+      // verify separator counts
+      expect(find.byType(VerticalDivider), findsNWidgets(2));
+    });
+    testWidgets('When press tab, field will be focused',
+        (WidgetTester tester) async {
+      const widgetName = 'key';
+      final testWidget = FormBuilderRadioGroup<int>(
+        name: widgetName,
+        options: const [
+          FormBuilderFieldOption(key: ValueKey('1'), value: 1),
+          FormBuilderFieldOption(key: ValueKey('2'), value: 2),
+          FormBuilderFieldOption(key: ValueKey('3'), value: 3),
+        ],
+      );
+      final widgetFinder = find.byWidget(testWidget);
+
+      await tester.pumpWidget(buildTestableFieldWidget(testWidget));
+      final focusNode =
+          formKey.currentState?.fields[widgetName]?.effectiveFocusNode;
+
+      expect(formSave(), isTrue);
+      expect(formValue(widgetName), isNull);
+      expect(Focus.of(tester.element(widgetFinder)).hasFocus, false);
+      expect(focusNode?.hasFocus, false);
+      await tester.sendKeyEvent(LogicalKeyboardKey.tab);
+      await tester.pumpAndSettle();
+      expect(Focus.of(tester.element(widgetFinder)).hasFocus, true);
+      expect(focusNode?.hasFocus, true);
+    });
+  });
+}
diff --git a/test/form_builder_range_slider_test.dart b/test/src/fields/form_builder_range_slider_test.dart
similarity index 68%
rename from test/form_builder_range_slider_test.dart
rename to test/src/fields/form_builder_range_slider_test.dart
index a83a64577c..e549e4a63f 100644
--- a/test/form_builder_range_slider_test.dart
+++ b/test/src/fields/form_builder_range_slider_test.dart
@@ -1,11 +1,12 @@
 import 'package:flutter/material.dart';
+import 'package:flutter/services.dart';
 import 'package:flutter_form_builder/flutter_form_builder.dart';
 import 'package:flutter_test/flutter_test.dart';
 
-import 'form_builder_tester.dart';
+import '../../form_builder_tester.dart';
 
 void main() {
-  group('FormBuilderRangeSlider --', () {
+  group('FormBuilderRangeSlider -', () {
     testWidgets('basic', (WidgetTester tester) async {
       const widgetName = 'formBuilderRangeSlider';
       final testWidget = FormBuilderRangeSlider(
@@ -61,6 +62,25 @@ void main() {
       expect(formValue<RangeValues>(widgetName), const RangeValues(11.0, 18.0));
     });
 
+    testWidgets('when set valueWidget then show on FormBuilderRangeSlider',
+        (WidgetTester tester) async {
+      const widgetName = 'formBuilderRangeSlider';
+      final keyValueWidget = Key('valueWidget');
+      final testWidget = FormBuilderRangeSlider(
+        name: widgetName,
+        min: 10.0,
+        max: 20.0,
+        valueWidget: (value) => Text(value, key: keyValueWidget),
+        initialValue: const RangeValues(14.0, 18.0),
+      );
+      await tester.pumpWidget(buildTestableFieldWidget(testWidget));
+
+      expect(formSave(), isTrue);
+      expect(formValue<RangeValues?>(widgetName),
+          equals(const RangeValues(14.0, 18.0)));
+      expect(find.byKey(keyValueWidget), findsOneWidget);
+    });
+
     testWidgets('Stateful Update', (WidgetTester tester) async {
       const widgetName = 'formBuilderRangeSlider';
       const testWidget = _FormBuilderRangeSliderStateTest(widgetName);
@@ -81,6 +101,31 @@ void main() {
         equals(const RangeValues(-9.0, 9.0)),
       );
     });
+
+    testWidgets('When press tab, field will be focused',
+        (WidgetTester tester) async {
+      const widgetName = 'key';
+      final testWidget = FormBuilderRangeSlider(
+        name: widgetName,
+        min: 10.0,
+        max: 20.0,
+      );
+      final widgetFinder = find.byWidget(testWidget);
+
+      await tester.pumpWidget(buildTestableFieldWidget(testWidget));
+      final focusNode =
+          formKey.currentState?.fields[widgetName]?.effectiveFocusNode;
+
+      expect(formSave(), isTrue);
+      expect(formValue<RangeValues?>(widgetName),
+          equals(const RangeValues(10.0, 10.0)));
+      expect(Focus.of(tester.element(widgetFinder)).hasFocus, false);
+      expect(focusNode?.hasFocus, false);
+      await tester.sendKeyEvent(LogicalKeyboardKey.tab);
+      await tester.pumpAndSettle();
+      expect(Focus.of(tester.element(widgetFinder)).hasFocus, true);
+      expect(focusNode?.hasFocus, true);
+    });
   });
 }
 
diff --git a/test/src/fields/form_builder_slider_test.dart b/test/src/fields/form_builder_slider_test.dart
new file mode 100644
index 0000000000..3f6d8b4d87
--- /dev/null
+++ b/test/src/fields/form_builder_slider_test.dart
@@ -0,0 +1,56 @@
+import 'package:flutter/material.dart';
+import 'package:flutter/services.dart';
+import 'package:flutter_form_builder/src/fields/form_builder_slider.dart';
+import 'package:flutter_test/flutter_test.dart';
+import '../../form_builder_tester.dart';
+
+void main() {
+  group('FormBuilderSlider -', () {
+    testWidgets('Basic', (WidgetTester tester) async {
+      const widgetName = 'slider1';
+      final testWidget = FormBuilderSlider(
+        name: widgetName,
+        initialValue: 2,
+        min: 0,
+        max: 10,
+        divisions: 20,
+        decoration: const InputDecoration(
+          labelText: 'Number of things',
+        ),
+      );
+      await tester.pumpWidget(buildTestableFieldWidget(testWidget));
+
+      expect(formSave(), isTrue);
+      expect(formValue(widgetName), equals(2.0));
+      await tester.tap(find.byType(Slider));
+      await tester.pumpAndSettle();
+      expect(formSave(), isTrue);
+      expect(formValue(widgetName), equals(5.0));
+    });
+
+    testWidgets('When press tab, field will be focused',
+        (WidgetTester tester) async {
+      const widgetName = 'key';
+      final testWidget = FormBuilderSlider(
+        name: widgetName,
+        initialValue: 2,
+        min: 0,
+        max: 10,
+      );
+      final widgetFinder = find.byWidget(testWidget);
+
+      await tester.pumpWidget(buildTestableFieldWidget(testWidget));
+      final focusNode =
+          formKey.currentState?.fields[widgetName]?.effectiveFocusNode;
+
+      expect(formSave(), isTrue);
+      expect(formValue(widgetName), equals(2.0));
+      expect(Focus.of(tester.element(widgetFinder)).hasFocus, false);
+      expect(focusNode?.hasFocus, false);
+      await tester.sendKeyEvent(LogicalKeyboardKey.tab);
+      await tester.pumpAndSettle();
+      expect(Focus.of(tester.element(widgetFinder)).hasFocus, true);
+      expect(focusNode?.hasFocus, true);
+    });
+  });
+}
diff --git a/test/src/fields/form_builder_switch_test.dart b/test/src/fields/form_builder_switch_test.dart
new file mode 100644
index 0000000000..161e3165bf
--- /dev/null
+++ b/test/src/fields/form_builder_switch_test.dart
@@ -0,0 +1,56 @@
+import 'package:flutter/material.dart';
+import 'package:flutter/services.dart';
+import 'package:flutter_form_builder/src/fields/form_builder_switch.dart';
+import 'package:flutter_test/flutter_test.dart';
+import '../../form_builder_tester.dart';
+
+void main() {
+  group('FormBuilderSwitch -', () {
+    testWidgets('Off/On/Off', (WidgetTester tester) async {
+      const widgetName = 'switch1';
+      final testWidget = FormBuilderSwitch(
+        name: widgetName,
+        title: const Text('Switch 1'),
+        initialValue: false,
+      );
+      final widgetFinder = find.byWidget(testWidget);
+
+      await tester.pumpWidget(buildTestableFieldWidget(testWidget));
+
+      expect(formSave(), isTrue);
+      expect(formValue(widgetName), isFalse);
+      await tester.tap(widgetFinder);
+      await tester.pumpAndSettle();
+      expect(formSave(), isTrue);
+      expect(formValue(widgetName), isTrue);
+      await tester.tap(widgetFinder);
+      await tester.pumpAndSettle();
+      expect(formSave(), isTrue);
+      expect(formValue(widgetName), isFalse);
+    });
+
+    testWidgets('When press tab, field will be focused',
+        (WidgetTester tester) async {
+      const widgetName = 'cb1';
+      final testWidget = FormBuilderSwitch(
+        name: widgetName,
+        title: const Text('Switch 1'),
+        initialValue: false,
+      );
+      final widgetFinder = find.byWidget(testWidget);
+
+      await tester.pumpWidget(buildTestableFieldWidget(testWidget));
+      final focusNode =
+          formKey.currentState?.fields[widgetName]?.effectiveFocusNode;
+
+      expect(formSave(), isTrue);
+      expect(formValue(widgetName), isFalse);
+      expect(Focus.of(tester.element(widgetFinder)).hasFocus, false);
+      expect(focusNode?.hasFocus, false);
+      await tester.sendKeyEvent(LogicalKeyboardKey.tab);
+      await tester.pumpAndSettle();
+      expect(Focus.of(tester.element(widgetFinder)).hasFocus, true);
+      expect(focusNode?.hasFocus, true);
+    });
+  });
+}
diff --git a/test/src/fields/form_builder_text_field_test.dart b/test/src/fields/form_builder_text_field_test.dart
new file mode 100644
index 0000000000..7aedc8500c
--- /dev/null
+++ b/test/src/fields/form_builder_text_field_test.dart
@@ -0,0 +1,123 @@
+import 'package:flutter/material.dart';
+import 'package:flutter/services.dart';
+import 'package:flutter_form_builder/flutter_form_builder.dart';
+import 'package:flutter_test/flutter_test.dart';
+
+import '../../form_builder_tester.dart';
+
+void main() {
+  group('FormBuilderTextField -', () {
+    testWidgets('Hello Planet', (WidgetTester tester) async {
+      const newTextValue = 'Hello 🪐';
+      const textFieldName = 'text1';
+      final testWidget = FormBuilderTextField(
+        name: textFieldName,
+      );
+      final widgetFinder = find.byWidget(testWidget);
+
+      await tester.pumpWidget(buildTestableFieldWidget(testWidget));
+      expect(formSave(), isTrue);
+      expect(formValue(textFieldName), isNull);
+      await tester.enterText(widgetFinder, newTextValue);
+      expect(formSave(), isTrue);
+      expect(formValue(textFieldName), equals(newTextValue));
+      await tester.enterText(widgetFinder, '');
+      expect(formSave(), isTrue);
+      expect(formValue(textFieldName), isEmpty);
+    });
+    testWidgets(
+      'without initialValue',
+      (tester) => _testFormBuilderTextFieldWithInitialValue(
+        tester,
+      ),
+    );
+    testWidgets(
+      'has initialValue on Field',
+      (tester) => _testFormBuilderTextFieldWithInitialValue(
+        tester,
+        initialValueOnField: 'ok',
+      ),
+    );
+    testWidgets(
+      'has initialValue on Form',
+      (tester) => _testFormBuilderTextFieldWithInitialValue(
+        tester,
+        initialValueOnForm: 'ok',
+      ),
+    );
+
+    testWidgets(
+      'triggers onTapOutside',
+      (tester) => _testFormBuilderTextFieldOnTapOutsideCallback(tester),
+    );
+    testWidgets('When press tab, field will be focused',
+        (WidgetTester tester) async {
+      const widgetName = 'cb1';
+      var testWidget = FormBuilderTextField(
+        name: widgetName,
+      );
+      final widgetFinder = find.byWidget(testWidget);
+
+      await tester.pumpWidget(buildTestableFieldWidget(testWidget));
+      final focusNode =
+          formKey.currentState?.fields[widgetName]?.effectiveFocusNode;
+
+      expect(formSave(), isTrue);
+      expect(formValue(widgetName), isNull);
+      expect(Focus.of(tester.element(widgetFinder)).hasFocus, false);
+      expect(focusNode?.hasFocus, false);
+      await tester.sendKeyEvent(LogicalKeyboardKey.tab);
+      await tester.pumpAndSettle();
+      expect(Focus.of(tester.element(widgetFinder)).hasFocus, true);
+      expect(focusNode?.hasFocus, true);
+    });
+  });
+}
+
+Future<void> _testFormBuilderTextFieldWithInitialValue(
+  WidgetTester tester, {
+  String? initialValueOnField,
+  String? initialValueOnForm,
+}) async {
+  int changedCount = 0;
+  const newTextValue = 'Hello 🪐';
+  const textFieldName = 'text1';
+
+  var testWidget = FormBuilderTextField(
+    name: textFieldName,
+    initialValue: initialValueOnField,
+    onChanged: (String? value) => changedCount++,
+  );
+  await tester.pumpWidget(buildTestableFieldWidget(
+    testWidget,
+    initialValue: {
+      textFieldName: initialValueOnForm,
+    },
+  ));
+  expect(formSave(), isTrue);
+  expect(formValue(textFieldName), initialValueOnField ?? initialValueOnForm);
+  expect(changedCount, 0);
+
+  await tester.enterText(find.byWidget(testWidget), newTextValue);
+  expect(formSave(), isTrue);
+  expect(formValue(textFieldName), newTextValue);
+
+  expect(changedCount, 1);
+}
+
+Future<void> _testFormBuilderTextFieldOnTapOutsideCallback(
+    WidgetTester tester) async {
+  const textFieldName = 'Hello 🪐';
+  bool triggered = false;
+
+  var testWidget = FormBuilderTextField(
+    name: textFieldName,
+    onTapOutside: (event) => triggered = true,
+  );
+  await tester.pumpWidget(buildTestableFieldWidget(
+    testWidget,
+  ));
+  final textField = tester.firstWidget(find.byType(TextField)) as TextField;
+  textField.onTapOutside?.call(const PointerDownEvent());
+  expect(triggered, true);
+}
diff --git a/test/src/form_builder_field_test.dart b/test/src/form_builder_field_test.dart
index 24ce41ffc4..ebe6442bc6 100644
--- a/test/src/form_builder_field_test.dart
+++ b/test/src/form_builder_field_test.dart
@@ -164,7 +164,6 @@ void main() {
         expect(textFieldKey.currentState?.valueHasError, isTrue);
       });
     });
-
     group('autovalidateMode -', () {
       testWidgets(
           'Should show error when init form and AutovalidateMode is always',
@@ -201,7 +200,6 @@ void main() {
         expect(find.text(errorTextField), findsOneWidget);
       });
     });
-
     group('isDirty - ', () {
       testWidgets('Should not dirty by default', (tester) async {
         const textFieldName = 'text';
@@ -301,7 +299,6 @@ void main() {
         expect(textFieldKey.currentState?.isDirty, false);
       });
     });
-
     group('isTouched - ', () {
       testWidgets('Should not touched by default', (tester) async {
         const textFieldName = 'text';
@@ -325,7 +322,6 @@ void main() {
         expect(textFieldKey.currentState?.isTouched, true);
       });
     });
-
     group('reset -', () {
       testWidgets('Should reset to null when call reset', (tester) async {
         const textFieldName = 'text';
@@ -378,5 +374,56 @@ void main() {
         expect(find.text(errorTextField), findsNothing);
       });
     });
+    group('focus -', () {
+      testWidgets('Should focus on field when invalidate it', (tester) async {
+        final textFieldKey = GlobalKey<FormBuilderFieldState>();
+        const widgetName = 'text';
+        const errorTextField = 'error text field';
+        final testWidget = FormBuilderTextField(
+          name: widgetName,
+          key: textFieldKey,
+        );
+        final widgetFinder = find.byWidget(testWidget);
+
+        await tester.pumpWidget(buildTestableFieldWidget(testWidget));
+        final focusNode =
+            formKey.currentState?.fields[widgetName]?.effectiveFocusNode;
+
+        expect(Focus.of(tester.element(widgetFinder)).hasFocus, false);
+        expect(focusNode?.hasFocus, false);
+
+        textFieldKey.currentState?.invalidate(errorTextField);
+        await tester.pumpAndSettle();
+
+        expect(Focus.of(tester.element(widgetFinder)).hasFocus, true);
+        expect(focusNode?.hasFocus, true);
+      });
+      testWidgets(
+          'Should not focus on field when invalidate field and is disabled',
+          (tester) async {
+        final textFieldKey = GlobalKey<FormBuilderFieldState>();
+        const widgetName = 'text';
+        const errorTextField = 'error text field';
+        final testWidget = FormBuilderTextField(
+          name: widgetName,
+          key: textFieldKey,
+          enabled: false,
+        );
+        final widgetFinder = find.byWidget(testWidget);
+
+        await tester.pumpWidget(buildTestableFieldWidget(testWidget));
+        final focusNode =
+            formKey.currentState?.fields[widgetName]?.effectiveFocusNode;
+
+        expect(Focus.of(tester.element(widgetFinder)).hasFocus, false);
+        expect(focusNode?.hasFocus, false);
+
+        textFieldKey.currentState?.invalidate(errorTextField);
+        await tester.pumpAndSettle();
+
+        expect(Focus.of(tester.element(widgetFinder)).hasFocus, false);
+        expect(focusNode?.hasFocus, false);
+      });
+    });
   });
 }
diff --git a/test/src/form_builder_test.dart b/test/src/form_builder_test.dart
index db9e59e404..93ec7257ad 100644
--- a/test/src/form_builder_test.dart
+++ b/test/src/form_builder_test.dart
@@ -183,7 +183,7 @@ void main() {
 
   group('skipDisabled -', () {
     testWidgets(
-        'Should not show error when field is not enabled and skipDisabled is true',
+        'Should not show error when field is disabled and skipDisabled is true',
         (tester) async {
       const textFieldName = 'text3';
       const errorTextField = 'error text field';
@@ -206,7 +206,7 @@ void main() {
       expect(find.text(errorTextField), findsNothing);
     });
     testWidgets(
-        'Should show error when field is not enabled and skipDisabled is false',
+        'Should show error when field is disabled and skipDisabled is false',
         (tester) async {
       const textFieldName = 'text4';
       const errorTextField = 'error text field';