Lesson 22 of 51 beginner

Row & Column Layout

Horizontal and Vertical Arrangement

Open interactive version (quiz + challenge)

Real-world analogy

Row and Column are like organizing books. A Row is a bookshelf where books stand side by side horizontally. A Column is a stack of books piled on top of each other vertically. MainAxisAlignment is how you space them along the shelf (or stack), and CrossAxisAlignment is how you align them perpendicular to that direction.

What is it?

Row and Column are the two fundamental layout widgets in Flutter. Row arranges children horizontally, Column arranges them vertically. Together with MainAxisAlignment, CrossAxisAlignment, Expanded, Flexible, and Spacer, they handle the vast majority of Flutter layouts through simple composition.

Real-world relevance

In team_mvp_kit, nearly every screen uses Row and Column. Login forms use Column to stack fields vertically. App bars use Row for horizontal icon arrangement. List tiles combine both: a Row with an icon, a Column of title and subtitle, and a trailing action. Mastering Row and Column is mastering Flutter layout.

Key points

Code example

import 'package:flutter/material.dart';

class UserCard extends StatelessWidget {
  final String name;
  final String email;
  final String role;

  const UserCard({
    super.key,
    required this.name,
    required this.email,
    required this.role,
  });

  @override
  Widget build(BuildContext context) {
    return Card(
      child: Padding(
        padding: const EdgeInsets.all(16),
        child: Row(
          children: [
            const CircleAvatar(
              radius: 28,
              child: Icon(Icons.person, size: 28),
            ),
            const SizedBox(width: 16),
            Expanded(
              child: Column(
                crossAxisAlignment: CrossAxisAlignment.start,
                children: [
                  Text(
                    name,
                    style: Theme.of(context).textTheme.titleMedium,
                  ),
                  const SizedBox(height: 4),
                  Text(
                    email,
                    style: Theme.of(context).textTheme.bodySmall,
                  ),
                ],
              ),
            ),
            Container(
              padding: const EdgeInsets.symmetric(
                horizontal: 12,
                vertical: 6,
              ),
              decoration: BoxDecoration(
                color: Colors.blue.shade50,
                borderRadius: BorderRadius.circular(16),
              ),
              child: Text(
                role,
                style: TextStyle(
                  color: Colors.blue.shade700,
                  fontSize: 12,
                  fontWeight: FontWeight.w600,
                ),
              ),
            ),
          ],
        ),
      ),
    );
  }
}

Line-by-line walkthrough

  1. 1. Import the Material package
  2. 2.
  3. 3. Define UserCard as a StatelessWidget since it just displays data
  4. 4. Declare required fields: name, email, and role
  5. 5.
  6. 6.
  7. 7.
  8. 8.
  9. 9. Build method returns the widget tree
  10. 10. Return a Card widget for the elevated surface look
  11. 11. Pad the card content by 16 pixels on all sides
  12. 12.
  13. 13. Row arranges avatar, text, and badge horizontally
  14. 14.
  15. 15. CircleAvatar creates a round profile picture placeholder
  16. 16. Set radius to 28 for a medium-sized avatar
  17. 17. Person icon inside the avatar
  18. 18.
  19. 19. SizedBox adds 16px horizontal gap between avatar and text
  20. 20. Expanded makes the text column fill remaining space
  21. 21. Column stacks name and email vertically
  22. 22. CrossAxisAlignment.start left-aligns the text
  23. 23.
  24. 24. Display the name with titleMedium theme style
  25. 25.
  26. 26.
  27. 27. SizedBox adds 4px gap between name and email
  28. 28.
  29. 29. Display email with bodySmall theme style (lighter color)
  30. 30.
  31. 31.
  32. 32.
  33. 33. Container wraps the role badge
  34. 34. Symmetric padding: 12px horizontal, 6px vertical
  35. 35.
  36. 36. BoxDecoration adds background color and rounded corners
  37. 37. Light blue background
  38. 38. 16px border radius for pill shape
  39. 39.
  40. 40. Text displays the role string
  41. 41. Styled with dark blue color, small font, semibold weight
  42. 42.
  43. 43.
  44. 44.
  45. 45.
  46. 46.
  47. 47.
  48. 48.

Spot the bug

Row(
  children: [
    Text('A very long text that keeps going and going'),
    Text('Another long text that also keeps going'),
  ],
)
Need a hint?
What happens when children in a Row are wider than the screen?
Show answer
The Row overflows because both Text widgets try to take their natural width, which exceeds the screen. Fix: wrap one or both Text widgets in Expanded or Flexible so they share the available space and wrap their text: Expanded(child: Text('A very long text...'))

Explain like I'm 5

Imagine you have toy blocks. Column is when you stack blocks into a tower going up. Row is when you line blocks up in a train going sideways. MainAxisAlignment is like choosing whether to bunch the blocks at one end, spread them out evenly, or put them in the middle. And Expanded is like a stretchy block that grows to fill any empty space so there are no gaps!

Fun fact

Flutter's layout system is inspired by the CSS Flexbox model from web development. Row is like display: flex with flex-direction: row, and Column is like flex-direction: column. If you know Flexbox, you already understand Flutter layout!

Hands-on challenge

Build a profile card that uses a Row for the top section (avatar on the left, Column of name and bio on the right), a Row of stat counters (posts, followers, following) using Expanded with equal flex, and a Row of two buttons (Follow as Expanded ElevatedButton, Message as Expanded OutlinedButton) with a SizedBox gap between them.

More resources

Open interactive version (quiz + challenge) ← Back to course: Flutter & Dart