skip to content

In Flutter, what are the main axis and cross axis of a Row and a Column, and which properties align children along each?

level: juniorimportance: must knowfreq 82%

answer

  1. direction of the children run
  2. Row horizontal, Column vertical
  3. mainAxisAlignment defaults to start
  4. crossAxisAlignment defaults to center
  5. mainAxisSize defaults to max

basics

~20 s

The main axis is the direction children are laid out: horizontal for Row, vertical for Column; the cross axis is perpendicular. mainAxisAlignment (default start) and mainAxisSize (default max) act on the main axis, crossAxisAlignment (default center) on the cross axis.

solid answer

~40 s

`Row` and `Column` are both `Flex` with a fixed `direction`. The **main axis** is the one children are placed along — horizontal for `Row`, vertical for `Column` — and the **cross axis** is perpendicular. Three properties matter: `mainAxisAlignment` places children and free space along the main axis (`start` by default, plus `end`, `center`, `spaceBetween`, `spaceAround`, `spaceEvenly`); `crossAxisAlignment` positions each child across (`center` by default, plus `start`, `end`, `stretch`, `baseline`); `mainAxisSize` decides whether the widget takes all available main-axis space (`max`, the default) or only what its children need (`min`). The classic slip is swapping axes: to centre children horizontally in a `Column` you set `crossAxisAlignment`, not `mainAxisAlignment`.

code

dart · 23 lines
dart
import 'package:flutter/material.dart';

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

  @override
  Widget build(BuildContext context) {
    return const Column(
      mainAxisSize: MainAxisSize.min, // hug the rows
      crossAxisAlignment: CrossAxisAlignment.stretch, // rows span the label width
      children: [
        Row(
          mainAxisAlignment: MainAxisAlignment.spaceBetween,
          children: [Text('Calories'), Text('230')],
        ),
        Row(
          mainAxisAlignment: MainAxisAlignment.spaceBetween,
          children: [Text('Total fat'), Text('8 g')],
        ),
      ],
    );
  }
}

go deeper

for a junior

Recall which axis is main for Row and for Column, the three properties and their defaults: start, center and max.

for a middle

Explain that mainAxisAlignment only distributes free space and that the cross extent comes from the largest child.

for a senior

Predict layouts from the axis model without trial and error, and spot when a flex child or MainAxisSize.min has removed the free space an alignment relies on.

for a principal

Encourage axis-based vocabulary in reviews and shared components so Row and Column layouts stay consistent across a large codebase.

## Two widgets, one layout `Row` and `Column` are thin subclasses of **`Flex`**. `Row` fixes `direction: Axis.horizontal`; `Column` fixes `direction: Axis.vertical`. Everything else — alignment, sizing, spacing, flexible children — is shared, and it is all described in terms of two axes rather than width and height. - The **main axis** is the direction the children run in. - The **cross axis** is perpendicular to it. | Widget | Main axis | Cross axis | Main-axis size means | Cross-axis size means | |---|---|---|---|---| | `Row` | horizontal | vertical | width | height | | `Column` | vertical | horizontal | height | width | Once you think in axes, the same property works for both widgets and you stop memorising 'which one is horizontal for Column'. ## mainAxisAlignment: placing children and free space `mainAxisAlignment` controls where children sit along the main axis and how any **free space** — main-axis space the children did not use — is distributed. The values: 1. `start` (the default) — children packed at the start, free space at the end. 2. `end` — packed at the end. 3. `center` — packed in the middle, free space split before and after. 4. `spaceBetween` — free space divided evenly between children, none at the ends. 5. `spaceAround` — half-size gaps at the ends, full gaps between. 6. `spaceEvenly` — equal gaps between children and at both ends. If there is no free space, because the children fill the axis or a flexible child took it, `mainAxisAlignment` has nothing to distribute and appears to do nothing. ## crossAxisAlignment: positioning across `crossAxisAlignment` places each child across the run. The values are `start`, `end`, `center` (the default), `stretch` and `baseline`. - `start`/`end`/`center` move a child within the widget's cross extent. - `stretch` forces every child to fill the cross axis by giving it tight cross-axis constraints. - `baseline` lines up text baselines in a `Row` and needs a `textBaseline` argument. The cross extent of a `Row` or `Column` is the largest cross size among its children, within its own constraints. So a `Column` of three labels is as wide as its widest label, and `CrossAxisAlignment.start` left-aligns the narrower ones inside that width. ## mainAxisSize: how much of the main axis to take `mainAxisSize` decides the widget's own main-axis extent after the children are sized: - **`MainAxisSize.max`** (default): as large as the incoming constraints allow. A `Column` in a screen body is as tall as the body, even with two short children. - **`MainAxisSize.min`**: the sum of the children's sizes (and any spacing), within the constraints. Use it for a `Column` inside a `Card` or dialog that should hug its content. `mainAxisSize` and `mainAxisAlignment` interact: with `min`, there is usually no free space, so `center` or `spaceBetween` have nothing to spread. ## A nutrition-label row, both ways A nutrition label is a `Column` of rows, each row a nutrient name, a daily-value bar and an amount: - The outer `Column` uses `crossAxisAlignment: CrossAxisAlignment.stretch` so every row spans the label's width, and `mainAxisSize: MainAxisSize.min` so the label is only as tall as its rows. - Each `Row` uses `mainAxisAlignment: MainAxisAlignment.spaceBetween` when it has just a name and an amount, pushing them to opposite edges. - Aligning the amount's text with the name's text is a cross-axis job for that `Row` (`crossAxisAlignment`), not a main-axis one. ## Common mistakes - Setting `mainAxisAlignment: MainAxisAlignment.center` on a `Column` and expecting horizontal centring. - Expecting `spaceBetween` to work in a `Row` whose `Expanded` child already consumed the free space. - Leaving a `Column` at `MainAxisSize.max` inside a dialog and wondering why the dialog is full height.

  • In a Flutter Row with an Expanded child, why does mainAxisAlignment: MainAxisAlignment.center seem to do nothing?
    `mainAxisAlignment` only distributes free space: main-axis space the children did not use. An `Expanded` child is forced to fill all the space left after the inflexible children, so the free space is zero and there is nothing to centre. Remove the flex, use `Flexible` with a loose fit, or let the Row use `MainAxisSize.min`.
  • How wide is a Flutter Column whose children are three Text labels of different lengths?
    A `Column`'s cross extent is the largest cross size among its children, within its own constraints, so it is as wide as the widest label (unless its constraints force more, for example tight width). `crossAxisAlignment` then positions the narrower labels inside that width; `stretch` instead forces every child to the maximum width available.

saying these in an interview costs you the question

  • In a Column, mainAxisAlignment centres the children horizontally.
  • Row's default crossAxisAlignment is start, so children sit at the top.
  • MainAxisSize.min makes a Column shrink on both axes.
  • spaceBetween still spreads children when an Expanded child is present.
  • Row and Column are unrelated widgets with different alignment properties.