DocumentationComponentsTheme CreatorGitHub
Theme CreatorGitHubIntroduction
InstallationUsageTheming
ComponentsAccordionAction SheetAlertAlertDialogArea ChartAspectRatioAvatarBadgeBannerBar ChartBottom NavBreadcrumbButtonButtonGroupCalendarCardCarouselChartChatBubbleChatBubbleNewCheckboxChipCoachMarkCodeBlockCollapsibleColor PickerComboboxCommandContainerContextMenuDate PickerDividerDrawerDropdown MenuEmptyStateFABFieldFieldsetFile UploadFlexFormGridHoverCardIconButtonLabelLine ChartLinkMenubarMeterModalNavigation MenuNumberFieldOTP InputPaginationPickerPie ChartPopoverProgressPromptInputRadar ChartRadial ChartRadioRatingScroll AreaSearchSegmentedControlSelectShortcutSidebarSkeletonSliderCircularSliderMediaTrimmerSpacerSpinnerSplit ButtonStackStatusStepperSurfaceSwitchTableTabsTextareaTime PickerToastToggleButtonToggleGroupTokenizerToolbarTooltipTop Header DesktopTop Header Mobile
Contributing
Components

Flex

A low-level flexbox primitive that exposes the full flex API as props — four directions plus a responsive { base, md } form, three wrap modes, align-items incl. baseline, justify-content, align-content, a token gap scale with separate row and column gaps, inline mode, polymorphic render, and LTR/RTL. FlexItem sets grow, shrink, basis, order and alignSelf on one child, and fill gives it an equal share plus the min-size reset truncating text needs.

Playground

Installation

pnpm add @tessinaui/ui

Usage

import { Flex, FlexItem } from "@tessinaui/ui";
{/* A list row: pinned avatar, truncating text, trailing meta */}
<Flex align="center" gap="sm">
  <FlexItem shrink={false}>
    <Avatar name="Maya Chen" />
  </FlexItem>
  <FlexItem fill>
    <p className="truncate">Maya Chen</p>
    <p className="truncate text-muted-foreground">Q3 roadmap review — notes from Thursday</p>
  </FlexItem>
  <time className="shrink-0">9:41</time>
</Flex>

{/* Stacked on phones, a right-aligned row from 768px up */}
<Flex direction={{ base: "column-reverse", md: "row" }} justify="end" gap="sm">
  <Button variant="secondary">Cancel</Button>
  <Button>Save</Button>
</Flex>

{/* Wrapping with independent gaps */}
<Flex wrap="wrap" columnGap="sm" rowGap="md">
  {tags.map((t) => <Chip key={t}>{t}</Chip>)}
</Flex>

{/* Semantic element */}
<Flex render={<nav aria-label="Primary" />} gap="sm">
  <a href="/">Home</a>
  <a href="/about">About</a>
</Flex>

Examples

Default

A simple row of items with a medium gap, vertically centered.

Direction

row lays items out horizontally; column stacks them vertically.

Responsive direction

{ base, md } changes direction at the md band. This dialog footer stacks full-width below 768px — column-reverse puts the primary action on top — and becomes a right-aligned row from there up.

Align

baseline lines up mixed type sizes on their text baseline — a metadata row, or a price beside its unit. inline flows a Flex inside a sentence, and a column with align="center" builds a profile lockup.

Justify

Distribute items along the main axis with between, center, and evenly.

Wrap

Wrapping rows with independent columnGap and rowGap.

Gaps and line packing

The seven-step gap scale, then a wrapping tag cloud with a larger row gap than column gap. In a tray taller than its content, content="start" keeps the lines packed at the top instead of spreading them apart.

FlexItem grow

A fixed sidebar beside a grow main region that fills the remaining space.

FlexItem basis

Fractional basis presets build a three-column 1/4 · 2/4 · 1/4 layout.

FlexItem order and alignSelf

order="first" moves an image above its title visually while the DOM keeps the title first; alignSelf="end" drops one child to the bottom of a top-aligned row.

Media rows

The most common Flex shape in real products: a pinned avatar, a fill text block that truncates, and trailing meta. The lists render as <ul>/<li> through render, the settings rows are links with a 44px floor, and the last list shows the same rows under dir="rtl".

Toolbar

A search that grows, filter and sort controls, and a primary action pushed to the end with Spacer. The search has a basis, so on a phone it takes its own line instead of squeezing the buttons. Below it, a bulk-selection bar.

Header

Three zones in a semantic <header>: a pinned brand, a search that fills the middle, and pinned actions.

Stat row

Equal tiles from fill, stacked below 768px. The profile trio shows each value above its label with column-reverse, so screen readers still hear the label first.

Split pane

A pinned sidebar beside a fill content pane that scrolls inside a fixed height on desktop and stacks on phones.

Direction

Unlike Stack, Flex exposes all four flex-direction values directly.

ValueCSS mapping
"row" (default)flex-row
"column"flex-col
"row-reverse"flex-row-reverse
"column-reverse"flex-col-reverse

