skip to Main Content

After Material 3, default TextField border and label color (when focused) were changed to grey. So I needed to set my ThemeData as below. If the TextField is empty, there’s a hint inside it with light gray color, which is desired behaviour. When I focus the TextField the label is now red at the top of the TextField. The problem arrives when I unfocus it and the color of the label text remains red, whereas border color is light gray.

My desired behavior would be the label color turning light gray, instead of red. I know I can do it programmatically but I have several TextFields on my app rendering it unpractical. Let’s note that on material 2 it worked like desired just by setting primary color.

      theme: ThemeData(
        brightness: Brightness.light,
        primarySwatch: Colors.red,
        elevatedButtonTheme: ElevatedButtonThemeData(
          style: ElevatedButton.styleFrom(
            backgroundColor: Colors.red,
            foregroundColor: Colors.white,
          ),
        ),
        inputDecorationTheme: InputDecorationTheme(
          floatingLabelStyle: TextStyle(color: Colors.red),
          border: OutlineInputBorder(borderRadius: BorderRadius.circular(10), borderSide: BorderSide()),
          focusedBorder: OutlineInputBorder(
            borderRadius: BorderRadius.circular(10),
            borderSide: BorderSide(color: Colors.red, width: 2),
          ),
        ),
        textSelectionTheme: TextSelectionThemeData(cursorColor: Colors.red),
      ),

2

Answers


  1. You can use FocusScope && Focus Widgets to handle this issue.

    Main Widget :

    class ChangeFocuseColorWidget extends StatefulWidget {
      const ChangeFocuseColorWidget({super.key});
    
      @override
      State<ChangeFocuseColorWidget> createState() =>
          _ChangeFocuseColorWidgetState();
    }
    
    class _ChangeFocuseColorWidgetState extends State<ChangeFocuseColorWidget> {
      late final TextEditingController _firstController;
      late final TextEditingController _secondController;
      @override
      void initState() {
        _firstController = TextEditingController();
        _secondController = TextEditingController();
        super.initState();
      }
    
     @override
      void dispose() {
        _firstController.dispose();
        _secondController.dispose();
        super.dispose();
      }
    
      @override
      Widget build(BuildContext context) {
        return Scaffold(
          appBar: AppBar(
            title: const Text("Focuse Color"),
          ),
          body: Column(
            children: <Widget>[
              const Icon(
                Icons.lock,
                size: 100,
              ),
              SizedBox(
                height: context.screenHeight * .07,
              ),
              Expanded(
                child: SingleChildScrollView(
                  child: Column(
                    children: [
                      FocuseTestWidget(
                        controller: _firstController,
                        title: "Username",
                        lable: "Your Name",
                      ),
                      SizedBox(
                        height: context.screenHeight * .05,
                      ),
                      FocuseTestWidget(
                        controller: _secondController,
                        title: "Email",
                        lable: "Your Email",
                      ),
                    ],
                  ),
                ),
              ),
            ],
          ),
        );
      }
    }
    

    The reusable TextFeild widget

    
    class FocuseTestWidget extends StatefulWidget {
      const FocuseTestWidget({
        super.key,
        required this.controller,
        required this.title,
        required this.lable,
      });
      final TextEditingController controller;
      final String title;
      final String lable;
    
      @override
      State<FocuseTestWidget> createState() => _FocuseTestWidgetState();
    }
    
    class _FocuseTestWidgetState extends State<FocuseTestWidget> {
      Color? lableColor = Colors.grey;
    
      void _changeLableColor({required bool isFocus}) {
        if (isFocus) {
          setState(() {
            lableColor = Colors.orange;
          });
        } else {
          setState(() {
            lableColor = Colors.grey;
          });
        }
      }
    
      @override
      Widget build(BuildContext context) {
        return Column(
          children: <Widget>[
            Padding(
              padding: const EdgeInsets.symmetric(
                horizontal: 10.0,
              ),
              child: Row(
                mainAxisAlignment: MainAxisAlignment.start,
                children: <Widget>[
                  Text(
                    widget.title,
                    style: const TextStyle(
                      fontSize: 17,
                      fontWeight: FontWeight.bold,
                    ),
                  ),
                ],
              ),
            ),
            const SizedBox(
              height: 20,
            ),
            FocusScope(
              child: Focus(
                onFocusChange: (bool isFocus) {
                  _changeLableColor(isFocus: isFocus);
                },
                child: Padding(
                  padding: const EdgeInsets.symmetric(
                    horizontal: 10.0,
                  ),
                  child: TextField(
                    controller: widget.controller,
                    keyboardType: TextInputType.text,
                    decoration: AppStyle.customInputDecoration(
                      lable: widget.lable,
                      lableColor: lableColor!,
                    ),
                  ),
                ),
              ),
            ),
          ],
        );
      }
    }
    
    

    You can use InputDecoration() directly in TextFeild or separate it like this so you can reuse it (which is better)

    
    class AppStyle {
      static InputDecoration customInputDecoration({
        required String lable,
        required Color lableColor,
      }) {
        return InputDecoration(
          filled: true,
          fillColor: const Color(0xFFEFECEC),
          label: Text(
            lable,
            style: TextStyle(
              color: lableColor,
            ),
          ),
          focusedBorder: OutlineInputBorder(
            borderRadius: BorderRadius.circular(10),
            borderSide: const BorderSide(
              color: Colors.orange,
              width: 1,
            ),
          ),
          enabledBorder: OutlineInputBorder(
            borderRadius: BorderRadius.circular(10),
            borderSide: const BorderSide(
              color: Colors.transparent,
              width: 0,
            ),
          ),
        );
      }
    }
    
    

    Hope that help you !!

    Login or Signup to reply.
  2. This issue is interesting, I think I should add enableFloatingLabelStyle but in the meantime what occurs to me is to use the MaterialStateTextStyle to obtain the desired result.

          theme: ThemeData(
            brightness: Brightness.light,
            primarySwatch: Colors.red,
            elevatedButtonTheme: ElevatedButtonThemeData(
              style: ElevatedButton.styleFrom(
                backgroundColor: Colors.red,
                foregroundColor: Colors.white,
              ),
            ),
            inputDecorationTheme: InputDecorationTheme(
              // floatingLabelStyle: const TextStyle(color: Colors.red),
              // use material state to change the color of the floating label
              floatingLabelStyle: MaterialStateTextStyle.resolveWith((states) {
                if (states.contains(MaterialState.focused)) {
                  return const TextStyle(color: Colors.red);
                }
                return const TextStyle(color: Colors.grey);
              }),
              //
              border: OutlineInputBorder(
                  borderRadius: BorderRadius.circular(10),
                  borderSide: const BorderSide()),
              focusedBorder: OutlineInputBorder(
                borderRadius: BorderRadius.circular(10),
                borderSide: const BorderSide(color: Colors.red, width: 2),
              ),
            ),
            textSelectionTheme:
                const TextSelectionThemeData(cursorColor: Colors.red),
          ),
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search