> ## Documentation Index
> Fetch the complete documentation index at: https://resources.devweekends.com/llms.txt
> Use this file to discover all available pages before exploring further.

# 7. Flexbox Mastery

> Complete guide to Flexbox layout in React Native

## Learning Objectives

By the end of this module, you'll understand:

* Flexbox fundamentals and layout principles
* Flex direction and wrapping
* Justify content and align items
* Flex sizing (grow, shrink, basis)
* Absolute positioning
* Common layout patterns

***

## Flexbox Fundamentals

Flexbox is the primary layout system in React Native. Unlike CSS on the web, all components in React Native use Flexbox by default -- there is no `display: block` or `display: inline`. Everything is a flex container.

Think of Flexbox like packing items into a suitcase. You decide the direction items are placed (left-to-right or top-to-bottom), how leftover space is distributed, and what happens when items do not fit.

**Key difference from web CSS:** In React Native, the default `flexDirection` is `column` (vertical), not `row` (horizontal). This matches mobile conventions where screens are taller than they are wide and content naturally flows top-to-bottom.

```jsx theme={null}
import { View, StyleSheet } from 'react-native';

function FlexExample() {
  return (
    <View style={styles.container}>
      <View style={[styles.box, { backgroundColor: 'red' }]} />
      <View style={[styles.box, { backgroundColor: 'green' }]} />
      <View style={[styles.box, { backgroundColor: 'blue' }]} />
    </View>
  );
}

const styles = StyleSheet.create({
  container: {
    flex: 1,                    // Takes all available space
    flexDirection: 'column',    // Default: stacks vertically
  },
  box: {
    width: 50,
    height: 50,
  },
});
```

***

## Flex Direction

Controls the **main axis** -- the direction children are laid out. Once you set the main axis, the **cross axis** is always perpendicular to it. Every alignment property in Flexbox refers to one of these two axes, so understanding this distinction is critical.

| Value            | Description                |
| ---------------- | -------------------------- |
| `column`         | Vertical stack (default)   |
| `row`            | Horizontal stack           |
| `column-reverse` | Vertical, reversed order   |
| `row-reverse`    | Horizontal, reversed order |

```jsx theme={null}
// Horizontal layout
<View style={{ flexDirection: 'row' }}>
  <Text>First</Text>
  <Text>Second</Text>
  <Text>Third</Text>
</View>

// Vertical layout (default)
<View style={{ flexDirection: 'column' }}>
  <Text>Top</Text>
  <Text>Middle</Text>
  <Text>Bottom</Text>
</View>
```

***

## Justify Content

Aligns children along the **main axis**:

```jsx theme={null}
// Center items horizontally in a row
<View style={{ flexDirection: 'row', justifyContent: 'center' }}>
  <Text>Centered</Text>
</View>

// Space items evenly
<View style={{ flexDirection: 'row', justifyContent: 'space-between' }}>
  <Text>Left</Text>
  <Text>Center</Text>
  <Text>Right</Text>
</View>
```

### Justify Content Options:

* `flex-start` (default) - Align to start
* `flex-end` - Align to end
* `center` - Center items
* `space-between` - Even spacing, edges at container bounds
* `space-around` - Even spacing including before first and after last
* `space-evenly` - Equal spacing between all items including edges

***

## Align Items

Aligns children along the **cross axis**:

```jsx theme={null}
// Stretch children to fill cross axis (default)
<View style={{ alignItems: 'stretch' }}>
  <View style={{ height: 50 }} />  // Width fills container
</View>

// Center items vertically
<View style={{ 
  flexDirection: 'row', 
  height: 200,
  alignItems: 'center' 
}}>
  <Text>Vertically centered</Text>
</View>
```

### Align Items Options:

* `stretch` (default) - Stretch to fill
* `flex-start` - Align to cross-start
* `flex-end` - Align to cross-end
* `center` - Center on cross axis
* `baseline` - Align text baselines

***

## Align Self

Override alignItems for individual children:

```jsx theme={null}
<View style={{ alignItems: 'flex-start' }}>
  <Text>Aligned start</Text>
  <Text style={{ alignSelf: 'flex-end' }}>Aligned end</Text>
  <Text style={{ alignSelf: 'center' }}>Centered</Text>
</View>
```

***

## Flex Sizing

Flex sizing controls how available space is distributed among children. Think of it like splitting a restaurant bill: `flex` values are each person's share. A child with `flex: 2` gets twice the space of a sibling with `flex: 1`.

### flex

Defines how a component grows relative to siblings:

```jsx theme={null}
// Both children share space equally
<View style={{ flexDirection: 'row' }}>
  <View style={{ flex: 1, backgroundColor: 'red' }} />
  <View style={{ flex: 1, backgroundColor: 'blue' }} />
</View>

// First takes 2/3, second takes 1/3
<View style={{ flexDirection: 'row' }}>
  <View style={{ flex: 2, backgroundColor: 'red' }} />
  <View style={{ flex: 1, backgroundColor: 'blue' }} />
</View>

// First is fixed, second fills remaining space
<View style={{ flexDirection: 'row' }}>
  <View style={{ width: 100, backgroundColor: 'red' }} />
  <View style={{ flex: 1, backgroundColor: 'blue' }} />
</View>
```

