Skip to content

Expanded

Understand how to make widgets fill available space in flex layouts.


What is it?

Expanded is a widget that expands a child of a Row, Column, or Flex to fill the available space along the main axis. It's used to make widgets take up remaining space proportionally. Expanded is essential for creating responsive layouts where widgets need to share or fill available space.


Why does it exist?

Expanded exists to:

  • Fill available space in flex layouts
  • Create proportional layouts
  • Make widgets responsive
  • Share space between children
  • Simplify flexible layouts
  • Handle different screen sizes
  • Create adaptive UIs

Basic Expanded

Expanded fills available space in a flex container.

// Basic Expanded usage
class BasicExpanded extends StatelessWidget {
  const BasicExpanded({super.key});

  @override
  Widget build(BuildContext context) {
    return Column(
      children: [
        // 1. Expanded in Row
        Container(
          height: 100,
          color: Colors.grey[200],
          child: Row(
            children: [
              Container(
                width: 50,
                color: Colors.red,
              ),
              Expanded(
                child: Container(
                  color: Colors.blue,
                  child: const Center(child: Text('Expanded')),
                ),
              ),
              Container(
                width: 50,
                color: Colors.green,
              ),
            ],
          ),
        ),

        const SizedBox(height: 20),

        // 2. Expanded in Column
        Container(
          height: 200,
          color: Colors.grey[200],
          child: Column(
            children: [
              Container(
                height: 50,
                color: Colors.red,
              ),
              Expanded(
                child: Container(
                  color: Colors.blue,
                  child: const Center(child: Text('Expanded')),
                ),
              ),
              Container(
                height: 50,
                color: Colors.green,
              ),
            ],
          ),
        ),
      ],
    );
  }
}

// Expanded properties:
// 1. flex - How much space to take (default: 1)
// 2. child - The widget to expand

What's happening here? - Expanded fills remaining space - Works in Row, Column, Flex - Child expands to fill space - Multiple Expanded share space - flex controls proportion


Flex Factors

Flex factors control space distribution.

// Flex factor examples
class FlexFactorExample extends StatelessWidget {
  const FlexFactorExample({super.key});

  @override
  Widget build(BuildContext context) {
    return Column(
      children: [
        // 1. Equal flex (1:1:1)
        Container(
          height: 80,
          color: Colors.grey[200],
          child: Row(
            children: [
              Expanded(
                flex: 1,
                child: Container(
                  color: Colors.red,
                  child: const Center(child: Text('1')),
                ),
              ),
              Expanded(
                flex: 1,
                child: Container(
                  color: Colors.green,
                  child: const Center(child: Text('1')),
                ),
              ),
              Expanded(
                flex: 1,
                child: Container(
                  color: Colors.blue,
                  child: const Center(child: Text('1')),
                ),
              ),
            ],
          ),
        ),

        const SizedBox(height: 10),

        // 2. Different flex (1:2:3)
        Container(
          height: 80,
          color: Colors.grey[200],
          child: Row(
            children: [
              Expanded(
                flex: 1,
                child: Container(
                  color: Colors.red,
                  child: const Center(child: Text('1')),
                ),
              ),
              Expanded(
                flex: 2,
                child: Container(
                  color: Colors.green,
                  child: const Center(child: Text('2')),
                ),
              ),
              Expanded(
                flex: 3,
                child: Container(
                  color: Colors.blue,
                  child: const Center(child: Text('3')),
                ),
              ),
            ],
          ),
        ),

        const SizedBox(height: 10),

        // 3. Mixed fixed and expanded
        Container(
          height: 80,
          color: Colors.grey[200],
          child: Row(
            children: [
              Container(
                width: 80,
                color: Colors.red,
                child: const Center(child: Text('Fixed')),
              ),
              Expanded(
                flex: 2,
                child: Container(
                  color: Colors.green,
                  child: const Center(child: Text('Flex 2')),
                ),
              ),
              Expanded(
                flex: 1,
                child: Container(
                  color: Colors.blue,
                  child: const Center(child: Text('Flex 1')),
                ),
              ),
            ],
          ),
        ),
      ],
    );
  }
}