Responsive direction

Pass an object to change direction at the md band (768px). Both keys are required.

<Flex direction={{ base: "column", md: "row" }}>…</Flex>

Flex emits two non-overlapping classes — max-md:flex-col md:flex-row — and no plain direction class beside them.

Don't make direction responsive with className. The default direction is emitted as a plain flex-row class, and a plain class beside a max-md: or md: variant of the same property is decided by stylesheet order, which Tailwind does not guarantee — className="max-md:flex-col" can silently lose. The object form is the supported way. The same applies to wrap, align and justify, which also emit plain defaults.

The bands follow the viewport, like Grid's cols and AspectRatio's ratio: a Flex in a narrow column on a wide screen keeps its md direction. Container-query bands are not offered — a container query resolves against an ancestor, so Flex cannot query its own width — and md is the only switch point today.

Wrap

ValueCSS mapping
"nowrap" (default)flex-nowrap
"wrap"flex-wrap
"wrap-reverse"flex-wrap-reverse

Gap

Seven presets that map to Tailwind's spacing scale.

ValueTailwindpx
"none"gap-00
"xs"gap-14
"sm"gap-28
"md"gap-416
"lg"gap-624
"xl"gap-832
"2xl"gap-1248

Flex has no default gap — children sit flush until you set one. That is deliberate: Flex is the raw primitive, and Stack is the sibling that defaults to md.

For independent axis control use rowGap and columnGap — they accept the same seven values and override gap on their axis.

<Flex wrap="wrap" columnGap="xl" rowGap="sm">…</Flex>

Align (align-items)

Cross-axis alignment of children.

ValueCSS mapping
"start"items-start
"center"items-center
"end"items-end
"stretch" (default)items-stretch
"baseline"items-baseline

Justify (justify-content)

Main-axis distribution. start and end are logical, so they follow dir.

ValueCSS mapping
"start" (default)justify-start
"center"justify-center
"end"justify-end
"between"justify-between
"around"justify-around
"evenly"justify-evenly

Content (align-content)

Applies only when wrap is enabled and the lines do not fill the cross axis. With no value, the lines stretch apart to fill a container taller than its content — set content="start" to keep them packed.

ValueCSS mapping
"start"content-start
"center"content-center
"end"content-end
"between"content-between
"around"content-around
"evenly"content-evenly
"stretch"content-stretch
"baseline"content-baseline

Inline

inline swaps flex for inline-flex so the container flows with surrounding text. Inside a <p>, render a <span> — a <div> is not allowed there.

<p>
  Status <Flex inline render={<span />} align="center" gap="xs">…</Flex> since Tuesday.
</p>

Polymorphic render

Preserve Flex styling while mounting semantic HTML.

<Flex direction="row" gap="md" render={<nav aria-label="Primary" />}>
  <a href="/">Home</a>
  <a href="/about">About</a>
</Flex>

<Flex render={<section />} direction="column" gap="lg">
  <h2>Settings</h2>
  <p>Adjust your preferences below.</p>
</Flex>

Props already on the element win over the same props passed to Flex, and the element keeps its own ref and dir. The element's own children are kept when it has any; otherwise Flex's children fill it.

FlexItem

A helper for setting flex-child properties (flex-grow, flex-shrink, flex-basis, order, align-self) without reaching for Tailwind classes directly. FlexItem is optional — you can always apply grow, shrink-0, etc. inline on any child. It takes render too, including another Flex, so one element can be both an item and a container.

<Flex direction="row" gap="md">
  <aside className="w-48">Sidebar</aside>
  <FlexItem grow>
    <main>Main (grows to fill)</main>
  </FlexItem>
</Flex>

fill

fill gives the item an equal share of the space and resets its minimum size.

ClassesWhy
grow basis-[0%]fill items split the space equally
min-w-0 min-h-0A flex item defaults to min-width: auto, so without this a truncate label pushes its row wider instead of truncating, and a nested scroll area never scrolls
  • An explicit grow or basis still wins.
  • A zero-basis item never wraps. wrap decides line breaks from each item's basis, and fill's is 0. For tiles that should wrap, give them a basis (e.g. className="basis-48") and grow.
  • It is written with longhands rather than flex-1, so an explicit basis can never race it.

grow

ValueCSS
true / 1grow
false / 0grow-0
2, 3, 4, 5flex-grow: n

Values outside 0–5 emit no class.

shrink

ValueCSS
true / 1shrink
false / 0shrink-0
2, 3, 4, 5flex-shrink: n

Values outside 0–5 emit no class. Pin avatars, icons and sidebars with shrink={false}.

basis

Presets cover fractional layouts without arbitrary values.

"auto" · "full" · "0" · "1/2" · "1/3" · "2/3" · "1/4" · "2/4" · "3/4" · "1/5" · "2/5" · "3/5" · "4/5" · "1/6" · "5/6" · "1/12" through "11/12"

order

ValueCSS
"none"order-none
"first"order-first
"last"order-last
1 – 12order-n

alignSelf

"auto" · "start" · "center" · "end" · "stretch" · "baseline" → self-*

RTL

dir="rtl" is forwarded to the DOM node and flips the main axis of row directions; justify start/end follow it. Column directions are unaffected by text direction. A render element keeps its own dir when Flex is given none.

Accessibility

  • Flex is a structural primitive — it applies no ARIA roles.
  • Use render to mount semantic HTML (<nav>, <ul>, <header>, <dl>) when the grouping has meaning.
  • order, row-reverse and column-reverse move pixels, not focus: keyboard and screen-reader order follow the DOM. Reversing a two-button footer on phones is a common, acceptable use — the primary action sits on top while the DOM keeps Cancel first — but never reorder content whose meaning depends on its sequence.
  • A pane that scrolls must be reachable by keyboard: give it focusable content (links, buttons), or tabIndex={0} and an accessible name.
  • inline does not remove any semantics — the element remains a <div> (or whatever render provides).
  • Both components stamp data-slot (flex, flex-item) for stable targeting in tests and automation.

When to use Flex vs. Stack

Both are flex wrappers. Pick based on how much of the flex API you actually need.

Use Stack when…Use Flex when…
You want a single-axis layout with sensible defaultsYou need the full flexbox API
A default md gap suits youYou want no gap until you set one
You want a divider between childrenYou need independent rowGap and columnGap
Children size themselves naturallyYou need grow / shrink / basis / order / fill on children

For many apps Stack is the right pick. Reach for Flex when you're building a layout that can't be expressed through Stack's opinionated API.

Usage rules

  • Do give a growing text child fill, so it can truncate instead of pushing its row wider.
  • Do pin avatars, icons and sidebars with shrink={false}.
  • Do use direction={{ base, md }} to change direction responsively.
  • Don't make direction, wrap, align or justify responsive with max-md:/md: classes — their defaults are plain classes and the pair races.
  • Don't hide a Flex with max-md:hidden — its flex display class is plain too. Render it conditionally or wrap it.
  • Don't expect fill items to wrap; give wrapping tiles a basis.
  • Don't use Flex for a toolbar that needs arrow-key navigation — that is Toolbar.

API Reference

Flex Props

PropTypeDefaultDescription
direction"row" | "column" | "row-reverse" | "column-reverse" | { base, md }"row"flex-direction; the object form changes it at the md band
wrap"nowrap" | "wrap" | "wrap-reverse""nowrap"flex-wrap
gap"none" | "xs" | "sm" | "md" | "lg" | "xl" | "2xl"—Shorthand for both row and column gap
rowGapSame as gap—Vertical gap (overrides gap on that axis)
columnGapSame as gap—Horizontal gap (overrides gap on that axis)
align"start" | "center" | "end" | "stretch" | "baseline""stretch"align-items
justify"start" | "center" | "end" | "between" | "around" | "evenly""start"justify-content
content"start" | "center" | "end" | "between" | "around" | "evenly" | "stretch" | "baseline"—align-content — only relevant with wrap
inlinebooleanfalseUses inline-flex instead of flex
renderReactElement—Polymorphic target — clone this element and apply Flex styles
dir"ltr" | "rtl"—Text direction forwarded to the DOM node
classNamestring—Extra classes on the root element

FlexItem Props

PropTypeDefaultDescription
fillboolean—Equal share of the space plus min-w-0 min-h-0
growboolean | 0 | 1 | 2 | 3 | 4 | 5—flex-grow
shrinkboolean | 0 | 1 | 2 | 3 | 4 | 5—flex-shrink
basisFraction preset (see table above)—flex-basis
order"none" | "first" | "last" | 1..12—order — visual only
alignSelf"auto" | "start" | "center" | "end" | "stretch" | "baseline"—align-self
renderReactElement—Polymorphic target
dir"ltr" | "rtl"—Text direction forwarded to the DOM node
classNamestring—Extra classes on the root element

Notes

  • No intrinsic padding. Flex only controls layout — add padding, borders, background via className.
  • No SSR caveats. Flex renders the same markup on the server and the client.
  • content is a prop, not an HTML attribute. React's native content HTML attribute (meta-tag-only) is omitted from Flex's props so the CVA variant takes precedence.
  • Arbitrary values. If a fraction you need isn't in the basis preset list, drop to className="basis-[...]" — FlexItem's class output is merged after its props.
  • data-slot. flex on Flex, flex-item on FlexItem, on both the plain and the render path.
File UploadForm

On this page

PlaygroundInstallationUsageExamplesDefaultDirectionResponsive directionAlignJustifyWrapGaps and line packingFlexItem growFlexItem basisFlexItem order and alignSelfMedia rowsToolbarHeaderStat rowSplit paneDirectionResponsive directionWrapGapAlign (align-items)Justify (justify-content)Content (align-content)InlinePolymorphic renderFlexItemfillgrowshrinkbasisorderalignSelfRTLAccessibilityWhen to use Flex vs. StackUsage rulesAPI ReferenceFlex PropsFlexItem PropsNotes