Flex

A flexbox container as a component: gap, alignment, direction and wrapping as props, with the gap sizes coming from the theme.

Usage

A flexbox container as a component: direction, alignment, gap and wrapping as props, on one element, with the gap sizes resolved from the live theme.

When to use

Flex is one element with display: flex on it and the flex properties as props. The children you pass are the flex items, with nothing inserted around them.
Reach for it when the layout itself is worth naming: a toolbar, a card header with actions pushed to the end, a two-column body, a stack of rows. Three other tools do a neighboring job better.
  • Space when all you want is an even gap between a row of controls. It wraps each child in an item of its own, which lets it split and align them, and makes it the wrong tool once a child needs to grow.
  • Grid (Row and Col) when it is page layout with breakpoints. Flex has no responsive props at all, so a column that should be full width on sm and a third on lg belongs there.
  • A plain div with flex utilities when you want none of the props: no component, no theme-resolved gap, no prop a design tool can read. The two are equivalent, so mix them as it suits you.

Direction: vertical and orientation

orientation takes horizontal or vertical and is the spelling to prefer, because Segmented, Space and Divider carry the same prop under the same name. vertical is the older boolean and still works. Set both and orientation wins.
Turning a row into a column changes what justify and align mean, since both are named after the axes rather than after the screen. It also changes the default cross-axis alignment: with align unset, a vertical Flex stretches its children to full width.

justify and align

justify distributes along the main axis, align positions across the other one. Both take any CSS value for their property, the same as in CSS.
  • justify="space-between" is the usual toolbar: a title at the start, an action group at the end, no spacer div and no margin-inline-start: auto.
  • align="center" is what makes an icon sit on the same optical line as the text beside it. It is the alignment most rows want and the one most often forgotten.
  • align="baseline" when the items are text at different sizes, a heading next to a count, because centering two different line heights lines up their boxes rather than their letters.
  • Reach for justify before you reach for a margin. A rule that pushes one child away from the rest lives on that child and breaks when the order changes. The container property does not.

gap: a named step or a number

gap is the one prop the kit extends. It takes three presets (small, medium, large), the eight spacing steps (xxs, xs, sm, base, md, lg, xl, xxl), or any CSS gap value.
  • A name moves with the theme, a number does not. The presets and the steps come from the theme's sizes, so in compact mode every named gap on the page tightens together. A gap={40} stays at 40.
  • Keep raw numbers for distances off the ramp, like an optical nudge between two glyphs, and leave a comment saying so.
  • gap="md" and a gap-md class give the same space. Pick whichever reads better where you write it. Only the class composes with responsive variants, and only the prop is readable by a design tool.
  • The CSS shorthand is available for two axes at once, so gap="1rem 2rem" sets row and column gaps separately on a wrapping container.

Wrapping, and claiming space

A Flex does not wrap unless you say so. wrap takes a boolean or any CSS flex-wrap value, so true is sugar for "wrap" and "wrap-reverse" is there when the new line should appear above rather than below.
  • Wrap anything whose count you do not control: a tag list, a filter row, a set of avatars. Without it the items shrink past legibility or push a scrollbar onto the page.
  • A wrapping row needs a row gap as well as a column one, and one gap already gives you both. Use the two-value shorthand when they should differ.
  • flex sets how a Flex behaves as an item of its parent, not how it treats its own children. A nested Flex can lay out its own row and take a share of the row above it in one element.
  • Any CSS flex shorthand works, and the two worth knowing are flex="1" for a pane that takes the remainder and flex="0 0 240px" for a sidebar that refuses to shrink.

The element it renders

component chooses the element, defaulting to div. The layout stays in props while the element matches the content, which a class-styled div cannot give you.
  • A list of things is a ul, and its rows are li. A screen reader announces the count, and a div does not.
  • A row of page links is a nav, a page region is a section or a header. These are the landmarks a reader jumps between.
  • It also takes a component, not only a tag name, so a link component can be the flex container itself instead of gaining a div around it.
  • Everything else on FlexProps is standard HTML attributes, so id, role, the data attributes and the event handlers all land on that element.

When a Flex is one div too many

  • A Flex with one child is not doing anything a property on the child would not. Centering a single item is usually the parent's job already.
  • A Flex that only carries a className is a div with extra steps. If no prop of the component is set, write the div.
  • An empty Flex is hidden. A Flex with no children disappears, and its height, padding and background go with it, whatever a className="h-20" on it says.
  • To hold space for a cell that is sometimes empty, keep one child in it at all times, hidden with invisible until the content arrives.