// Flex factor calculation:
// Total flex = sum of all flex factors
// Space per flex = available space / total flex
// Child space = flex factor * space per flex

What's happening here? - Higher flex = more space - Equal flex = equal space - Flex factors proportionally distribute - Fixed widgets maintain their size - Expanded fills remaining space


Expanded vs Flexible

Comparing Expanded with Flexible.

// Expanded vs Flexible comparison
class ExpandedVsFlexible extends StatelessWidget {
  const ExpandedVsFlexible({super.key});

  @override
  Widget build(BuildContext context) {
    return Column(
      children: [
        // 1. Expanded - always fills space
        Container(
          height: 80,
          color: Colors.grey[200],
          child: Row(
            children: [
              Expanded(
                child: Container(
                  color: Colors.red,
                  child: const Center(child: Text('Expanded')),
                ),
              ),
              Expanded(
                child: Container(
                  color: Colors.blue,
                  child: const Center(child: Text('Expanded')),
                ),
              ),
            ],
          ),
        ),

        const SizedBox(height: 10),

        // 2. Flexible - can fit to content
        Container(
          height: 80,
          color: Colors.grey[200],
          child: Row(
            children: [
              Flexible(
                fit: FlexFit.loose,
                child: Container(
                  color: Colors.green,
                  child: const Text('Flexible Loose'),
                ),
              ),
              Flexible(
                fit: FlexFit.tight,
                child: Container(
                  color: Colors.orange,
                  child: const Text('Flexible Tight'),
                ),
              ),
            ],
          ),
        ),

        const SizedBox(height: 10),

        // 3. When to use each
        Row(
          children: [
            // Expanded: Force fill
            Expanded(
              child: Container(
                color: Colors.purple,
                child: const Text('Expanded'),
              ),
            ),

            // Flexible: Allow natural size
            Flexible(
              fit: FlexFit.loose,
              child: Container(
                color: Colors.pink,
                child: const Text('Flexible'),
              ),
            ),
          ],
        ),
      ],
    );
  }
}

// Expanded = Flexible(fit: FlexFit.tight)
// Expanded always fills space
// Flexible can be loose or tight
// Use Expanded when you want to fill
// Use Flexible when you want flexibility

What's happening here? - Expanded: always fills space - Flexible: can fit to content - Expanded = Flexible tight - Flexible offers more control - Choose based on behavior needed


Expanded in Different Layouts

Expanded works in various flex layouts.

// Expanded in different contexts
class ExpandedInLayouts extends StatelessWidget {
  const ExpandedInLayouts({super.key});

  @override
  Widget build(BuildContext context) {
    return Column(
      children: [
        // 1. In Row
        Container(
          height: 60,
          color: Colors.grey[200],
          child: Row(
            children: [
              const Text('Left'),
              Expanded(
                child: Container(
                  color: Colors.blue,
                  child: const Center(child: Text('Center')),
                ),
              ),
              const Text('Right'),
            ],
          ),
        ),

        const SizedBox(height: 10),

        // 2. In Column
        Container(
          height: 150,
          color: Colors.grey[200],
          child: Column(
            children: [
              const Text('Top'),
              Expanded(
                child: Container(
                  color: Colors.green,
                  child: const Center(child: Text('Middle')),
                ),
              ),
              const Text('Bottom'),
            ],
          ),
        ),

        const SizedBox(height: 10),

        // 3. Nested Expanded
        Container(
          height: 150,
          color: Colors.grey[200],
          child: Row(
            children: [
              Expanded(
                flex: 2,
                child: Container(
                  color: Colors.red,
                  child: const Center(child: Text('Left')),
                ),
              ),
              Expanded(
                flex: 3,
                child: Column(
                  children: [
                    Expanded(
                      child: Container(
                        color: Colors.green,
                        child: const Center(child: Text('Top')),
                      ),
                    ),
                    Expanded(
                      child: Container(
                        color: Colors.blue,
                        child: const Center(child: Text('Bottom')),
                      ),
                    ),
                  ],
                ),
              ),
            ],
          ),
        ),
      ],
    );
  }
}