### flexGrow

Similar to `flex`, but the key difference is that `flexGrow` distributes *extra* space after each child's base size is accounted for, while `flex` ignores base size entirely. In practice, use `flex` for simple proportional layouts and `flexGrow` when children have a meaningful minimum width/height:

```jsx theme={null}
<View style={{ flexDirection: 'row' }}>
  <View style={{ 
    flexGrow: 1, 
    width: 50,          // Base size
    backgroundColor: 'red' 
  }} />
  <View style={{ 
    flexGrow: 2, 
    width: 50,          // Base size
    backgroundColor: 'blue' 
  }} />
</View>
```

### flexShrink

Controls how components shrink when space is limited:

```jsx theme={null}
<View style={{ flexDirection: 'row', width: 200 }}>
  <View style={{ 
    flexShrink: 0,      // Don't shrink below width
    width: 150,
    backgroundColor: 'red' 
  }} />
  <View style={{ 
    flexShrink: 1,      // Can shrink
    width: 150,
    backgroundColor: 'blue' 
  }} />
</View>
```

### flexBasis

Sets the initial size before flexGrow/flexShrink:

```jsx theme={null}
<View style={{ flexDirection: 'row' }}>
  <View style={{ 
    flexBasis: 100,     // Start at 100, can grow
    flexGrow: 1,
    backgroundColor: 'red' 
  }} />
  <View style={{ 
    flexBasis: '50%',   // Percentage also works
    flexGrow: 1,
    backgroundColor: 'blue' 
  }} />
</View>
```

***

## Flex Wrap

Controls wrapping of flex items:

```jsx theme={null}
// Items wrap to next line when overflow
<View style={{ 
  flexDirection: 'row', 
  flexWrap: 'wrap',
}}>
  {items.map(item => (
    <View key={item.id} style={styles.item} />
  ))}
</View>

const styles = StyleSheet.create({
  item: {
    width: '50%',        // Two items per row
    padding: 10,
  },
});
```

### Flex Wrap Options:

* `nowrap` (default) - Single line
* `wrap` - Multi-line, top to bottom
* `wrap-reverse` - Multi-line, bottom to top

***

## Align Content

Aligns wrapped lines within container (only works with flexWrap):

```jsx theme={null}
<View style={{ 
  flexDirection: 'row', 
  flexWrap: 'wrap',
  alignContent: 'center',    // Centers wrapped lines
}}>
  {/* Multiple rows of items */}
</View>
```

Options: `flex-start`, `flex-end`, `center`, `stretch`, `space-between`, `space-around`

***

## Positioning

React Native supports two positioning modes. Relative positioning is the default and rarely needs to be set explicitly. Absolute positioning removes an element from the normal layout flow -- it no longer pushes other elements around, similar to pulling a sticky note off a stack and placing it anywhere on your desk.

### Relative Positioning (Default)

Elements positioned according to normal flow, with optional offsets from their natural position:

```jsx theme={null}
<View style={{ position: 'relative', top: 10, left: 20 }}>
  {/* Offset from original position */}
</View>
```

### Absolute Positioning

Removes element from document flow:

```jsx theme={null}
// Parent must have relative/absolute position
<View style={{ position: 'relative', flex: 1 }}>
  {/* Positioned relative to parent */}
  <View style={{ 
    position: 'absolute',
    top: 0,
    left: 0,
    right: 0,
    bottom: 0,
    backgroundColor: 'rgba(0,0,0,0.5)'
  }}>
    <Text>Overlay</Text>
  </View>
</View>
```

### Absolute Fill Shortcut

```jsx theme={null}
import { StyleSheet } from 'react-native';

// Using spread
<View style={{ ...StyleSheet.absoluteFill, backgroundColor: 'blue' }} />

// Or
<View style={[StyleSheet.absoluteFill, { backgroundColor: 'blue' }]} />

// Equivalent to:
<View style={{
  position: 'absolute',
  top: 0,
  left: 0,
  right: 0,
  bottom: 0,
}} />
```

***

## Z-Index

Controls stacking order of positioned elements:

```jsx theme={null}
<View style={{ position: 'relative' }}>
  <View style={{ 
    position: 'absolute',
    zIndex: 1,
    backgroundColor: 'red'
  }} />
  <View style={{ 
    position: 'absolute',
    zIndex: 2,              // On top
    backgroundColor: 'blue'
  }} />
</View>
```

***

## Common Layout Patterns

### Center Content

```jsx theme={null}
const styles = StyleSheet.create({
  center: {
    flex: 1,
    justifyContent: 'center',
    alignItems: 'center',
  },
});
```

### Row with Space Between

