Overview

Expanded is a widget that expands its child to fill the available space along the main axis within a Row, Column, or Flex widget.

Expanded is a special case of the Flexible widget with fit: FlexFit.tight applied. This means it forces the child widget to occupy all allocated space. When multiple Expanded widgets exist, space is distributed proportionally according to their flex values.

See: https://api.flutter.dev/flutter/widgets/Expanded-class.html

When to use it?

  • When a widget needs to fill all remaining space within a Row/Column
  • When distributing space proportionally between multiple widgets
  • When making TextField or other input widgets use all available horizontal space
  • When creating responsive layouts
  • When using Spacer to push widgets apart

Basic Usage

// Filling remaining space in a Row
Row({
  children: [
    Container({ width: 100, height: 50, color: 'blue' }),
    Expanded({
      child: Container({ height: 50, color: 'red' })
    }),
    Container({ width: 100, height: 50, color: 'green' })
  ]
})

// Using in Column
Column({
  children: [
    Container({ height: 100, color: 'blue' }),
    Expanded({
      child: Container({ color: 'red' }) // Takes all remaining vertical space
    }),
    Container({ height: 100, color: 'green' })
  ]
})

Props

child (required)

Value: Widget

The child widget to be expanded.

Expanded({
  child: Container({ color: 'blue' })
})

flex

Value: number (default: 1)

Defines the proportion of space this widget should take compared to other Expanded/Flexible widgets. Higher values take more space.

  • Must be 0 or greater (negative values not allowed)
  • Default is 1
  • Space is distributed as a ratio with other flex children
Row({
  children: [
    Expanded({
      flex: 2, // Takes 2/3 of total space
      child: Container({ color: 'red' })
    }),
    Expanded({
      flex: 1, // Takes 1/3 of total space
      child: Container({ color: 'blue' })
    })
  ]
})

Advanced Usage

Proportional Space Distribution

Row({
  children: [
    Expanded({
      flex: 3, // 3/6 = 50%
      child: Container({ height: 100, color: 'red' })
    }),
    Expanded({
      flex: 2, // 2/6 = 33.33%
      child: Container({ height: 100, color: 'green' })
    }),
    Expanded({
      flex: 1, // 1/6 = 16.67%
      child: Container({ height: 100, color: 'blue' })
    })
  ]
})

Using with Fixed-Size Widgets

Row({
  children: [
    Icon({ icon: Icons.menu }), // Fixed size
    SizedBox({ width: 16 }), // Fixed spacing
    Expanded({
      child: Text('Long title that displays within available space')
    }),
    IconButton({ // Fixed size
      icon: Icons.more_vert,
      onPressed: () => {}
    })
  ]
})

Practical Examples

const searchBar = Container({
  padding: EdgeInsets.all(16),
  child: Row({
    children: [
      Expanded({
        child: TextField({
          decoration: InputDecoration({
            hintText: 'Search...',
            prefixIcon: Icon({ icon: Icons.search }),
            border: OutlineInputBorder({
              borderRadius: BorderRadius.circular(30)
            })
          })
        })
      }),
      SizedBox({ width: 12 }),
      IconButton({
        icon: Icons.filter_list,
        onPressed: () => console.log('Open filters')
      })
    ]
  })
});

Example 2: Chat Input

const chatInput = Container({
  padding: EdgeInsets.all(8),
  decoration: BoxDecoration({
    color: 'white',
    boxShadow: [
      BoxShadow({
        color: 'rgba(0, 0, 0, 0.1)',
        blurRadius: 4,
        offset: { x: 0, y: -2 }
      })
    ]
  }),
  child: Row({
    children: [
      IconButton({
        icon: Icons.attach_file,
        onPressed: () => {}
      }),
      Expanded({
        child: TextField({
          decoration: InputDecoration({
            hintText: 'Type a message...',
            border: InputBorder.none
          }),
          maxLines: 3
        })
      }),
      IconButton({
        icon: Icons.send,
        onPressed: () => {}
      })
    ]
  })
});

Example 3: Responsive Button Group

const responsiveButtons = Container({
  padding: EdgeInsets.all(16),
  child: Row({
    children: [
      Expanded({
        child: ElevatedButton({
          onPressed: () => console.log('Cancel'),
          style: ButtonStyle({
            backgroundColor: 'gray'
          }),
          child: Text('Cancel')
        })
      }),
      SizedBox({ width: 16 }),
      Expanded({
        flex: 2, // Confirm button is wider
        child: ElevatedButton({
          onPressed: () => console.log('Confirm'),
          child: Text('Confirm')
        })
      })
    ]
  })
});

Example 4: Using Spacer

// Spacer internally uses Expanded
const header = Container({
  padding: EdgeInsets.all(16),
  color: 'blue',
  child: Row({
    children: [
      Text('Logo', { style: TextStyle({ color: 'white', fontSize: 20 }) }),
      Spacer(), // Same as Expanded({ child: Container() })
      IconButton({
        icon: Icons.notifications,
        color: 'white',
        onPressed: () => {}
      }),
      IconButton({
        icon: Icons.account_circle,
        color: 'white',
        onPressed: () => {}
      })
    ]
  })
});

Difference from Flexible

Expanded is a special case of Flexible:

// These two are identical
Expanded({ 
  flex: 2, 
  child: widget 
})

Flexible({ 
  flex: 2, 
  fit: FlexFit.tight, // Key difference
  child: widget 
})
  • Expanded: Always takes all allocated space (tight)
  • Flexible: By default takes only needed space (loose)

Important Notes

  • Expanded must be a direct child of Row, Column, or Flex.
  • Cannot nest Expanded directly inside another Expanded or Flexible.
  • An error occurs if the parent widget has unbounded size in the main axis.
  • The flex value must be 0 or greater; negative values cause errors.
  • When using Expanded in nested Column/Row structures, you may need to wrap the inner Column/Row with Expanded.
  • Flexible: More flexible widget that Expanded is based on
  • Spacer: Special use of Expanded to create empty space
  • Row: Use Expanded in horizontal layouts
  • Column: Use Expanded in vertical layouts
  • Flex: Base widget for Row and Column