Flutter Layout Made Easy: Row, Column, Flex and Expanded for Beginners (2026)

Flutter layouts feel confusing until you understand one rule: everything is a widget — including the layout itself.

In most frameworks, flutter layout is a separate concern from UI components. In Flutter, there’s no such separation. A Row is a widget. A Column is a widget. Even spacing and padding are widgets. Once that clicks, the whole system becomes predictable — because you’re just nesting widgets inside other widgets, all the way down.

This guide covers the four layout widgets you’ll use in almost every Flutter screen: Row, Column, Flex, and Expanded. Every section has a visual diagram, a complete copy-paste code example, and a clear explanation of what each property actually does. By the end you’ll know how to build any common UI structure — and how to fix the overflow errors that trip up every beginner.

Prerequisites: You should be able to run a Flutter app and understand basic widgets. If you haven’t set that up yet, start with our Flutter setup guide.

Table of Contents


1. The Core Mental Model: Main Axis vs Cross Axis

Before writing any layout code, you need one concept locked in: every flex layout widget has a main axis (the direction it places children) and a cross axis (perpendicular to it). These two axes determine how all the alignment properties behave.

Widget Main axis Cross axis mainAxisAlignment controls crossAxisAlignment controls
Row Horizontal ↔ Vertical ↕ Horizontal spacing between children Vertical alignment of children
Column Vertical ↕ Horizontal ↔ Vertical spacing between children Horizontal alignment of children

Every alignment decision you make will refer back to this table. When you set mainAxisAlignment on a Row, you’re controlling horizontal spacing. When you set crossAxisAlignment on a Row, you’re controlling how children sit vertically within the row’s height.


2. Row — Horizontal Layout

A Row places its children side by side horizontally. It expands to fill the full width available to it by default and sizes itself to the tallest child vertically.

💡 Notice the SizedBox: When you want a fixed gap between two children in a Row, SizedBox(width: 16) is cleaner than relying on mainAxisAlignment alone. Use SizedBox(height: N) for gaps in a Column.

3. Column — Vertical Layout

A Column stacks its children top-to-bottom along the vertical axis. It works identically to Row — the only difference is the direction of the main axis.


4. Alignment Reference: All mainAxisAlignment Values

This is the table you’ll want to bookmark. Both Row and Column share the same MainAxisAlignment enum — just remember to apply the mental model from Section 1 to know which physical direction each value affects.

Value Visual result When to use it
start (default) [A][B][C]· · · · · Children packed at the start — default behavior
end · · · · ·[A][B][C] Right-align / bottom-align children
center · · [A][B][C] · · Center all children as a group
spaceBetween [A]· · · [B]· · · [C] Space only between items — flush to edges
spaceAround · [A]· · [B]· · [C]· Half-space at edges, full space between
spaceEvenly · [A]· · [B]· · [C]· Equal space before, between, and after all items
CrossAxisAlignment value Effect in a Row Effect in a Column
center (default) Children vertically centered within row height Children horizontally centered
start Children aligned to top of row Children aligned to left edge
end Children aligned to bottom of row Children aligned to right edge
stretch Children stretched to row’s full height Children stretched to column’s full width
baseline Text baselines aligned (requires textBaseline) N/A

5. Expanded — Fill Available Space

Expanded is used inside a Row, Column, or Flex to make one child take up all remaining space on the main axis after the fixed-size siblings have been measured. It’s one of the most useful widgets in Flutter and solves a huge range of common layout problems.

Expanded in a Column — fixed header, stretching body

Expanded in a Row — input field + button

One of the most common patterns in real apps — a text field takes all available width, and a button sits alongside it at its natural size:


6. Expanded with flex: — Proportional Space Splitting

When multiple siblings are all Expanded, Flutter splits the remaining space between them proportionally based on their flex value. The default flex is 1. Setting flex: 2 gives that child twice as much space as a sibling with flex: 1.


7. Flex — The Widget Behind Row and Column