What's happening here? - Works in both Row and Column - Can be nested - Flexible in any direction - Creates complex layouts - Responsive and adaptive


Real-World Examples

Common patterns using Expanded.

// 1. App bar with title
class AppBarWithTitle extends StatelessWidget {
  const AppBarWithTitle({super.key});

  @override
  Widget build(BuildContext context) {
    return Container(
      height: 56,
      color: Colors.blue,
      padding: const EdgeInsets.symmetric(horizontal: 16),
      child: Row(
        children: [
          const Icon(Icons.menu, color: Colors.white),
          const SizedBox(width: 16),
          // Title expands to fill center space
          Expanded(
            child: const Text(
              'App Title',
              style: TextStyle(
                color: Colors.white,
                fontSize: 20,
                fontWeight: FontWeight.bold,
              ),
            ),
          ),
          const Icon(Icons.search, color: Colors.white),
          const SizedBox(width: 16),
          const Icon(Icons.more_vert, color: Colors.white),
        ],
      ),
    );
  }
}

// 2. Login screen with flexible layout
class LoginScreen extends StatelessWidget {
  const LoginScreen({super.key});

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Column(
        children: [
          // Logo takes some space
          const SizedBox(height: 60),
          const Icon(Icons.flutter_dash, size: 80, color: Colors.blue),
          const SizedBox(height: 20),
          const Text(
            'Welcome',
            style: TextStyle(
              fontSize: 28,
              fontWeight: FontWeight.bold,
            ),
          ),

          // Form takes remaining space
          Expanded(
            child: Padding(
              padding: const EdgeInsets.all(24),
              child: Column(
                mainAxisAlignment: MainAxisAlignment.center,
                children: [
                  const TextField(
                    decoration: InputDecoration(
                      labelText: 'Email',
                      border: OutlineInputBorder(),
                    ),
                  ),
                  const SizedBox(height: 16),
                  const TextField(
                    decoration: InputDecoration(
                      labelText: 'Password',
                      border: OutlineInputBorder(),
                    ),
                    obscureText: true,
                  ),
                  const SizedBox(height: 24),
                  SizedBox(
                    width: double.infinity,
                    child: ElevatedButton(
                      onPressed: () {},
                      child: const Text('Login'),
                    ),
                  ),
                ],
              ),
            ),
          ),
        ],
      ),
    );
  }
}

// 3. Card with expandable content
class ExpandableCard extends StatelessWidget {
  const ExpandableCard({super.key});

  @override
  Widget build(BuildContext context) {
    return Card(
      margin: const EdgeInsets.all(8),
      child: Column(
        children: [
          // Fixed header
          Container(
            padding: const EdgeInsets.all(16),
            color: Colors.blue,
            child: const Row(
              children: [
                Icon(Icons.info, color: Colors.white),
                SizedBox(width: 8),
                Text(
                  'Card Header',
                  style: TextStyle(
                    color: Colors.white,
                    fontWeight: FontWeight.bold,
                  ),
                ),
              ],
            ),
          ),

          // Expandable content
          Expanded(
            child: Container(
              padding: const EdgeInsets.all(16),
              child: const Text(
                'This content expands to fill available space. '
                'It will take up all remaining space in the card.',
              ),
            ),
          ),

          // Fixed footer
          Container(
            padding: const EdgeInsets.all(16),
            child: Row(
              mainAxisAlignment: MainAxisAlignment.end,
              children: [
                TextButton(
                  onPressed: () {},
                  child: const Text('Cancel'),
                ),
                const SizedBox(width: 8),
                ElevatedButton(
                  onPressed: () {},
                  child: const Text('Save'),
                ),
              ],
            ),
          ),
        ],
      ),
    );
  }
}

// 4. Equal-height columns with Expanded
class EqualHeightColumns extends StatelessWidget {
  const EqualHeightColumns({super.key});

