Skip to content

Extra vertical padding surrounding DropdownButtonFormField when compared to TextField #60624

Open

Description

@HansMuller

This issue was original reported by @cassioseffrin in #46844 (comment)


@shihaohong take a look:

Screen Shot 2020-06-30 at 10 58 17

the 1st field (price) is a common TextField with OutlineInputBorder border;
the 2nd field (unit) is a DropdownButtonFormField with OutlineInputBorder border;

Even with isDense=true there is an extra padding (8 pixes in total: 4 on top, 4 on bottom) between the labelText and the widget that wraps the labelText and the Icon

in dropdown.dart line 1284 there is a method that calculates the height, the result is 24 if I set it to 16 the DropdownButtonFormField render the same height of the TextField, however I think it's not correct to set it as a constant. I can't figure out where this 8 pixels of extra padding were created.

Line 1284 of dropdown.dart.

  double get _denseButtonHeight {
    final double fontSize =
        _textStyle.fontSize ?? Theme.of(context).textTheme.subtitle1.fontSize;
    return math.max(fontSize, math.max(widget.iconSize, _kDenseButtonHeight));
  }

I am in last stable release of Flutter (Channel stable, v1.17.4)


@HansMuller, I don't think it's related to #59196, in this case the Text height is exactly the same. I actually have made a correction in the widget dropdown.dart, just 1 line of code. May I could make a PR?

The problem is the icon size calculation, the resulting height is stretching all the DropdownButtonFormField: see the results, both components are now with exactly the same height.
Screen Shot 2020-06-30 at 14 44 21

Here without debug paint:
Screen Shot 2020-06-30 at 15 04 14

