Why doesn't the email text field have focus?
Tags: flutter, dart, programming
Published: 2023-01-26 00:06:33

My code writes the code where the email textfield needs to be focused. However, when I change the screen to the signup screen and back, the email textfield is not focused.

Here are two videos showing what I said:

![Email textfield](https://i.stack.imgur.com/3YKYe.gif)

![Keyboard](https://i.stack.imgur.com/aT1yo.gif)

As you can see, when I open the sign in screen, the keyboard pops up. When I change the screen to the sign up screen, the keyboard also pops up. However, when I change back to the sign in screen, there is no keyboard, but the email text field is weird:

![Email textfield](https://i.stack.imgur.com/CFck4.png)

![Keyboard](https://i.stack.imgur.com/zp3aa.png)

Why is this result returned?

My code:

```
enum SignInFormType { signIn, signUp }

class SignInState {
  SignInState({
    this.isSubmitted = false,
    this.isPasswordObscured = true,
    this.formType = SignInFormType.signIn,
    this.value = const AsyncValue.data(null),
  });

  final bool isSubmitted;
  final bool isPasswordObscured;
  final SignInFormType formType;

  final AsyncValue<void> value;

  bool get isLoading => value.isLoading;

  SignInState copyWith({
    bool? isSubmitted,
    bool? isPasswordObscured,
    SignInFormType? formType,
    AsyncValue<void>? value,
  }) {
    return SignInState(
      isSubmitted: isSubmitted ?? this.isSubmitted,
      isPasswordObscured: isPasswordObscured ?? this.isPasswordObscured,
      formType: formType ?? this.formType,
      value: value ?? this.value,
    );
  }
}

extension SignInScreenState on SignInState {
  String? nameValidator(String? value) {
    if (value!.trim().isEmpty) {
      return "Please enter your name";
    }
    return null;
  }

  String? emailValidator(String? value) {
    if (value!.trim().isEmpty) {
      return "Please enter your email address";
    }
    if (!RegExp(r"\S+@\S+\.\S+").hasMatch(value)) {
      return "Please enter a valid email address";
    }
    return null;
  }

  String get title {
    if (formType == SignInFormType.signIn) {
      return "Sign in";
    } else {
      return "Sign up";
    }
  }

  String get secondaryButtonText {
    if (formType == SignInFormType.signIn) {
      return "Sign up";
    } else {
      return "Sign in";
    }
  }

  SignInFormType get secondaryActionFormType {
    if (formType == SignInFormType.signUp) {
      return SignInFormType.signIn;
    } else {
      return SignInFormType.signUp;
    }
  }
}
```

----------

```
class SignInController extends StateNotifier<SignInState> {
  SignInController({required SignInFormType formType}) : super(SignInState(formType: formType));

  void updateIsSubmitted(bool isSubmitted) => state = state.copyWith(isSubmitted: isSubmitted);

  void updateIsPasswordObscured(bool isPasswordObscured) => state = state.copyWith(isPasswordObscured: isPasswordObscured);

  void updateFormType(SignInFormType formType) {
    state = state.copyWith(formType: formType);
  }
}

final signInControllerProvider = StateNotifierProvider.autoDispose.family<SignInController, SignInState, SignInFormType>(
  (ref, formType) => SignInController(formType: formType);
);
```

----------

```
class CustomTextFormField extends StatelessWidget {
  const CustomTextFormField({
    this.focusNode,
    this.textFormFieldKey,
    this.controller,
    this.validator,
    this.icon,
    required this.labelText,
    required this.hintText,
    this.suffixIcon,
    this.obscureText,
    this.keyboardType,
    this.textInputAction,
    required this.readOnly,
    this.maxLines,
    this.onEditingComplete,
    this.enabled,
    this.onChanged,
    this.onFieldSubmitted,
    this.onSaved,
    this.onTap,
    this.initialValue,
    this.autofocus,
    super.key,
  });

  final FocusNode? focusNode;
  final Key? textFormFieldKey;
  final TextEditingController? controller;
  final String? Function(String?)? validator;
  final IconData? icon;
  final String labelText;
  final String hintText;
  final Widget? suffixIcon;
  final bool? obscureText;
  final TextInputType? keyboardType;
  final TextInputAction? textInputAction;
  final bool readOnly;
  final int? maxLines;
  final VoidCallback? onEditingComplete;
  final bool? enabled;
  final Function(String)? onChanged;
  final Function(String)? onFieldSubmitted;
  final Function(String?)? onSaved;
  final VoidCallback? onTap;
  final String? initialValue;
  final bool? autofocus;

  @override
  Widget build(BuildContext context) => Theme(
        data: ThemeData().copyWith(colorScheme: ThemeData().colorScheme.copyWith(primary: Colors.black.withOpacity(0.5))),
        child: TextFormField(
          autofocus: autofocus ?? false,
          focusNode: focusNode,
          key: textFormFieldKey,
          controller: controller,
          validator: validator,
          style: const TextStyle(color: Colors.black),
          textAlignVertical: TextAlignVertical.top,
          initialValue: initialValue,
          decoration: InputDecoration(
            alignLabelWithHint: true,
            floatingLabelAlignment: FloatingLabelAlignment.start,
            prefixIcon: icon == null ? null : Icon(icon, color: Colors.black),
            labelText: labelText,
            labelStyle: const TextStyle(color: Colors.black),
            hintText: hintText,
            hintStyle: const TextStyle(color: Colors.black),
            border: const OutlineInputBorder(),
            focusedBorder: const OutlineInputBorder(borderSide: BorderSide(color: Colors.black, width: 1.0)),
            enabledBorder: const OutlineInputBorder(borderSide: BorderSide(color: Colors.black, width: 1.0)),
            suffixIcon: suffixIcon,
            filled: true,
            fillColor: Colors.white,
          ),
          autocorrect: false,
          obscureText: obscureText == null ? false : obscureText!,
          keyboardType: keyboardType,
          textInputAction: textInputAction,
          readOnly: readOnly,
          maxLines: maxLines,
          onEditingComplete: onEditingComplete,
          enabled: enabled,
          onChanged: onChanged,
          onFieldSubmitted: onFieldSubmitted,
          onSaved: onSaved,
          onTap: onTap,
        ),
      );
}
```

----------

```
class SignInScreen extends ConsumerStatefulWidget {
  const SignInScreen({required this.formType, super.key});

  final SignInFormType formType;

  @override
  ConsumerState<SignInScreen> createState() => _SignInScreenState();
}

class _SignInScreenState extends ConsumerState<SignInScreen> {
  final formKey = GlobalKey<FormState>();

  final emailFocusNode = FocusNode();
  final nameFocusNode = FocusNode();

  final nameController = TextEditingController();
  final emailController = TextEditingController();
  final passwordController = TextEditingController();

  void updateFormType(SignInFormType formType) {
    ref.read(signInControllerProvider(widget.formType).notifier).updateFormType(formType);

    passwordController.clear();
  }

  @override
  void initState() {
    emailFocusNode.requestFocus();
    super.initState();
  }

  @override
  void dispose() {
    nameFocusNode.dispose();
    emailFocusNode.dispose();
    nameController.dispose();
    emailController.dispose();
    passwordController.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    final state = ref.watch(signInControllerProvider(widget.formType));
    final controller = ref.read(signInControllerProvider(widget.formType).notifier);

    return Scaffold(
      appBar: AppBar(title: Text(state.title)),
      body: Padding(
        padding: const EdgeInsets.all(10.0),
        child: Form(
          key: formKey,
          child: SingleChildScrollView(
            child: Column(
              children: [
                state.secondaryActionFormType == SignInFormType.signUp
                    ? Container()
                    : CustomTextFormField(
                        focusNode: nameFocusNode,
                        controller: nameController,
                        validator: (value) => state.nameValidator(value),
                        icon: FontAwesomeIcons.solidUser,
                        labelText: "Name",
                        hintText: "Type your name here...",
                        keyboardType: TextInputType.name,
                        textInputAction: TextInputAction.next,
                        readOnly: state.isSubmitted ? true : false,
                      ),
                state.secondaryActionFormType == SignInFormType.signUp ? Container() : const SizedBox(height: 10.0),
                CustomTextFormField(
                  focusNode: emailFocusNode,
                  controller: emailController,
                  validator: (value) => state.emailValidator(value),
                  icon: Icons.email,
                  labelText: "Email",
                  hintText: "Type your email here...",
                  keyboardType: TextInputType.emailAddress,
                  textInputAction: TextInputAction.next,
                  readOnly: state.isSubmitted,
                ),
                …
                InkWell(
                  onTap: state.isSubmitted == true
                      ? null
                      : () {
                          updateFormType(state.secondaryActionFormType);
                          if (state.formType == signInFormType.signIn) {
                            emailFocusNode.unfocus();
                            nameFocusNode.requestFocus();
                          } else {
                            nameFocusNode.unfocus();
                            emailFocusNode.requestFocus();
                          }
                        },
                  child: Text(state.secondaryButtonText, textAlign: TextAlign.center, style: const TextStyle(color: Colors.black)),
                ),
              ],
            ),
          ),
        ),
      ),
    );
  }
}
```

Feel free to leave a comment if you need more information.

Why doesn't the email text field have focus? I would appreciate any help. Thank you in advance!