  @override
  Widget build(BuildContext context) {
    return SizedBox(
      height: 200,
      child: Row(
        children: [
          // Each column has equal height
          Expanded(
            child: Container(
              color: Colors.red[100],
              padding: const EdgeInsets.all(16),
              child: Column(
                children: [
                  const Icon(Icons.star, size: 40),
                  const SizedBox(height: 8),
                  const Text('Column 1'),
                  Expanded(
                    child: Container(
                      color: Colors.red[200],
                      child: const Center(
                        child: Text('Content 1'),
                      ),
                    ),
                  ),
                ],
              ),
            ),
          ),
          const SizedBox(width: 4),
          Expanded(
            child: Container(
              color: Colors.green[100],
              padding: const EdgeInsets.all(16),
              child: Column(
                children: [
                  const Icon(Icons.favorite, size: 40),
                  const SizedBox(height: 8),
                  const Text('Column 2'),
                  Expanded(
                    child: Container(
                      color: Colors.green[200],
                      child: const Center(
                        child: Text('Content 2'),
                      ),
                    ),
                  ),
                ],
              ),
            ),
          ),
          const SizedBox(width: 4),
          Expanded(
            child: Container(
              color: Colors.blue[100],
              padding: const EdgeInsets.all(16),
              child: Column(
                children: [
                  const Icon(Icons.person, size: 40),
                  const SizedBox(height: 8),
                  const Text('Column 3'),
                  Expanded(
                    child: Container(
                      color: Colors.blue[200],
                      child: const Center(
                        child: Text('Content 3'),
                      ),
                    ),
                  ),
                ],
              ),
            ),
          ),
        ],
      ),
    );
  }
}

What's happening here? - App bar with centered title - Login screen with flexible form - Card with expandable content - Equal-height columns with Expanded


Best Practices

Use Expanded for Remaining Space

// Good - Fills remaining space
@override
Widget build(BuildContext context) {
  return Row(
    children: [
      Text('Fixed'),
      Expanded(
        child: Text('This expands'),
      ),
    ],
  );
}

Use Flex Factors for Proportions

// Good - Proportional sizing
@override
Widget build(BuildContext context) {
  return Row(
    children: [
      Expanded(
        flex: 2,
        child: Container(color: Colors.red),
      ),
      Expanded(
        flex: 1,
        child: Container(color: Colors.blue),
      ),
    ],
  );
}

Avoid Overusing Expanded

// Good - Appropriate use
@override
Widget build(BuildContext context) {
  return Row(
    children: [
      // Only one Expanded needed
      Text('Fixed'),
      Expanded(child: Text('Expands')),
      Text('Fixed'),
    ],
  );
}

// Bad - Unnecessary Expanded
@override
Widget build(BuildContext context) {
  return Row(
    children: [
      Expanded(child: Text('All expanded')), // No need
      Expanded(child: Text('All expanded')), // No need
    ],
  );
}

Common Mistakes

Using Expanded Outside Flex

Wrong:

// Error: Expanded must be inside Flex
Container(
  child: Expanded(
    child: Text('Error'),
  ),
)

Correct:

// Expanded inside Row/Column/Flex
Row(
  children: [
    Expanded(
      child: Text('Correct'),
    ),
  ],
)

Not Using flex Factor

Wrong:

// All equal without reason
Row(
  children: [
    Expanded(child: Text('Short')),
    Expanded(child: Text('Very long text')),
  ],
)

Correct:

// Use flex for proportions
Row(
  children: [
    Expanded(
      flex: 1,
      child: Text('Short'),
    ),
    Expanded(
      flex: 3,
      child: Text('Very long text'),
    ),
  ],
)


Summary

Expanded fills available space in flex layouts. Use Expanded for remaining space, flex factors for proportions, and combine with fixed widgets for balanced layouts. Expanded is essential for creating responsive, adaptive UIs.


Next Steps


Did You Know?

  • Expanded = Flexible(fit: FlexFit.tight)
  • Multiple Expanded share space proportionally
  • flex factor controls space distribution
  • Expanded only works in Flex (Row/Column)
  • Expanded fills remaining space after fixed children
  • flex default is 1
  • Expanded can be nested
  • Expanded is essential for responsive layouts