```jsx theme={null}
const styles = StyleSheet.create({
  rowBetween: {
    flexDirection: 'row',
    justifyContent: 'space-between',
    alignItems: 'center',
    padding: 16,
  },
});
```

### Sticky Footer

```jsx theme={null}
function ScreenWithFooter() {
  return (
    <View style={{ flex: 1 }}>
      <ScrollView style={{ flex: 1 }}>
        {/* Scrollable content */}
      </ScrollView>
      <View style={{ padding: 16 }}>
        {/* Footer content */}
        <Button title="Submit" />
      </View>
    </View>
  );
}
```

### Sidebar Layout

```jsx theme={null}
function SplitScreen() {
  return (
    <View style={{ flex: 1, flexDirection: 'row' }}>
      <View style={{ width: 250, backgroundColor: '#f5f5f5' }}>
        {/* Sidebar */}
      </View>
      <View style={{ flex: 1 }}>
        {/* Main content */}
      </View>
    </View>
  );
}
```

### Grid Layout

```jsx theme={null}
function Grid({ data }) {
  return (
    <View style={{ flexDirection: 'row', flexWrap: 'wrap' }}>
      {data.map(item => (
        <View 
          key={item.id} 
          style={{ width: '33.33%', padding: 8 }}
        >
          <Card item={item} />
        </View>
      ))}
    </View>
  );
}
```

### Card with Overlay

```jsx theme={null}
function CardWithOverlay({ image, title, onPress }) {
  return (
    <TouchableOpacity style={{ position: 'relative' }}>
      <Image source={image} style={{ width: '100%', height: 200 }} />
      <View style={{
        ...StyleSheet.absoluteFill,
        backgroundColor: 'rgba(0,0,0,0.3)',
        justifyContent: 'flex-end',
        padding: 16,
      }}>
        <Text style={{ color: 'white', fontSize: 18 }}>{title}</Text>
      </View>
    </TouchableOpacity>
  );
}
```

***

## Gap Property

Before `gap`, you had to use margins on individual children to space them apart, which always created an unwanted margin on the first or last item. `gap` solves this cleanly -- it adds space *between* items only, never at the edges. If you have used CSS Grid's `gap`, this is the same concept.

```jsx theme={null}
// Add space between items
<View style={{ 
  flexDirection: 'row',
  gap: 16,          // 16px gap between items
}}>
  <Button title="Cancel" />
  <Button title="Confirm" />
</View>

// Row and column gaps
<View style={{ 
  flexDirection: 'row',
  flexWrap: 'wrap',
  rowGap: 16,       // Vertical gap
  columnGap: 8,     // Horizontal gap
}}>
  {items.map(item => <Card key={item.id} />)}
</View>
```

**Note:** Gap property requires React Native 0.71+ or Expo SDK 48+

***

## Layout Props Reference

### Container Props

| Prop             | Type   | Description             |
| ---------------- | ------ | ----------------------- |
| `flex`           | number | Grow factor             |
| `flexDirection`  | string | Layout direction        |
| `flexWrap`       | string | Wrapping behavior       |
| `justifyContent` | string | Main axis alignment     |
| `alignItems`     | string | Cross axis alignment    |
| `alignContent`   | string | Wrapped lines alignment |

### Item Props

| Prop         | Type          | Description                   |
| ------------ | ------------- | ----------------------------- |
| `alignSelf`  | string        | Override container alignItems |
| `flexGrow`   | number        | Growth factor                 |
| `flexShrink` | number        | Shrink factor                 |
| `flexBasis`  | number/string | Initial size                  |

### Position Props

| Prop       | Type   | Description                  |
| ---------- | ------ | ---------------------------- |
| `position` | string | `'relative'` or `'absolute'` |
| `top`      | number | Offset from top              |
| `bottom`   | number | Offset from bottom           |
| `left`     | number | Offset from left             |
| `right`    | number | Offset from right            |
| `zIndex`   | number | Stacking order               |

***

## Best Practices

1. **Use `flex: 1`** for components that should fill available space -- this is the single most important Flexbox pattern in React Native. Forgetting it is the most common reason a screen appears blank.
2. **Avoid fixed dimensions** when possible -- use `flex` and percentages. Fixed pixel values that look perfect on your test device will break on a different screen size.
3. **Center anything** with `justifyContent: 'center'` and `alignItems: 'center'` -- this two-property combo works regardless of `flexDirection` and is the universal centering recipe.
4. **Understand the axes** -- `justifyContent` controls the main axis (direction of `flexDirection`), `alignItems` controls the cross axis (perpendicular). This is the mental model that makes all of Flexbox click.
5. **Use `gap` instead of margins** for spacing between items -- it is cleaner, avoids edge-margin bugs, and requires React Native 0.71+.
6. **Test on extreme screen sizes** -- Flexbox is responsive by default, but edge cases like the iPhone SE (320pt wide) and iPad (768pt+ wide) often reveal layout assumptions. Run your app on both during development.