Activity

  1. HansMuller commented on Jun 30, 2020

    @HansMuller
    ContributorAuthor

    This may be due to the padding added to the icon buttons to ensure that their hit area is 48x48.

  2. added
    p: material_uimaterial_ui package in flutter/packages
    frameworkflutter/packages/flutter repository. See also f: labels.
    on Jul 1, 2020
  3. cassioseffrin commented on Jul 1, 2020

    @cassioseffrin

    I think the real problem is in InputDecoration, according with the flutter docs: If isOutline property of [border] is true then contentPaddding is EdgeInsets.fromLTRB(12, 20, 12, 12) when [isDense] is true and EdgeInsets.fromLTRB(12, 24, 12, 16) when [isDense] is false.

    According with the docs the default padding for an InputDecoration with outline border and isDense equals to true must be EdgeInsets.fromLTRB(12, 20, 12, 12). For some reason it's not rendering.

    If I set the contentPadding of InputDecoration to EdgeInsets.fromLTRB(12, 22, 12, 14), It's rendering with exactly the same height of an ordinary TextField with outline border, without any changes in dropdown.dart.

    Here is the the reduced version of my DropdownButtonFormField wrapped in a StreamBuilder. I also use the isExpanded: true, and the Text with overflow TextOverflow.ellipsis, but these properties doesn't have any side effect, I have already tested without them.

    DropdownButtonHideUnderline(
        child: Container(
      child: StreamBuilder<List<ProductUnit>>(
        stream: _blocProduct.lstProductUnitController,
        builder: (context, snapshot) {
          if (snapshot.hasData) {
            return DropdownButtonFormField ProductUnit>(
              isExpanded: true,
              isDense: true,
              value: _unidadeMedidaSelecionada,
              decoration: InputDecoration(
                border: OutlineInputBorder(
                  borderRadius: BorderRadius.all(
                    Radius.circular(5),
                  ),
                ),
                **contentPadding: EdgeInsets.fromLTRB(12, 22, 12, 14),**
                hintText: "Unit",
                labelText: "Unit",
              ),
              onChanged: (ProductUnit _unit) {
                _blocProduct.setProductUnit( _unit);
                FocusScope.of(context).requestFocus(FocusNode());
              },
              items:
                  snapshot.data.map((ProductUnit e) {
                return new DropdownMenuItem<ProductUnit>(
                  value: e,
                  child: new Text(e.name, overflow: TextOverflow.ellipsis),
                );
              }).toList(),
            );
          } else {
            return CircularProgressIndicator();
          }
        },
      ),
    )),
    
  4. shihaohong commented on Jul 6, 2020

    @shihaohong
    Contributor

    Screenshot_1594028585

    Reproducible sample:

    import 'package:flutter/material.dart';
    
    void main() {
      runApp(MyApp());
    }
    
    class MyApp extends StatelessWidget {
      @override
      Widget build(BuildContext context) {
        return MaterialApp(
          title: 'Text Field Height Padding',
          theme: ThemeData(
            visualDensity: VisualDensity.adaptivePlatformDensity,
          ),
          home: MyHomePage(),
        );
      }
    }
    
    class MyHomePage extends StatefulWidget {
      MyHomePage({Key key}) : super(key: key);
      @override
      _MyHomePageState createState() => _MyHomePageState();
    }
    
    class _MyHomePageState extends State<MyHomePage> {
      @override
      Widget build(BuildContext context) {
        return Scaffold(
          appBar: AppBar(),
          body: Center(
            child: Row(
              children: <Widget>[
                Flexible(
                  child: TextField(
                    decoration: InputDecoration(
                      suffixIcon: Icon(Icons.arrow_drop_down),
                      // contentPadding and isDense are properly reflected
                      // as mentioned in the documentation
                      isDense: true,
                      // isDense: true padding value
                      contentPadding: EdgeInsets.fromLTRB(12, 20, 12, 12),
                      // isDense: false padding value
                      // contentPadding: EdgeInsets.fromLTRB(12, 24, 12, 16),
                      border: OutlineInputBorder(),
                    ),
                  ),
                ),
                Flexible(
                  child: DropdownButtonFormField(
                    decoration: InputDecoration(
                      // contentPadding and isDense are properly reflected
                      // as mentioned in the documentation
                      isDense: true,
                      // isDense: true padding value
                      contentPadding: EdgeInsets.fromLTRB(12, 20, 12, 12),
                      // isDense: false padding value
                      // contentPadding: EdgeInsets.fromLTRB(12, 24, 12, 16),
                      border: OutlineInputBorder(),
                    ),
                    onChanged: (item) {},
                    value: 1,
                    items: [
                      DropdownMenuItem(
                        value: 1,
                        child: Text('1'),
                      ),
                      DropdownMenuItem(
                        value: 2,
                        child: Text('2'),
                      ),
                      DropdownMenuItem(
                        value: 3,
                        child: Text('3'),
                      ),
                    ],
                  ),
                ),
              ],
            ),
          ),
        );
      }
    }
  5. shihaohong commented on Jul 6, 2020

    @shihaohong
    Contributor

    The real issue is as @HansMuller suggested -- For DropdownButtonFormField, the padding is applied around the Text and the Icon widgets. Since the Icon widget is taller than the text widget in DropdownButtonFormField, the outline for DropdownButtonFormField will look "taller" due to the presence of the icon.

    For the TextField, the padding is applied around only the text, but not the icon specified in InputDecorator.suffixIcon. One simple way to observe this is to play around with the left/right padding on both widgets with debug painting on to see what I mean.

    One way we could fix this is to have the DropdownButtonFormField's contentPadding behave as TextField's does. That would be a breaking change, since the padding would be applied to the right of the selected value rather than to the right of the DropdownButton icon itself.

    Edit: Actually, it seems to be from the Container calculation described above:

      double get _denseButtonHeight {
        final double fontSize =
            _textStyle.fontSize ?? Theme.of(context).textTheme.subtitle1.fontSize;
        return math.max(fontSize, math.max(widget.iconSize, _kDenseButtonHeight));
      }

    When the icon is shorter than 24.0 pixels tall, what ends up happening is that the height being prescribed to the Container that wraps the Row that contains the text and icon in DropdownButtonFormField ends up being taller than the icon and the font in the default case, which is 24.0 (_kDenseButtonHeight). However, when the icon is taller, the icon then dictates the height of the overall container, which will never be shorter than it currently is, causing DropdownButtonFormField to be taller than expected.

  6. changed the title [-]Extra padding in TextFields with OutlineInputBorder[/-] [+]Extra padding surrounding DropdownButtonFormField when compared to TextField[/+] on Jul 6, 2020
  7. changed the title [-]Extra padding surrounding DropdownButtonFormField when compared to TextField[/-] [+]Extra vertical padding surrounding DropdownButtonFormField when compared to TextField[/+] on Jul 6, 2020
  8. shihaohong commented on Jul 6, 2020

    @shihaohong
    Contributor

    In the meantime, the workaround is to apply lesser vertical padding to the decoration for DropdownButtonFormField, since there is no way to make the contents of DropdownButtonFormField shorter than 24.0 without introducing a breaking change.

    To get the DropdownButtonFormField's height to exactly match TextField's (assuming no modifications to TextStyle to either TextField or DropdownButtonFormField), this is how you would do it:

    DropdownButtonFormField(
      iconSize: 24.0,
      decoration: InputDecoration(
      // isDense: true
      // contentPadding: EdgeInsets.fromLTRB(12, 18, 12, 10),
      // isDense: false
      contentPadding: EdgeInsets.fromLTRB(12, 22, 12, 14),
      border: OutlineInputBorder(),
    ),

    These values would of course vary depending on the actual heights, etc.

  9. shihaohong commented on Jul 6, 2020

    @shihaohong
    Contributor

    One solution could be to remove the usage of _kDenseButtonHeight altogether and rely on the font and icon heights in determining the height of the DropdownButtonFormField. However, this would still require the user to reduce the icon size for DropdownButtonFormField to get the same height as TextField, and the icon sizes will no longer match since TextField's suffixIcon is not surrounded by contentPadding for TextField, whereas the dropdown widget in DropdownButtonFormField is.

  10. cassioseffrin commented on Jul 6, 2020

    @cassioseffrin

    @shihaohong thks for yours concerns and sensitivity to reach exactly point that I am.

    One solution could be to remove the usage of _kDenseButtonHeight altogether and rely on the font and icon heights in determining the height of the DropdownButtonFormField.

    That was what I have done at #46844, after some tests I have realised another issue with this approach, which is: the hit area will be shorter (It will cause bad response to user) and plus it will get a side effect when a custom icon size is set.
    I also have tried to place the arrow_down Icon in decoration as a suffixIcon like in TextField. But It's very difficult to achieve due to the fact that suffix and prefix Icons are placed in another widget (InputDecoration).

    At the moment, I have end up customising the contentPadding. However it's take a lot of additional code in large forms with additional suffix command icons. But it's works!

  11. markusaksli-nc commented on Jul 20, 2020

    @markusaksli-nc
    Contributor

    Reproducible on the latest master 1.21.0-2.0.pre.66.

    flutter doctor -v
    [√] Flutter (Channel master, 1.21.0-2.0.pre.66, on Microsoft Windows [Version 10.0.18362.900], locale et-EE)
       • Flutter version 1.21.0-2.0.pre.66 at C:\Development\flutter_master
       • Framework revision 54c9441723 (3 days ago), 2020-07-17 18:56:12 -0400
       • Engine revision d327828632
       • Dart version 2.9.0 (build 2.9.0-21.0.dev 9dca49e71e)
    
    
    [√] Android toolchain - develop for Android devices (Android SDK version 30.0.0)
       • Android SDK at C:\Users\Isa\AppData\Local\Android\sdk
       • Platform android-30, build-tools 30.0.0
       • Java binary at: C:\Users\Isa\AppData\Local\JetBrains\Toolbox\apps\AndroidStudio\ch-0\193.6626763\jre\bin\java
       • Java version OpenJDK Runtime Environment (build 1.8.0_242-release-1644-b01)
       • All Android licenses accepted.
    
    [√] Chrome - develop for the web
       • Chrome at C:\Program Files (x86)\Google\Chrome\Application\chrome.exe
    
    [√] Visual Studio - develop for Windows (Visual Studio Community 2019 16.6.4)
       • Visual Studio at C:\Program Files (x86)\Microsoft Visual Studio\2019\Community
       • Visual Studio Community 2019 version 16.6.30309.148
       • Windows 10 SDK version 10.0.18362.0
    
    [√] Android Studio (version 4.0)
       • Android Studio at C:\Users\Isa\AppData\Local\JetBrains\Toolbox\apps\AndroidStudio\ch-0\193.6626763
       • Flutter plugin version 47.1.2
       • Dart plugin version 193.7361
       • Java version OpenJDK Runtime Environment (build 1.8.0_242-release-1644-b01)
    
    [√] VS Code (version 1.47.2)
       • VS Code at C:\Users\Isa\AppData\Local\Programs\Microsoft VS Code
       • Flutter extension version 3.12.2
    
    [√] Connected device (5 available)
       • SM G950F (mobile)       • ce12171c51cc001c03 • android-arm64  • Android 9 (API 28)
       • sdk gphone x86 (mobile) • emulator-5554      • android-x86    • Android 11 (API 30) (emulator)
       • Windows (desktop)       • windows            • windows-x64    • Microsoft Windows [Version 10.0.18362.900]
       • Web Server (web)        • web-server         • web-javascript • Flutter Tools
       • Chrome (web)            • chrome             • web-javascript • Google Chrome 84.0.4147.89
    
    • No issues found!
    
  12. exaby73 commented on Nov 15, 2022

    @exaby73
    Member

    This issue is still reproducible on Master (3.6.0-3.0.pre.26). Updating labels to reflect the same

  13. flutter-triage-bot commented on Aug 19, 2024

    @flutter-triage-bot

    This issue is missing a priority label. Please set a priority label when adding the triaged-design label.

  14. added
    triaged-designTriaged by Design Languages team
    P2Important issues not at the top of the work list
    on Aug 21, 2024
  15. nebkat commented on Oct 8, 2025

    @nebkat
    Contributor

    This also affects DropdownMenu:
    Image

    Easiest fix is:

    DropdownMenuFormField<T>(
        // TODO: Remove when resolved https://github.com/flutter/flutter/issues/60624
        inputDecorationTheme: InputDecorationTheme(
          suffixIconConstraints: BoxConstraints.loose(Size(50, 50)),
          contentPadding: EdgeInsets.fromLTRB(12, 20, 12, 12),
        ),
    )

    or

    ThemeData(
      dropdownMenuTheme: DropdownMenuThemeData(
        // TODO: Remove when resolved https://github.com/flutter/flutter/issues/60624
        inputDecorationTheme: InputDecorationTheme(
          suffixIconConstraints: BoxConstraints.loose(Size(50, 50)),
          contentPadding: EdgeInsets.fromLTRB(12, 20, 12, 12),
        ),
      ),
    ),
    Image

    Pixel perfect 😃

  16. added
    packageflutter/packages repository. See also p: labels.
    and removed
    frameworkflutter/packages/flutter repository. See also f: labels.
    on Aug 17, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    P2Important issues not at the top of the work lista: qualityA truly polished experiencefound in release: 3.3Found to occur in 3.3found in release: 3.6Found to occur in 3.6has reproducible stepsThe issue has been confirmed reproducible and is ready to work onp: material_uimaterial_ui package in flutter/packagespackageflutter/packages repository. See also p: labels.team-designOwned by Design Languages teamtriaged-designTriaged by Design Languages team

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions