# Flex
> A layout primitive that aligns elements horizontally or vertically and injects white space between them.

## Import

```js
import { Flex, FlexItem } from '@gemini-suite/vera-react';
```

- `Flex`: The main wrapper with `display: flex`.
- `FlexItem`: Used as a child of `Flex` to control growing and shrinking based on available space.

## Background

The primary job of **Flex** is to lay out a horizontal row of content or a vertical stack of content.
On top of that it provides fine-grained control of spacing and alignment, making it a perfect candidate for small-scale layout tasks.

<Callout variant="tip">

If you need to lay out content over many columns and rows, [consider Grid as an alternative](/components/layout/grid).

</Callout>

**Flex** is abstraction over [CSS Flexbox Module](https://www.w3.org/TR/css-flexbox-1/).

<Grid
  columns={{
    '@initial': '1',
    '@mqLargeAndUp': '2'
  }}
  columnGap="spacingL"
  className="mTm"
>
  <GridItem>
    <Card
      href="https://web.dev/learn/css/flexbox/"
      title="Learn more about CSS Flexbox"
      actionIcon="externalLink"
    />
  </GridItem>
</Grid>

## Examples

### Flow

#### Horizontal

```jsx
<Flex as="ul" gap="spacingL" flow="row" padding="none">
  <Box
    as="li"
    css={{
      padding: '$spacingS',
      backgroundColor: '$backgroundNeutralModerate'
    }}
  >
    Item 1
  </Box>
  <Box
    as="li"
    css={{
      padding: '$spacingS',
      backgroundColor: '$backgroundNeutralModerate'
    }}
  >
    Item 2
  </Box>
  <Box
    as="li"
    css={{
      padding: '$spacingS',
      backgroundColor: '$backgroundNeutralModerate'
    }}
  >
    Item 3
  </Box>
</Flex>
```

#### Vertical

Change `flow` to `column` to render items in a stack.

```jsx
<Flex as="ul" gap="spacingM" flow="column" padding="none">
  <Box
    as="li"
    css={{
      padding: '$spacingS',
      backgroundColor: '$backgroundNeutralModerate'
    }}
  >
    Item 1
  </Box>
  <Box
    as="li"
    css={{
      padding: '$spacingS',
      backgroundColor: '$backgroundNeutralModerate'
    }}
  >
    Item 2
  </Box>
  <Box
    as="li"
    css={{
      padding: '$spacingS',
      backgroundColor: '$backgroundNeutralModerate'
    }}
  >
    Item 3
  </Box>
</Flex>
```

#### Reversed

You can reverse the visual flow using `flow="column-reverse"`

```jsx
<Flex flow="column-reverse">
  <ExampleBox>1</ExampleBox>
  <ExampleBox>2</ExampleBox>
  <ExampleBox>3</ExampleBox>
</Flex>
```

And `row-reverse`

```jsx
<Flex flow="row-reverse" main="center">
  <ExampleBox>1</ExampleBox>
  <ExampleBox>2</ExampleBox>
  <ExampleBox>3</ExampleBox>
</Flex>
```

### White space

Flow elements require space to physically and conceptually separate them from the elements that come before and after them.
Ideally these elements should not provide surrounding white space, instead spacing should be owned by layout components.
**Flex** is exactly such a layout primitive: it injects gap between elements via their common parent.

<Callout variant="tip">

Vera provides [a standard white space scale](/tokens/white-space) that is
available across all layout components via `gap` property.

</Callout>

#### spacingS

```jsx
<Flex gap="spacingS">
  <ExampleBox />
  <ExampleBox />
  <ExampleBox />
</Flex>
```

#### spacingXl

```jsx
<Flex gap="spacingXl">
  <ExampleBox />
  <ExampleBox />
  <ExampleBox />
</Flex>
```

#### Different spacing per breakpoint

```jsx
<Flex
  flow="column"
  gap={{
    '@initial': 'spacingS',
    '@mqLargeAndUp': 'spacingM'
  }}
  cross="center"
>
  <SvgIcon iconName="box" size="large" css={{ color: '$colorBlue100' }} />
  <Heading as="h3" marginY="none">
    Heading text
  </Heading>
  <Text>Lorem ipsum dolor sit amet.</Text>
</Flex>
```

### Wrap

Control content wrapping via `wrap` property. Items inside `Flex` will wrap onto multiple lines naturally, and without the need for any viewport `@media` queries.

```jsx
<Flex wrap="wrap-reverse" gap="spacingS">
  {Array(16)
    .fill()
    .map((_, i) => (
      <ExampleBox key={i}>{i + 1}</ExampleBox>
    ))}
</Flex>
```

#### List of tags

```jsx
<Flex as="ul" wrap="wrap" gap="spacingS" padding="none" marginBottom="none">
  <Label as="li">Label</Label>
  <Label as="li" color="accent">
    Label
  </Label>
  <Label as="li" color="info">
    Label
  </Label>
  <Label as="li" color="warning">
    Label
  </Label>
  <Label as="li" color="danger">
    Label
  </Label>
  <Label as="li" color="success">
    Label
  </Label>
  <Label as="li" variant="subtle">
    Label
  </Label>
  <Label as="li" color="accent" variant="subtle">
    Label
  </Label>
  <Label as="li" color="info" variant="subtle">
    Label
  </Label>
  <Label as="li" color="warning" variant="subtle">
    Label
  </Label>
  <Label as="li" color="danger" variant="subtle">
    Label
  </Label>
  <Label as="li" color="success" variant="subtle">
    Label
  </Label>
</Flex>
```

### Alignment

Since **Flex** layout is used to lay out elements in horizontal rows or vertical columns, use `main` and `cross` to align the items across main axis or cross axis.

#### main="end"

```jsx
<React.Fragment>
  <Flex
    css={{
      width: '25rem',
      maxWidth: '100%',
      backgroundColor: '$colorBlue10'
    }}
    main="end"
  >
    <ExampleBox />
    <ExampleBox />
    <ExampleBox />
  </Flex>
  <Flex
    flow="column"
    main="end"
    css={{
      width: '25rem',
      height: '15rem',
      maxWidth: '100%',
      backgroundColor: '$colorBlue10',
      mt: '$spacingM'
    }}
  >
    <ExampleBox />
    <ExampleBox />
    <ExampleBox />
  </Flex>
</React.Fragment>
```

#### main="center"

```jsx
<React.Fragment>
  <Flex
    css={{
      width: '25rem',
      maxWidth: '100%',
      backgroundColor: '$colorBlue10'
    }}
    main="center"
  >
    <ExampleBox />
    <ExampleBox />
    <ExampleBox />
  </Flex>
  <Flex
    css={{
      width: '25rem',
      maxWidth: '100%',
      height: '15rem',
      backgroundColor: '$colorBlue10',
      mt: '$spacingM'
    }}
    flow="column"
    main="center"
  >
    <ExampleBox />
    <ExampleBox />
    <ExampleBox />
  </Flex>
</React.Fragment>
```

#### cross="center"

<Callout variant="tip">
  When `flow` is set to horizontal (`row` or `row-reverse`), items are centered
  on the cross axis by default.
</Callout>

```jsx
<React.Fragment>
  <Flex
    css={{
      width: '25rem',
      maxWidth: '100%',
      backgroundColor: '$colorBlue10'
    }}
    flow="row"
  >
    <ExampleBox css={{ height: '6rem' }} />
    <ExampleBox css={{ height: '4.5rem' }} />
    <ExampleBox />
  </Flex>
  <Flex
    css={{
      width: '25rem',
      maxWidth: '100%',
      backgroundColor: '$colorBlue10',
      mt: '$spacingM'
    }}
    flow="column"
    cross="center"
  >
    <ExampleBox />
    <ExampleBox css={{ width: '25%' }} />
    <ExampleBox css={{ width: '50%' }} />
  </Flex>
</React.Fragment>
```

#### main="space-between"

Spacing between items is now controlled by the container size:

```jsx
<React.Fragment>
  <Flex
    css={{
      width: '25rem',
      maxWidth: '100%',
      backgroundColor: '$colorBlue10'
    }}
    flow="row"
    main="space-between"
  >
    <ExampleBox css={{ width: '4rem' }} />
    <ExampleBox />
    <ExampleBox css={{ width: '4rem' }} />
  </Flex>
  <Flex
    css={{
      width: '25rem',
      height: '15rem',
      maxWidth: '100%',
      backgroundColor: '$colorBlue10',
      mt: '$spacingM'
    }}
    flow="column"
    main="space-between"
  >
    <ExampleBox css={{ width: '25%' }} />
    <ExampleBox css={{ width: '50%' }} />
    <ExampleBox />
  </Flex>
</React.Fragment>
```

#### Buttons aligned to the right

```jsx
<Flex main="end">
  <Button variant="outline">Secondary action</Button>
  <Button>Primary action</Button>
</Flex>
```

#### Complex buttons layout

```jsx
<Flex main="space-between" cross="center" wrap="wrap-reverse">
  <Button variant="ghost">Ghost button</Button>
  <Flex>
    <Button variant="outline">Outline button</Button>
    <Button>Fill button</Button>
  </Flex>
</Flex>
```

### Flex item

You can use `FlexItem` component to control how a flex item will behave inside a `Flex` container. `FlexItem` exposes properties such as `flex`, `grow` and `shrink`. You can also change `cross` alignment and `order` on an individual flex item.

#### flex

`flex` property sets how a `FlexItem` will grow or shrink to fit the available space.

##### flex="initial" (default)

The item is sized according to its content or the value of its width and height properties. It shrinks to its minimum size to fit the container, but does not grow to absorb any extra free space in the flex container. This is equivalent to `flex: 0 1 auto` in CSS and is the default behavior for the children elements within a `Flex` container.

```jsx
<Flex cross="start">
  <FlexItem flex="initial">
    <ExampleBox>
      <FakeText words="1" />
    </ExampleBox>
  </FlexItem>
  <FlexItem flex="initial">
    <ExampleBox>
      <FakeText words="3" />
    </ExampleBox>
  </FlexItem>
  <FlexItem flex="initial">
    <ExampleBox>
      <FakeText words="5, 10" />
    </ExampleBox>
  </FlexItem>
</Flex>
```

##### flex="1"

The item will grow to absorb any extra free space in the flex container and shrink as needed to fit the container without taking its initial size into account. This is equivalent to `flex: 1 1 0%` in CSS. Useful to set all items to be of equal width no matter their content.

```jsx
<Flex cross="start">
  <FlexItem flex="1">
    <ExampleBox>
      <FakeText words="1" />
    </ExampleBox>
  </FlexItem>
  <FlexItem flex="1">
    <ExampleBox>
      <FakeText words="3" />
    </ExampleBox>
  </FlexItem>
  <FlexItem flex="1">
    <ExampleBox>
      <FakeText words="5, 10" />
    </ExampleBox>
  </FlexItem>
</Flex>
```

##### flex="auto"

The item is sized according to its content or the value of its width and height properties, but grows to absorb any extra free space in the flex container, and shrinks to its minimum size to fit the container. This is equivalent to `flex: 1 1 auto` in CSS.

```jsx
<Flex cross="start">
  <FlexItem flex="auto">
    <ExampleBox>
      <FakeText words="1" />
    </ExampleBox>
  </FlexItem>
  <FlexItem flex="auto">
    <ExampleBox>
      <FakeText words="3" />
    </ExampleBox>
  </FlexItem>
  <FlexItem flex="auto">
    <ExampleBox>
      <FakeText words="5, 10" />
    </ExampleBox>
  </FlexItem>
</Flex>
```

##### flex="none"

The item is sized according to its content or the value of its width and height properties. It is fully inflexible: it neither shrinks nor grows in relation to the flex container.

```jsx
<Flex cross="start">
  <FlexItem flex="1">
    <ExampleBox striped>Item that can grow or shrink if needed</ExampleBox>
  </FlexItem>
  <FlexItem flex="auto">
    <ExampleBox>Item that cannot grow or shrink</ExampleBox>
  </FlexItem>
  <FlexItem flex="1">
    <ExampleBox striped>Item that can grow or shrink if needed</ExampleBox>
  </FlexItem>
</Flex>
```

#### grow

Use `grow` property to control how `FlexItem` grows.

```jsx
<Flex cross="start">
  <FlexItem flex="none">
    <ExampleBox striped>Item that cannot grow</ExampleBox>
  </FlexItem>
  <FlexItem grow="1">
    <ExampleBox>Item that grows</ExampleBox>
  </FlexItem>
  <FlexItem flex="none">
    <ExampleBox striped>Item that cannot grow</ExampleBox>
  </FlexItem>
</Flex>
```

#### shrink

Use `shrink` property to control how `FlexItem` shrinks.

```jsx
<Flex cross="start">
  <FlexItem>
    <ExampleBox striped>
      <FakeText words="10, 15" />
    </ExampleBox>
  </FlexItem>
  <FlexItem>
    <ExampleBox striped>
      <FakeText words="10, 15" />
    </ExampleBox>
  </FlexItem>
  <FlexItem shrink="0">
    <ExampleBox>This item will not shrink below its initial size</ExampleBox>
  </FlexItem>
</Flex>
```

#### order

Use `order` property to render `FlexItem` in a different order than it appears in the source code.

```jsx
<Flex main="space-between">
  <FlexItem order="last">
    <ExampleBox>1</ExampleBox>
  </FlexItem>
  <FlexItem>
    <ExampleBox striped>2</ExampleBox>
  </FlexItem>
  <FlexItem>
    <ExampleBox striped>3</ExampleBox>
  </FlexItem>
</Flex>
```

#### alignment

Use `crossSelf` property to align individual `FlexItem` on the cross axis.

```jsx
<Flex cross="start" css={{ height: '6rem', backgroundColor: '$colorBlue10' }}>
  <FlexItem flex="1">
    <ExampleBox striped />
  </FlexItem>
  <FlexItem flex="1" crossSelf="center">
    <ExampleBox />
  </FlexItem>
  <FlexItem flex="1" crossSelf="end">
    <ExampleBox />
  </FlexItem>
</Flex>
```

#### Shrinking past content size

There is a behavior that can sometimes be surprising when using Flex layout. The content of a `FlexItem` can force it to not shrink properly, for example when you have a long word or URL that you want to truncate.
The reason is that flex items won’t shrink below their minimum content size.

```jsx
<Flex flow="column" as="ul">
  <ExampleBox as="li" display="block" borderRadius="spacingS">
    <Flex>
      <FlexItem
        shrink="0"
        css={{
          width: '2.5rem',
          height: '2.5rem',
          borderRadius: '50%',
          backgroundColor: '$backgroundNeutral'
        }}
      />
      <FlexItem flex="auto">
        <Text as="p" marginBottom="none" overflowStrategy="truncate">
          Textwithverylongtitletobefitinthatspaceoktextwithverylongtitletobefitinthatspaceoktextwithverylong
        </Text>
      </FlexItem>
      <FlexItem shrink="0">
        <Button variant="ghost" rightIcon={<SvgIcon iconName="arrowRight" />}>
          View more
        </Button>
      </FlexItem>
    </Flex>
  </ExampleBox>
  <ExampleBox as="li" display="block" borderRadius="spacingS" striped>
    <Flex>
      <FlexItem
        shrink="0"
        css={{
          width: '2.5rem',
          height: '2.5rem',
          borderRadius: '50%',
          backgroundColor: '$backgroundNeutral'
        }}
      />
      <FlexItem flex="auto" className="txtTruncate">
        <FakeText words="20, 25" />
      </FlexItem>
      <FlexItem shrink="0">
        <Button variant="ghost" rightIcon={<SvgIcon iconName="arrowRight" />}>
          View more
        </Button>
      </FlexItem>
    </Flex>
  </ExampleBox>
</Flex>
```

You can get around this behavior by setting `shrinkPastContentSize` property which applies `min-width: 0` to the flex item.

```jsx
<ExampleBox display="block" borderRadius="spacingS">
  <Flex>
    <FlexItem
      shrink="0"
      css={{
        width: '2.5rem',
        height: '2.5rem',
        borderRadius: '50%',
        backgroundColor: '$backgroundNeutral'
      }}
    />
    <FlexItem flex="auto" shrinkPastContentSize>
      <Text as="p" marginBottom="none" overflowStrategy="truncate">
        Textwithverylongtitletobefitinthatspaceoktextwithverylongtitletobefitinthatspaceok
      </Text>
    </FlexItem>
    <FlexItem shrink="0">
      <Button variant="ghost" rightIcon={<SvgIcon iconName="arrowRight" />}>
        View more
      </Button>
    </FlexItem>
  </Flex>
</ExampleBox>
```

### Nesting

Multiple `Flex` components can be nested. Below is a demo of a nested structure to create more complex white space rules.

```jsx
<Flex flow="column">
  <FormField.Root as={Flex} flow="column">
    <FormField.Label>{'Name'}</FormField.Label>
    <TextInput />
  </FormField.Root>
  <FormField.Root as={Flex} flow="column" validationStatus="error">
    <FormField.Label>Email</FormField.Label>
    <TextInput />
    <FormField.FeedbackMessage>
      <FormField.FeedbackIcon />
      {'Please provide a valid e-mail address.'}
    </FormField.FeedbackMessage>
  </FormField.Root>
  <Flex main="end">
    <Button>Submit</Button>
  </Flex>
</Flex>
```

---

## API Reference

### Flex

<Callout variant="tip">

In addition to the props below, you can pass [Box props](/components/layout/box#api-reference) to control the spacing.

</Callout>

| Name      | Type                                                                        | Default      | Description                                                                                                                                                                                                                                                                                  | Required |
| --------- | --------------------------------------------------------------------------- | ------------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------- |
| `as`      | `keyof JSX.IntrinsicElements \| React.ComponentType<any>`                   | `div`        | Change the component to a different HTML tag or custom component. This will merge the original component props with the props of the supplied element/component and change the underlying DOM node.   For more details, read our [Composition](/get-started/composition#polymorphism) guide. |          |
| `css`     | `StitchesCss`                                                               |              | Apply styles directly to a component in a similar way how you would define inline styles. Vera uses [Stitches](https://stitches.dev/) under the hood with a fully-typed API and support for features like tokens, media queries or variants.                                                 |          |
| `display` | `"flex" \| "inline-flex"`                                                   | `"flex"`     | Set block or inline display of the flex container.                                                                                                                                                                                                                                           |          |
| `flow`    | `"row" \| "row-reverse" \| "column" \| "column-reverse"`                    | `"row"`      | Set how items are placed in the flex container, defining the main axis and the direction.                                                                                                                                                                                                    |          |
| `main`    | `"start" \| "center" \| "end" \| "stretch" \| "space-between" \| "inherit"` |              | Alignment of the items across main axis.                                                                                                                                                                                                                                                     |          |
| `cross`   | `"start" \| "center" \| "end" \| "baseline" \| "stretch" \| "inherit"`      |              | Alignment of the items across cross axis. Defaults to `center` when `flow` is set to `row` or `row-reverse`.                                                                                                                                                                                 |          |
| `wrap`    | `"wrap" \| "nowrap" \| "revert" \| "wrap-reverse"`                          |              | Control content wrapping.                                                                                                                                                                                                                                                                    |          |
| `gap`     | `SpacingToken`                                                              | `"spacingM"` | Spacing between items.                                                                                                                                                                                                                                                                       |          |

### FlexItem

<Callout variant="tip">

In addition to the props below, you can pass [Box props](/components/layout/box#api-reference) to control the spacing.

</Callout>

| Name                    | Type                                                                                                                 | Default | Description                                                                                                                                                                                                                                                                                  | Required |
| ----------------------- | -------------------------------------------------------------------------------------------------------------------- | ------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------- |
| `as`                    | `keyof JSX.IntrinsicElements \| React.ComponentType<any>`                                                            | `div`   | Change the component to a different HTML tag or custom component. This will merge the original component props with the props of the supplied element/component and change the underlying DOM node.   For more details, read our [Composition](/get-started/composition#polymorphism) guide. |          |
| `css`                   | `StitchesCss`                                                                                                        |         | Apply styles directly to a component in a similar way how you would define inline styles. Vera uses [Stitches](https://stitches.dev/) under the hood with a fully-typed API and support for features like tokens, media queries or variants.                                                 |          |
| `flex`                  | `"initial" \| "auto" \| "1" \| "none"`                                                                               |         | Control how flex item both grows and shrinks.                                                                                                                                                                                                                                                |          |
| `grow`                  | `"0" \| "1"`                                                                                                         |         | Control how flex item grows.                                                                                                                                                                                                                                                                 |          |
| `shrink`                | `"0" \| "1"`                                                                                                         |         | Control how flex item shrinks.                                                                                                                                                                                                                                                               |          |
| `crossSelf`             | `"auto" \| "start" \| "center" \| "end" \| "baseline" \| "stretch"`                                                  |         | Override default (or the one specified by `cross` property on `Flex`) alignment across cross axis for the individual flex item.                                                                                                                                                              |          |
| `order`                 | `"first" \| "last" \| "none" \| "1" \| "2" \| "3" \| "4" \| "5" \| "6" \| "7" \| "8" \| "9" \| "10" \| "11" \| "12"` |         | Control the order in which `FlexItem` appears in the `Flex` container.                                                                                                                                                                                                                       |          |
| `shrinkPastContentSize` | `boolean`                                                                                                            |         | When `true`, allows the flex item to be smaller than the size of its content.                                                                                                                                                                                                                |          |
