Skip to content

Border.symmetric() is confusing #193094

Closed

Description

@navaronbracke

Use case

Developers combining symmetric EdgeInsets (padding) and borders might get a bit confused that "vertical/horizontal" does not mean the same thing for borders and padding.

Given the following code sample:

import 'package:flutter/material.dart';

void main() {
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      debugShowCheckedModeBanner: false,
      home: Scaffold(
        body: Center(
          child: Container(
            color: Colors.green,
            padding: .symmetric(horizontal: 32, vertical: 4),
            child: DecoratedBox(
              decoration: BoxDecoration(
                border: Border.symmetric(
                  vertical: BorderSide(color: Colors.red),
                  horizontal: BorderSide(color: Colors.blue),
                ),
              ),
              child: Text('Hello, World!'),
            ),
          ),
        ),
      ),
    );
  }
}
  1. The vertical padding is on the top and bottom, the horizontal padding is on the left and right.
  2. Now compare the above statement with what happens for Border: The "vertical" argument are the left and right borders, not the top and bottom ones. This is very unintuitive in my opinion.
    In retrospect the arguments refer to how the border is drawn, not where it is positioned. (i.e. left & right are drawn vertically)

The entire framework barely uses said constructor, it only seems to be referenced in a test?

TableBorder also has a symmetric constructor, but that one uses different named parameters (inside, outside) and applies them uniformly like so

  const TableBorder.symmetric({
    BorderSide inside = BorderSide.none,
    BorderSide outside = BorderSide.none,
    this.borderRadius = BorderRadius.zero,
  }) : top = outside,
       right = outside,
       bottom = outside,
       left = outside,
       horizontalInside = inside,
       verticalInside = inside;

Proposal

Deprecate the "old" behavior of Border.symmetric() and flip the arguments around so that "horizontal" means left/right and "vertical" means top/bottom, matching what EdgeInsets does.

Context

The original addition is 6+ years old, and the original issue for it #45524
did not specify exactly which side horizontal/vertical where for (the example in the issue seems very arbitrary)

Activity

  1. added
    frameworkflutter/packages/flutter repository. See also f: labels.
    c: proposalA detailed proposal for a change to Flutter
    on Sep 21, 2026
  2. added
    P3Issues that are less important to the Flutter project
    on Sep 22, 2026
  3. Renzo-Olivares commented on Sep 22, 2026

    @Renzo-Olivares
    Contributor

    Hi @navaronbracke, thanks for filing this proposal!

    Looking back at the git history, there is actually an interesting backstory here:

    1. EdgeInsets.symmetric dates back to March 2016 (e71bd77e4f4), where vertical applies to top/bottom and horizontal applies to left/right.
    2. When Border.symmetric was originally added in January 2020 (Add Border.symmetric constructor #47523), it did match EdgeInsets.symmetric (top = vertical, bottom = vertical, left = horizontal, right = horizontal).
    3. However, in July 2020, issue Border.symmetric constructor inverts the meaning of vertical and horizontal #61470 ("Border.symmetric constructor inverts the meaning of vertical and horizontal") was filed and executed as a 3-phase breaking migration (Fix Border.symmetric: phase 1 #61474, Fix Border.symmetric: phase 2 #61666, Fix Border.symmetric: phase 3 #62471) to intentionally flip them to left = vertical, right = vertical, top = horizontal, bottom = horizontal on the rationale that the vertical borders (the lines running vertically, like TableBorder.verticalInside and VerticalDivider) are the left and right borders, whereas horizontal borders (like TableBorder.horizontalInside and Divider) are the top and bottom borders.

    Because this behavior was deliberately migrated in #61470 to align with Divider/VerticalDivider/TableBorder and has been in place for 6 years, flipping it back in-place would break existing callers. We can leave this open to see if there is appetite for clearer parameter naming or documentation.

  4. navaronbracke commented on Sep 22, 2026

    @navaronbracke
    ContributorAuthor

    Then I would propose to use this as an addendum to the docs?

    I.e.

      /// Creates a border with symmetrical vertical and horizontal sides.
      ///
      /// The `vertical` argument refers to the borders that are drawn vertically,
      /// which are the [left] and [right] sides, and the `horizontal` argument refers
      /// to the borders that are drawn horizontally, which are [top] and [bottom] sides.
      ///
      /// All arguments default to [BorderSide.none].
    

    Then again I personally don't really use this constructor much (I either pick fromBorderSide() or explicit top/left/right/bottom in the unnamed constructor)

  5. github-actions commented on Oct 16, 2026

    @github-actions

    This thread has been automatically locked since there has not been any recent activity after it was closed. If you are still experiencing a similar issue, please open a new bug, including the output of flutter doctor -v and a minimal reproduction of the issue.

  6. locked as resolved and limited conversation to collaborators on Oct 16, 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

    P3Issues that are less important to the Flutter projectc: proposalA detailed proposal for a change to Flutterframeworkflutter/packages/flutter repository. See also f: labels.team-frameworkOwned by Framework teamtriaged-frameworkTriaged by Framework team

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions