Import
import { Flex } from '@dnb/eufemia'render(<Flex.Container />)
Description
Flex.Container is a building block for CSS flexbox based layout of contents and components.
Relevant links
NB: For form layouts, use Flex.Stack instead.
You can also use Flex.Item or Card for you inner wrappers:
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:
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:
justifycontrols placement along the main axis (CSSjustify-content).aligncontrols alignment along the cross axis (CSSalign-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">
<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">
<Flex.Horizontal><Flex.Item>part of horizontal alignment</Flex.Item><Flex.Item>part of horizontal alignment</Flex.Item></Flex.Horizontal>
Relevant links
Limitations
The Flex.Container will iterate over its childrenToReact, but not the children of the children
NB: This examples showcases the limitation:
import { Flex, Card } from '@dnb/eufemia'// The Cards will not get the spacing appliedconst 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.
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, 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:
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
<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
<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"
<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"
<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.
<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.
<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
<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.
<Flex.Container> <Field.String label="Label" value="Foo" width="medium" /> <Field.String label="Label" value="Foo" width="small" /> </Flex.Container>
Vertical Flex.Item
<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
<Flex.Container direction="vertical"> <Card>Card contents</Card> <Card>Card contents</Card> <Card>Card contents</Card> </Flex.Container>
Vertical line divider
<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.
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
// @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> )