Row and Column are both specialised versions of Flex. The only difference is that Flex requires you to explicitly pass a directionAxis.horizontal (same as Row) or Axis.vertical (same as Column). Everything else — mainAxisAlignment, crossAxisAlignment, Expanded children — works identically.

💡 When to use Flex directly: Use Flex when you’re building a reusable widget that accepts a direction parameter. For example, a Divider-style widget that can be horizontal or vertical depending on context. For everything else, Row and Column are clearer and more readable.

8. Real UI Examples: Combining Row, Column & Expanded

Profile Card — Row inside Card with nested Column

Equal-Width Buttons — Expanded side by side


9. Overflow: What It Is and How to Fix It

When a Row or Column‘s children take up more space than the widget has available, Flutter renders the infamous yellow-and-black hatched overflow stripe along the overflowing edge. This is Flutter telling you: “Something doesn’t fit — you need to decide how to handle it.”

The overflow: three ways to fix it

Situation Best fix
Single-line text overflowing in a Row Expanded + TextOverflow.ellipsis
Text that should wrap onto multiple lines Expanded with default softWrap: true
Multiple chips or tags that may not fit Wrap widget instead of Row
Column content taller than the screen ListView instead of Column

10. Common Beginner Mistakes

Mistake 1: Using Expanded outside a Row, Column, or Flex

Mistake 2: Using Column for a scrollable page

Mistake 3: Forgetting mainAxisSize: MainAxisSize.min on inner columns

Mistake 4: Nesting two Expanded widgets incorrectly


11. Interview Q&A

Q1: What is the difference between Row and Column?

Answer: A Row lays out its children horizontally — the main axis is horizontal, the cross axis is vertical. A Column lays out its children vertically — the main axis is vertical, the cross axis is horizontal. Both accept the same alignment properties and work the same way; only the direction differs.

Q2: What does Expanded do, and where can you use it?

Answer: Expanded makes a child of a Row, Column, or Flex fill all remaining space on the main axis after fixed-size siblings have been measured. It can only be used as a direct child of one of those three flex widgets — using it anywhere else throws a runtime layout error.

Q3: What does flex: 2 mean on an Expanded widget?

Answer: It means that widget receives twice the share of remaining space compared to a sibling with flex: 1. Flutter adds up all the flex values (e.g. 1 + 2 + 1 = 4), then allocates each child its fraction of the available space (25%, 50%, 25%). The default flex value is 1.

Q4: What is Flex and how does it relate to Row and Column?

Answer: Row and Column are both subclasses of Flex. Flex is the underlying implementation — it requires an explicit direction parameter (Axis.horizontal or Axis.vertical) while Row and Column hardcode that direction. All three support the same children, alignment, and Expanded behaviour.

Q5: Why does Flutter show the yellow-and-black overflow stripe?

Answer: It appears when a layout widget’s children collectively need more space than the widget has available — i.e. the children overflow the render box boundary. Common fixes include wrapping overflowing children in Expanded, adding TextOverflow.ellipsis to text, replacing Column with ListView for scrollable content, or using the Wrap widget for items that should flow onto multiple lines.

Q6: When should you use ListView instead of Column?

Answer: Use ListView whenever the content may grow taller than the available screen height. Column does not scroll and will overflow if its children exceed its bounds. ListView.builder is also more memory-efficient for long or dynamic lists because it only builds the widgets currently visible on screen, unlike Column which builds all children at once.

Quick-Copy Reference Snippet

Bookmark this — it combines alignment, flex sizing, and responsive width in one clean template:


See Layouts in a Real App

Every concept in this article is used throughout our notes app series — Column for the editor screen, Expanded to stretch the content field, Row inside the AppBar actions. See it all working in context:

Article Layout concepts in use
Notes App Part 1: Project Setup & Core UI Column for editor layout, Expanded to fill content field height, Scaffold + AppBar
Notes App Part 2: Local Persistence & Polish Column in ListTile subtitles, Card + Row composition patterns
Flutter Widgets Explained: Stateless vs Stateful Column with mainAxisAlignment.center in every widget example
Show 1 Comment

1 Comment

Leave a Reply