Explain the difference between mainAxisAlignment and crossAxisAlignment

Medium PriorityAsked in ~60% of Flutter interviews

2 min read

Widgets & Layout

WidgetMain axisCross axis
RowHorizontal (→)Vertical (↕)
ColumnVertical (↓)Horizontal (↔)

mainAxisAlignment divides the free space along the main axis. crossAxisAlignment decides where each child sits in the perpendicular dimension.


Visualising the options

Row with three boxes A, B, C:

start         [A][B][C]___________
end           ___________[A][B][C]
center        _____[A][B][C]______
spaceBetween  [A]______[B]______[C]
spaceAround   __[A]___[B]___[C]__
spaceEvenly   ___[A]___[B]___[C]___

crossAxisAlignment (Row, so vertical):

start     align children to top
end       align children to bottom
center    centred vertically (default)
stretch   stretch each child to fill height (child can't have height)
baseline  align text baselines (must set textBaseline)

Code in action

// Navbar — items spread evenly
Row(
  mainAxisAlignment: MainAxisAlignment.spaceEvenly,
  children: const [Icon(Icons.home), Icon(Icons.search), Icon(Icons.person)],
);

// Form fields — stretch to full width
Column(
  crossAxisAlignment: CrossAxisAlignment.stretch,
  children: [
    TextField(decoration: const InputDecoration(labelText: 'Email')),
    TextField(decoration: const InputDecoration(labelText: 'Password')),
    ElevatedButton(onPressed: () {}, child: const Text('Login')),
  ],
);

// Centre a success state
Column(
  mainAxisAlignment: MainAxisAlignment.center,        // vertical centring
  crossAxisAlignment: CrossAxisAlignment.center,      // horizontal centring
  children: const [Icon(Icons.check, size: 64), Text('Done')],
);

When to reach for which

You want…Use
Push children to one endmainAxisAlignment: start / end
Spread items out (toolbar, footer)spaceBetween / spaceAround / spaceEvenly
Centre everythingboth axes set to center
Make column items full-widthcrossAxisAlignment: stretch (no width on children)
Align text by baseline (mixed font sizes)crossAxisAlignment: baseline + textBaseline

Common mistakes to avoid

// ❌ mainAxisAlignment doing nothing
Row(
  mainAxisSize: MainAxisSize.min,                     // shrink-wraps children
  mainAxisAlignment: MainAxisAlignment.spaceBetween,  // no free space → no effect
  children: [...],
);
// ✅ Use the default mainAxisSize.max, or rethink the layout

// ❌ stretch on a child that already has a size
Column(
  crossAxisAlignment: CrossAxisAlignment.stretch,
  children: [SizedBox(width: 100, child: ...)],       // SizedBox width fights stretch
);

// ❌ Confusing axes between Row and Column
Column(mainAxisAlignment: MainAxisAlignment.center)   // centres VERTICALLY, not horizontally
// ✅ For Column horizontal centring → crossAxisAlignment.center

// ❌ Forgetting textBaseline with baseline alignment
Row(
  crossAxisAlignment: CrossAxisAlignment.baseline,    // must also set textBaseline
);

Interview follow-ups

  1. Why does mainAxisAlignment: spaceBetween sometimes have no visible effect? Because there's no free space along the main axis. Common causes: mainAxisSize: MainAxisSize.min (the Row only wraps its children), or the Row is inside a parent that gave it unbounded width.

  2. What's the difference between mainAxisSize.min and mainAxisSize.max? max (default) makes the Row/Column fill the available main-axis space — needed for spaceBetween etc. to have anything to distribute. min shrink-wraps to just the children.

  3. Why does crossAxisAlignment: stretch clash with sized children? stretch tries to force each child to fill the cross axis. If a child already declares its own cross-axis size (e.g. SizedBox(width: 100) inside a Column), you get conflicting constraints and Flutter complains or unexpectedly clamps.

  4. How do Spacer and Expanded interact with mainAxisAlignment? They consume the free space themselves — once a Flex has Expanded/Spacer children, there's nothing left for mainAxisAlignment to distribute, so it effectively becomes a no-op.


How helpful was this content?

Please sign in to rate this article.