UNPKG

@dnb/eufemia

Version:

DNB Eufemia Design System UI Library

531 lines (453 loc) 13.6 kB
--- title: 'Flex.Container' description: '`Flex.Container` is a building block for CSS Grid based layouts.' version: 11.8.2 generatedAt: 2026-07-03T14:39:19.909Z checksum: 090b7d977ba4be5e2c4c04d199a30a4048416c59f443a56985df2f80629d9c40 --- # Flex.Container ## Import ```tsx import { Flex } from '@dnb/eufemia' render(<Flex.Container />) ``` ## Description `Flex.Container` is a building block for [CSS flexbox](https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_flexible_box_layout) based layout of contents and components. ## Relevant links - [Source code](https://github.com/dnbexperience/eufemia/tree/main/packages/dnb-eufemia/src/components/flex/Container.tsx) - [Docs code](https://github.com/dnbexperience/eufemia/tree/main/packages/dnb-design-system-portal/src/docs/uilib/layout/flex/container) **NB:** For form layouts, use [Flex.Stack](/uilib/layout/flex/stack/) instead. You can also use [Flex.Item](/uilib/layout/flex/item) or [Card](/uilib/components/card) for you inner wrappers: ```jsx import { Flex, Card } from '@dnb/eufemia' render( <Flex.Container> <Flex.Item>content</Flex.Item> <Card>content</Card> </Flex.Container> ) ``` But you can use it with what ever element too. It will wrap it in an `Flex.Item` to ensure the spacing is applied: ```jsx import { Flex } from '@dnb/eufemia' render( <Flex.Container> <div>content</div> <div>content</div> </Flex.Container> ) ``` During render, the items within the "Wrapper" container are wrapped with the same properties. This ensures that all the items have the same appearance. ### Align vs Justify `Flex.Container` has two props for positioning its children: `justify` and `align`. These map directly to CSS flexbox properties and their effect depends on the `direction` of the container: - **`justify`** controls placement along the **main axis** (CSS `justify-content`). - **`align`** controls alignment along the **cross axis** (CSS `align-items`). In practice, this means: | | `Flex.Horizontal` | `Flex.Vertical` | | ----------------------- | ------------------ | ------------------ | | **Center horizontally** | `justify="center"` | `align="center"` | | **Center vertically** | `align="center"` | `justify="center"` | The main axis follows the direction: horizontal for `Flex.Horizontal`, vertical for `Flex.Vertical`. The cross axis is always perpendicular. ### Horizontal and Vertical aliases For shortening the usage of `direction="..."`, you can use: - `<Flex.Vertical>` instead of `<Flex.Container direction="vertical">` ```jsx <Flex.Vertical> <Flex.Item>part of vertical alignment</Flex.Item> <Flex.Item>part of vertical alignment</Flex.Item> </Flex.Vertical> ``` - `<Flex.Horizontal>` instead of `<Flex.Container direction="horizontal">` ```jsx <Flex.Horizontal> <Flex.Item>part of horizontal alignment</Flex.Item> <Flex.Item>part of horizontal alignment</Flex.Item> </Flex.Horizontal> ``` ## Relevant links - [Source code](https://github.com/dnbexperience/eufemia/tree/main/packages/dnb-eufemia/src/components/flex/Container.tsx) - [Docs code](https://github.com/dnbexperience/eufemia/tree/main/packages/dnb-design-system-portal/src/docs/uilib/layout/flex/container/) ## Limitations The `Flex.Container` will iterate over its childrenToReact, but not the children of the children **NB:** This examples showcases the limitation: ```tsx import { Flex, Card } from '@dnb/eufemia' // The Cards will not get the spacing applied const MyItem = () => ( <> <Card>content</Card> <Card>content</Card> </> ) const MyContainer = () => ( <Flex.Container> <MyItem /> </Flex.Container> ) ``` ## How spacing is applied Nested components should preferably support [spacing properties](/uilib/layout/space/). When an element or component was given, that does not support spacing, it will still work out of the box as it gets wrapped in a spacing block. You may else wrap your custom component in a `Flex.Item` – this way, you still can change the spacing per component basis. Technically, `Flex.Container` checks if a nested component has a property called `_supportsSpacingProps`. So if you have a component that supports the [spacing properties](/uilib/layout/space/), you can add this property `ComponentName._supportsSpacingProps = true`. If you provide `false`, it will not support spacing. If the component is a wrapper component, and you want its children to support spacing, you can add this property `ComponentName._supportsSpacingProps = 'children'`. But for simplicity, you can use the HOC `Flex.withChildren`: ```tsx const Wrapper = Flex.withChildren(({ children }) => { return <div>{children}</div> }) render( <Flex.Container direction="vertical"> <Item /> <Wrapper> <Item /> <Item /> </Wrapper> <Item /> </Flex.Container> ) ``` ## Demos ### No properties ```tsx render( <Flex.Container> <Flex.Item> <TestElement>FlexItem</TestElement> </Flex.Item> <Flex.Item> <TestElement>FlexItem</TestElement> </Flex.Item> <Flex.Item> <TestElement>FlexItem</TestElement> </Flex.Item> <Flex.Item> <TestElement>FlexItem</TestElement> </Flex.Item> </Flex.Container> ) ``` ### Horizontal Flex.Item ```tsx render( <Flex.Container> <Flex.Item> <TestElement>FlexItem</TestElement> </Flex.Item> <Flex.Item> <TestElement>FlexItem</TestElement> </Flex.Item> <Flex.Item> <TestElement>FlexItem</TestElement> </Flex.Item> <Flex.Item> <TestElement>FlexItem</TestElement> </Flex.Item> </Flex.Container> ) ``` ### Horizontal Flex.Item, `justify="center"` ```tsx render( <Flex.Container justify="center"> <Flex.Item> <TestElement>FlexItem</TestElement> </Flex.Item> <Flex.Item> <TestElement>FlexItem</TestElement> </Flex.Item> <Flex.Item> <TestElement>FlexItem</TestElement> </Flex.Item> <Flex.Item> <TestElement>FlexItem</TestElement> </Flex.Item> </Flex.Container> ) ``` ### Horizontal Flex.Item, `justify="flex-end"` ```tsx render( <Flex.Container justify="flex-end"> <Flex.Item> <TestElement>FlexItem</TestElement> </Flex.Item> <Flex.Item> <TestElement>FlexItem</TestElement> </Flex.Item> <Flex.Item> <TestElement>FlexItem</TestElement> </Flex.Item> <Flex.Item> <TestElement>FlexItem</TestElement> </Flex.Item> </Flex.Container> ) ``` ### Horizontal Flex.Item, `align="center"` Centers items vertically inside a horizontal container. ```tsx render( <Flex.Container align="center"> <Flex.Item> <TestElement style={{ height: '4rem', }} > Tall </TestElement> </Flex.Item> <Flex.Item> <TestElement>Short</TestElement> </Flex.Item> <Flex.Item> <TestElement style={{ height: '6rem', }} > Taller </TestElement> </Flex.Item> <Flex.Item> <TestElement>Short</TestElement> </Flex.Item> </Flex.Container> ) ``` ### Vertical Flex.Item, `align="center"` Centers items horizontally inside a vertical container. ```tsx render( <Flex.Container direction="vertical" align="center"> <Flex.Item> <TestElement>FlexItem</TestElement> </Flex.Item> <Flex.Item> <TestElement>Wider FlexItem</TestElement> </Flex.Item> <Flex.Item> <TestElement>FlexItem</TestElement> </Flex.Item> </Flex.Container> ) ``` ### Horizontal with `size` and `grow` ```tsx render( <Flex.Horizontal> <Flex.Item span={3}> <Card>Card contents</Card> </Flex.Item> <Flex.Item span={4}> <Card>Card contents</Card> </Flex.Item> <Flex.Item span={5}> <Card>Card contents</Card> </Flex.Item> <Flex.Item grow> <Card>Card contents</Card> </Flex.Item> <Flex.Item grow> <Card>Card contents</Card> </Flex.Item> <Flex.Item grow> <Card>Card contents</Card> </Flex.Item> </Flex.Horizontal> ) ``` ### Horizontal Field.String Will wrap on small screens. ```tsx render( <Flex.Container> <Field.String label="Label" value="Foo" width="medium" /> <Field.String label="Label" value="Foo" width="small" /> </Flex.Container> ) ``` ### Vertical Flex.Item ```tsx render( <Flex.Container direction="vertical"> <Flex.Item> <TestElement>FlexItem</TestElement> </Flex.Item> <Flex.Item> <TestElement>FlexItem</TestElement> </Flex.Item> <Flex.Item> <TestElement>FlexItem</TestElement> </Flex.Item> <Flex.Item> <TestElement>FlexItem</TestElement> </Flex.Item> </Flex.Container> ) ``` ### Vertical aligned Card ```tsx render( <Flex.Container direction="vertical"> <Card>Card contents</Card> <Card>Card contents</Card> <Card>Card contents</Card> </Flex.Container> ) ``` ### Vertical line divider ```tsx render( <Flex.Container direction="vertical" divider="line" alignSelf="stretch"> <TestElement>FlexItem</TestElement> <TestElement>FlexItem</TestElement> <TestElement>FlexItem</TestElement> </Flex.Container> ) ``` ### Framed line dividers This example shows how to use the `Flex.Container` component to create a framed line divider (`line-framed`), which includes a line before the first item and above the last item. ```tsx const Item = () => ( <Flex.Stack divider="line-framed" gap="x-small"> <TestElement>FlexItem</TestElement> <TestElement>FlexItem</TestElement> </Flex.Stack> ) render( <Flex.Horizontal rowGap={false}> <Item /> <Item /> <Item /> </Flex.Horizontal> ) ``` ### Flex.withChildren ```tsx // @ts-expect-error -- strictFunctionTypes const Wrapper = Flex.withChildren(({ children }) => { return <div>{children}</div> }) render( <Flex.Container direction="vertical"> <TestElement>FlexItem 1</TestElement> <Wrapper> <TestElement>FlexItem 2</TestElement> <TestElement>FlexItem 3</TestElement> </Wrapper> <TestElement>FlexItem 4</TestElement> </Flex.Container> ) ``` ## Properties ```json { "props": { "direction": { "doc": "Direction of sub components. Can be: `horizontal` or `vertical`.", "type": ["'horizontal'", "'vertical'"], "defaultValue": "'horizontal'", "status": "optional" }, "wrap": { "doc": "Define if we should wrap contents if there is not enough space.", "type": "boolean", "defaultValue": "true", "status": "optional" }, "justify": { "doc": "Distribute sub components along the main axis (CSS `justify-content`). In horizontal direction, this controls left-to-right placement. In vertical direction, this controls top-to-bottom placement.", "type": [ "'flex-start'", "'flex-end'", "'center'", "'space-between'", "'space-around'", "'space-evenly'" ], "defaultValue": "'flex-start'", "status": "optional" }, "align": { "doc": "Align sub components along the cross axis (CSS `align-items`). In horizontal direction, this controls vertical alignment. In vertical direction, this controls horizontal alignment.", "type": [ "'flex-start'", "'flex-end'", "'center'", "'stretch'", "'baseline'" ], "defaultValue": "'flex-start'", "status": "optional" }, "divider": { "doc": "How to separate sub components.", "type": ["'space'", "'line'", "'line-framed'"], "defaultValue": "'space'", "status": "optional" }, "sizeCount": { "doc": "Define how many parts your layout should be divided in. Should be used in combination with a [Flex.Item](/uilib/layout/flex/item).", "type": "number", "defaultValue": "12", "status": "optional" }, "gap": { "doc": "How much space between child items. Use `false` for no spacing. If in vertical layout: if both `rowGap` and `gap` is set, `rowGap` will be used.", "type": [ "'xx-small'", "'x-small'", "'small'", "'medium'", "'large'", "'x-large'", "'xx-large'", "false" ], "defaultValue": "'small'", "status": "optional" }, "rowGap": { "doc": "How much space between rows. Use `false` for no row gap. If in vertical layout: if both `rowGap` and `gap` is set, `rowGap` will be used.", "type": [ "'xx-small'", "'x-small'", "'small'", "'medium'", "'large'", "'x-large'", "'xx-large'", "false" ], "defaultValue": "'small'", "status": "optional" }, "element": { "doc": "Define the type of element.", "type": ["string", "React.Element"], "defaultValue": "'div'", "status": "optional" }, "ref": { "doc": "Provide a React.Ref to access the inner HTML element.", "type": "React.RefObject", "defaultValue": "undefined", "status": "optional" }, "wrapChildrenInSpace": { "doc": "Define if intrinsic DOM child elements such as `li` should be wrapped in `Space` to receive spacing. Set to `false` to keep them as direct descendants.", "type": "boolean", "defaultValue": "true", "status": "optional" }, "[Space](/uilib/layout/space/properties)": { "doc": "Spacing properties like `top` or `bottom` are supported.", "type": "Various", "status": "optional" } }, "showDefaultValue": true } ```