skip to content

In Flutter, what do CrossAxisAlignment.stretch and CrossAxisAlignment.baseline do in a Row, and what does each require to work?

level: middleimportance: should knowfreq 42%

answer

  1. tight cross-axis constraints
  2. needs a bounded cross axis
  3. textBaseline has no default
  4. alphabetic or ideographic
  5. treated as start in Column

basics

~20 s

stretch gives every child tight cross-axis constraints equal to the Row's incoming max height, so it needs a bounded height. baseline lines up children's text baselines, and throws unless textBaseline is set; in a Column it acts like start.

solid answer

~40 s

With `CrossAxisAlignment.stretch`, a `Row` lays children out with `BoxConstraints.tightFor(height: maxHeight)` — every child is forced to the Row's incoming max height, not to the tallest sibling. That needs a bounded height: as an item in a vertical `ListView` the Row's height is unbounded and layout fails with 'BoxConstraints forces an infinite height.' `CrossAxisAlignment.baseline` aligns children so their text baselines match, useful when a large bold amount sits next to a small unit label. It requires `textBaseline` (`TextBaseline.alphabetic` or `ideographic`); the Row has no default and throws 'To use CrossAxisAlignment.baseline, you must also specify which baseline to use…'. Children with no baseline are top-aligned, and a `Column` treats `baseline` as `start`.

code

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

Widget caloriesRow() => const Row(
      crossAxisAlignment: CrossAxisAlignment.baseline,
      textBaseline: TextBaseline.alphabetic, // required, no default
      children: [
        Text('230', style: TextStyle(fontSize: 28, fontWeight: FontWeight.bold)),
        SizedBox(width: 4),
        Text('kcal', style: TextStyle(fontSize: 12)),
      ],
    );

go deeper

for a junior

Recall that stretch fills the cross axis and baseline lines up text, and that baseline needs textBaseline.

for a middle

Explain the constraints each value produces: tight cross-axis height for stretch, baseline offsets for baseline, and why stretch fails under an unbounded height.

for a senior

Diagnose stretch failures inside scrolling lists and choose between bounding the height and measuring children, weighing the extra layout cost.

for a principal

Guide typography-heavy components toward baseline alignment and fixed row heights so mixed-size text stays aligned across locales and scripts.

## Beyond start, center and end `CrossAxisAlignment` has five values. `start`, `center` (the default) and `end` only move a child within the Row's height; they pass each child loose cross-axis constraints (height 0 up to the Row's max). The other two change more than position: | Value | What children receive | What it needs | Typical use | |---|---|---|---| | `stretch` | tight height equal to the Row's incoming max height | a bounded incoming height | full-height dividers, equal-height tiles in a fixed-height row | | `baseline` | loose height, then vertical offsets that line up baselines | a `textBaseline` argument | mixed font sizes in one line of text | ## stretch: filling the cross axis For a `Row`, stretch changes step one of the flex algorithm: instead of `BoxConstraints(maxHeight: maxHeight)` each inflexible child gets `BoxConstraints.tightFor(height: maxHeight)`. Flexible children get the same tight cross-axis height. Three consequences: 1. **Children fill the Row's available height, not the tallest child's height.** If the Row sits in a 120-pixel-tall slot, every child is 120 tall. Matching the tallest sibling instead requires measuring the children first, which is the intrinsic-sizing topic. 2. **The incoming height must be bounded.** When the Row is an item in a vertical `ListView` or a child of a `Column` inside a vertical scroll view, its max height is infinite. Stretch then asks children to be infinitely tall, and layout fails with 'BoxConstraints forces an infinite height.' 3. **The Row's own height becomes the max height**, because every child is that tall. In a `Column`, stretch is the common way to make children full width: its cross axis is horizontal, and the width is usually bounded by the screen. ## baseline: lining up text Text with different font sizes has different ascents. Centring a 28-point '230' next to a 12-point 'kcal' makes their bottoms disagree. `CrossAxisAlignment.baseline` asks each child for its distance to a baseline and offsets children so those baselines sit on one line. - **`textBaseline` is mandatory.** `Row`'s `textBaseline` has no default; the framework comment says it cannot know which baseline the text uses. Without it the Row throws: 'To use CrossAxisAlignment.baseline, you must also specify which baseline to use using the "textBaseline" argument.' - **Values:** `TextBaseline.alphabetic` for Latin-style scripts, where the baseline runs along the bottom of letters; `TextBaseline.ideographic` for CJK layouts. - **What counts as a child's baseline:** typically the first `Text` or `RichText` inside it. Children that report none are top-aligned. - **Extra height** goes below the children: if the Row's minimum height exceeds what the aligned children need, they align as close to the top as they can. - **Vertical main axis:** baselines are horizontal lines, so a `Column` treats `baseline` as `start`. ## The nutrition-label case On a nutrition label the calorie row shows a large number and a small unit. The fix for 'the unit floats too high' is: 1. Set `crossAxisAlignment: CrossAxisAlignment.baseline`. 2. Set `textBaseline: TextBaseline.alphabetic`. 3. Keep both texts as direct children, or wrap them in widgets that pass a baseline through (padding and most single-child layout widgets do). For the label's vertical divider between columns, stretch is the tool, but only if the row has a bounded height, for example because the label gives each row a fixed height. ## Checklist - Stretch inside a scrollable along the cross axis? Bound the height first. - Baseline without `textBaseline`? It throws at layout. - Baseline in a `Column`? It silently behaves like `start`. - Expecting stretch to equalise to the tallest child? It uses the Row's max height instead.

  • In Flutter, how do you make every child of a Row as tall as the tallest one when the Row's height is unbounded?
    Stretch alone cannot do it, because it fills the incoming max height, which is infinite in a scrolling list. You either give the Row a bounded height, for example a fixed-height `SizedBox`, or measure the children first with an intrinsic-height wrapper, which costs an extra layout pass and belongs to the intrinsic-sizing toolbox.
  • Why does a Flutter Row with CrossAxisAlignment.stretch end up as tall as its slot even if every child is short?
    Stretch gives each child tight constraints equal to the Row's incoming max height, so each child must be exactly that tall. The Row's cross extent is the tallest child, which is now the max height. That is the intended behaviour for dividers and equal-height tiles, but surprising if you expected content-driven height.

saying these in an interview costs you the question

  • stretch makes children as tall as the tallest sibling.
  • baseline works without textBaseline because alphabetic is the default.
  • stretch works the same inside a vertical ListView item.
  • baseline in a Column aligns the first line of each child.
  • start, center and end also change the constraints children receive.