flex-wrap and Multi-Row Layouts in CSS Flexbox
What You Learn From This Page
- How
nowrap,wrap, andwrap-reversecontrol flex-line creation. - How main-axis space, item bases, shrinking, gaps, and minimums determine wrapping.
- Why every wrapped flex line performs its own one-dimensional sizing calculation.
- How
justify-content,align-items, andalign-contentbehave with multiple lines. - How to build responsive tags, actions, filters, toolbars, navigation, and cards.
- Why column wrapping usually requires a definite or constrained main size.
- When wrapped Flexbox is appropriate and when CSS Grid is the better layout model.
- How to debug overflow, unexpected line breaks, uneven final rows, and accessibility risks.
Introduction
The CSS flex-wrap property controls whether flex items are forced onto one flex line or may be divided across additional lines when the current line cannot contain them. It turns Flexbox from a strictly single-line arrangement into a content-driven multi-line flow.
The initial value is nowrap. Items stay on one line and Flexbox tries to resolve a shortage through shrinking before content overflows. With wrap, line breaking becomes available: items fill the current line in source order, and a later item can move to a new line when it no longer fits. With wrap-reverse, items wrap but the cross-axis stacking direction of the lines is reversed.
Wrapping is useful for groups whose item count or label length changes, including tags, filter chips, buttons, toolbars, navigation links, and flexible cards. It does not turn Flexbox into a two-dimensional grid. Each line remains an independent one-dimensional layout, which is the key to understanding uneven final rows and deciding when Grid is more suitable.
Basic Syntax
Set flex-wrap on the flex container. Its direct in-flow flex items are the boxes that may be assigned to one or more lines.
.container {
display: flex;
flex-wrap: wrap;
}
The property accepts three principal values.
| Value | Line Behavior | Cross-Axis Stacking |
|---|---|---|
nowrap | All items remain on one flex line | No additional lines |
wrap | Additional flex lines may be created | Lines stack toward cross-end |
wrap-reverse | Additional flex lines may be created | Cross-start and cross-end are reversed for line stacking |
The Default: flex-wrap: nowrap
A flex container is single-line by default. This does not mean items immediately overflow whenever their preferred sizes exceed the container. The flex sizing algorithm first tries to shrink eligible items according to their flex-shrink factors, bases, and minimum-size constraints.
.toolbar {
display: flex;
flex-wrap: nowrap;
}
If shrinking can resolve the deficit, the items remain on one compressed line. If minimum sizes, unbreakable content, fixed dimensions, or zero shrink factors prevent enough reduction, overflow occurs. No-wrap is appropriate when the component must remain one line and has a deliberate overflow or responsive transformation strategy.
Allowing Additional Lines with wrap
With flex-wrap: wrap, the browser collects flex items into lines according to available main-axis space. It considers each item's outer hypothetical main size, including relevant margins, and accounts for gaps between items. When another item cannot fit, a new line starts.
.tag-list {
display: flex;
flex-wrap: wrap;
gap: 0.5rem;
}
A wide container may show every tag on one line. A narrower container may show two or more lines. The source sequence remains the same; only line assignment changes.
What wrap-reverse Changes
wrap-reverse does not reverse the order of items within each line. It reverses the cross-axis direction in which the flex lines are stacked. In a common horizontal row, ordinary wrap places later lines below earlier lines, while wrap-reverse places them toward the opposite cross side.
.container {
display: flex;
flex-wrap: wrap-reverse;
}
The DOM and reading sequence remain unchanged. Because the visual line placement can conflict with what readers and keyboard users expect, use wrap-reverse only when the reversed cross-axis relationship has a clear purpose.
Main and Cross Axes with Wrapping
Items fill a flex line along the main axis. Additional lines are placed along the cross axis. In a normal row under a common horizontal writing mode, items fill from left to right and new lines appear vertically. In a column, items fill vertically and additional lines form column-like groups across the cross axis.
.row-wrap {
display: flex;
flex-direction: row;
flex-wrap: wrap;
}
.column-wrap {
display: flex;
flex-direction: column;
flex-wrap: wrap;
}
Writing mode, direction, and reverse values can change the physical mapping. Use main-axis and cross-axis language while reasoning, then translate that model to the current document direction.
The flex-flow Shorthand
The flex-flow shorthand sets flex-direction and flex-wrap together. It provides a compact declaration when both are part of one layout decision.
.container {
display: flex;
flex-flow: row wrap;
}
This is equivalent to declaring flex-direction: row and flex-wrap: wrap separately. Use the form that makes the component easiest to scan and maintain.
How the Browser Forms Flex Lines
A practical mental model is that the browser considers items in order and adds each to the current line while it fits. When the next item's outer hypothetical main size plus the required gap cannot fit, the browser closes the current line and begins another. An individual item that is larger than the line is still placed alone on a line and may overflow.
consider next item
-> fits current line: add it
-> does not fit: start a new line
-> oversized by itself: place it and handle overflow
The detailed specification includes additional sizing rules, but this model explains most real layouts. Basis, width, margins, gaps, minimums, and content all influence whether an item fits.
flex-basis Drives Responsive Wrapping
A meaningful basis gives each item a preferred main-axis starting size. Combined with wrapping, it lets the browser choose how many items fit without a media query for every possible width.
.card {
flex: 1 1 16rem;
}
Each card begins around 16rem, can grow to share positive space, and can shrink when needed. Once another 16rem card plus the gap no longer fits acceptably, it moves to another line. Min/max constraints and intrinsic minimums still influence the final result.
Fixed-Basis vs Growing Items
Whether items grow changes the appearance of each line. With flex: 0 1 16rem, cards prefer 16rem and may shrink, but they do not expand to fill unused line space. With flex: 1 1 16rem, they can expand, so every line tends to fill its available width.
.natural-card { flex: 0 1 16rem; }
.filling-card { flex: 1 1 16rem; }
Neither pattern is universally better. Use non-growing items when their stable width matters. Use growing items when filling each line is desirable and an incomplete last row may legitimately contain wider items.
Every Flex Line Sizes Independently
This is the defining limitation of multi-line Flexbox. The browser lays out each line independently. It does not create shared column tracks across lines. If three growing cards occupy the first line and only two occupy the second, the two cards can become wider because they share that line's free space between themselves.
.cards {
display: flex;
flex-wrap: wrap;
gap: 1rem;
}
.card {
flex: 1 1 16rem;
}
The wider final row is not a browser error. It follows the one-dimensional line model. When cards must align into consistent columns across every row, use CSS Grid.
The Incomplete Final-Row Problem
An incomplete final row often exposes the difference between flow and grid requirements. With growing items, the last two cards in a three-card pattern may expand to half-width each. With justify-content: space-between, two non-growing cards may move to opposite edges and leave a large empty region between them.
Do not add fragile placeholder items merely to imitate grid tracks. Decide whether wider last-row cards are acceptable, whether non-growing cards should remain at a stable basis, or whether the design actually requires Grid's shared tracks.
Why gap Is the Preferred Spacing Tool
The gap property creates defined gutters between adjacent items and between flex lines. It does not add spacing around the outer edge of the container, which keeps component padding and internal spacing as separate responsibilities.
.filters {
display: flex;
flex-wrap: wrap;
gap: 0.75rem 1rem;
}
With two values, the first is the row gap and the second is the column gap in common row-based layouts. row-gap and column-gap can be declared separately when that is clearer.
Gaps Participate in Line Fitting
Gaps consume available main-axis space. Three items with bases of 200 pixels need more than 600 pixels when two 20-pixel gaps are also required. In a 620-pixel container, only two may fit because three would require 640 pixels before other margins or borders are considered.
3 * 200px items + 2 * 20px gaps = 640px
This is why percentage bases such as 33.333 percent can wrap unexpectedly when gaps are added. Grid's fractional tracks account for gaps more naturally when a strict number of columns is required.
justify-content Applies Per Line
In a multi-line flex container, justify-content distributes items independently within each flex line. Centering can produce a centered incomplete final row, while space-between can create a very large interval between the final row's few items.
.centered-tags {
display: flex;
flex-wrap: wrap;
justify-content: center;
gap: 0.5rem;
}
Use gap for consistent neighboring distance. Use justify-content only when distributing the remaining space within every line is part of the design.
align-items Works Inside Each Line
align-items sets the default cross-axis alignment of items inside each individual flex line. If items on one line have different heights, center, start, end, baseline, or stretch alignment is resolved against that line's cross size.
.toolbar {
display: flex;
flex-wrap: wrap;
align-items: center;
gap: 0.75rem;
}
Align-items does not move the collection of lines as a group through a tall container. That is the responsibility of align-content.
align-content Distributes the Flex Lines
When multiple flex lines exist and the container has extra cross-axis space, align-content controls how the lines are packed or distributed. It acts on lines, not directly on individual items.
.panel {
min-block-size: 24rem;
display: flex;
flex-wrap: wrap;
align-content: center;
gap: 1rem;
}
Center groups the lines around the cross-axis center. Other common values include flex-start, flex-end, space-between, space-around, space-evenly, and stretch. A visible effect requires multiple lines and available cross-axis space.
align-items vs align-content
| Property | Target | Question |
|---|---|---|
align-items | Items within each line | How should items align inside their line? |
align-self | One item | How should this item override its line default? |
align-content | The collection of flex lines | How should multiple lines use cross-axis space? |
On a single-line container, align-content normally has no line-distribution work to perform. Use align-items for item alignment in that case.
align-content Values
flex-start packs lines near cross-start, flex-end packs them near cross-end, and center groups them around the cross-axis center. The space distribution values divide available cross-axis room around or between the lines.
.start-lines { align-content: flex-start; }
.center-lines { align-content: center; }
.spread-lines { align-content: space-between; }
.even-lines { align-content: space-evenly; }
The normal behavior in Flexbox commonly produces stretch-like line sizing when extra cross-axis room exists. Stretch changes flex-line cross sizes; align-items then controls items within those lines.
Row-Based Multi-Line Layouts
A row-based wrapping container is the common pattern for tags, buttons, and responsive cards. The main axis runs along the row, and new lines stack along the cross axis.
.courses {
display: flex;
flex-flow: row wrap;
gap: 1rem;
}
.course {
flex: 1 1 14rem;
}
The browser can place more courses per line as the container widens and fewer as it narrows. The exact count is an outcome of available space and item sizing rather than a fixed breakpoint table.
Column Wrapping
With flex-direction: column, items fill the vertical main axis first. When wrapping occurs, additional flex lines appear as column-like groups along the cross axis.
.column-flow {
block-size: 20rem;
display: flex;
flex-direction: column;
flex-wrap: wrap;
gap: 0.75rem;
}
A constrained main size is usually necessary. If block size remains auto, the container can keep growing vertically to contain its items, so it may never need to create another column.
Why Column Wrap Appears Not to Work
Column wrapping depends on a known or constrained vertical main size under a common writing mode. Without a height, block-size, max-block-size, or another definite containing constraint, the browser often expands the container instead of wrapping.
Before adding an arbitrary fixed height, ask whether column wrapping is genuinely the correct pattern. A multi-column list can create an unexpected reading sequence, and CSS Grid or multi-column layout may better represent the content.
Real-World Tag and Skill Lists
Tags and skills are excellent Flexbox wrapping candidates because their widths are content-driven and strict column alignment is unnecessary. Each label keeps its natural relationship while the group adapts to the container.
.skills {
display: flex;
flex-wrap: wrap;
gap: 0.5rem;
}
.skill {
flex: 0 0 auto;
}
Do not give short and long tags identical widths unless the design requires it. Natural content sizing preserves compact scanning and makes wrapping efficient.
Real-World Button Groups
A secondary action group can wrap when translated labels or narrow containers prevent a single line. Gap maintains stable separation without margin rules tied to item position.
.actions {
display: flex;
flex-wrap: wrap;
justify-content: flex-end;
gap: 0.75rem;
}
Check whether the resulting line order still communicates action priority. On very small screens, deliberately stacking full-width buttons can be more predictable than allowing an arbitrary break between actions.
Real-World Filter Toolbars
Filter toolbars often combine search, selects, date controls, and commands. Wrapping lets the component respond to its own available width instead of depending only on viewport breakpoints.
.filter-toolbar {
display: flex;
flex-wrap: wrap;
align-items: end;
gap: 1rem;
}
.filter-search {
flex: 1 1 16rem;
min-width: 0;
}
Keep labels associated with controls and preserve an understandable keyboard sequence. If exact form columns matter, Grid may provide stronger structure.
Real-World Navigation
Simple secondary navigation can wrap naturally, but uncontrolled primary-navigation wrapping may create an awkward header with unpredictable height and separated groups. A deliberate menu disclosure is often better for a primary mobile navigation.
.secondary-nav {
display: flex;
flex-wrap: wrap;
gap: 0.5rem 1rem;
}
Use wrapping when every link remains visible and the line breaks preserve comprehension. Use a responsive navigation control when space, hierarchy, or interaction requirements call for a different structure.
Real-World Flexible Cards
A content-driven card collection can use a preferred basis and wrapping when exact columns are not essential.
.cards {
display: flex;
flex-wrap: wrap;
gap: 1rem;
}
.card {
flex: 1 1 18rem;
}
The pattern is concise and adapts to intermediate container widths. Accept that each line is independent and the final row may use different card widths. If that result is undesirable, reconsider the layout model rather than over-calculating percentages.
Flexbox vs Grid for Multiple Rows
| Requirement | Better Starting Point | Reason |
|---|---|---|
| Content-sized tags or chips | Flexbox | Natural one-dimensional flow |
| Wrapping action buttons | Flexbox | Sequence and content drive line breaks |
| Adaptive toolbar controls | Flexbox or Grid | Depends on whether columns must align |
| Strict card columns | Grid | Shared tracks align every row |
| Two-dimensional dashboard | Grid | Rows and columns are coordinated |
| One-dimensional group that may wrap | Flexbox | Each line remains an independent flow |
A Grid Alternative for Card Tracks
When cards must maintain consistent columns across all rows, Grid expresses the requirement directly. The following pattern creates as many 18rem-or-larger tracks as fit and aligns the final row to the same tracks.
.cards {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(18rem, 1fr));
gap: 1rem;
}
Choose the tool according to the relationship. Flexbox is not inferior when lines are independent; Grid is not excessive when shared two-dimensional tracks are the actual requirement.
Flex Item Wrapping vs Text Wrapping
Flex-wrap controls whether flex items move to additional flex lines. It does not control line breaking inside the content of an item. Text wrapping is governed by white-space, overflow-wrap, word-break, available inline size, and related text properties.
.container {
display: flex;
flex-wrap: wrap;
}
.item {
white-space: nowrap;
}
The item can move to a new flex line while its own text still refuses to break. Diagnose the correct layer before changing properties.
Long Content and Minimum Sizes
Wrapping cannot make one oversized item narrower than its effective minimum. A long unbroken value, fixed-width image, table, or explicit min-width can overflow even when the container wraps.
.item {
min-width: 0;
overflow-wrap: anywhere;
}
In a row, minimum zero lets the item shrink below its automatic content-based minimum. Overflow-wrap then gives text a legal breaking strategy. Wide tables or code may require a controlled scrolling wrapper instead.
Margins, Padding, and Box Sizing
Outer main-axis margins participate in line fitting, while padding and borders contribute through the item's box model. Unexpected wrapping often comes from calculating only content width and forgetting these additions.
Use box-sizing: border-box consistently so declared sizes include padding and border. Prefer gap over per-item margins for gutters because gap avoids first/last-item exceptions and makes the occupied space easier to reason about.
Wrapping and Source Order
Ordinary wrapping preserves the flex-item source sequence. If the DOM order is A, B, C, D, and E, a two-line row normally presents A through C on the first line and D through E on the second. Reading and keyboard sequences follow the same logical order.
Heavy use of order, row-reverse, or wrap-reverse can disconnect visual placement from DOM sequence. Keep source order meaningful and avoid visual rearrangement that changes interpretation or task flow.
Responsive Design Considerations
Wrapping is a component-level responsive tool, but it is not a complete responsive strategy. Test the minimum and maximum expected item counts, long translated labels, validation messages, loading states, permission-based controls, and user-generated content. Line breaks may occur in places not represented by short design samples.
Use container queries when a component needs a deliberate structural change based on its own width. Natural wrapping can handle intermediate sizes, while a query can switch action orientation, control width, or hierarchy when the design reaches a meaningful threshold.
Accessibility Considerations
Wrapped items remain usable when source order, focus order, visual sequence, and semantic relationships stay aligned. Problems arise when reverse directions or order values make keyboard focus jump unexpectedly, or when a label and its control appear on separate lines without a clear association.
Test keyboard navigation, 200 and 400 percent zoom, enlarged text, RTL content, and screen magnification. Ensure focus indicators are not clipped and each wrapped control keeps an adequate target size. If a toolbar becomes several lines tall, confirm it does not cover content when sticky or fixed.
Common Mistake: Forgetting wrap Is Opt-In
Declaring display: flex does not enable multiple lines. A toolbar that overflows on mobile may simply be using the default nowrap value.
.toolbar {
display: flex;
flex-wrap: wrap;
}
Enable wrapping only when line breaks are acceptable. If the component must remain one line, define which item shrinks, what can scroll, or when the structure changes.
Common Mistake: Expecting Grid-Like Columns
Wrapped Flexbox does not align columns across independent lines. Cards in the second row do not inherit the first row's track widths. Trying to repair that limitation with complex nth-child rules usually produces brittle CSS.
Use Grid when shared columns are a requirement. Keep Flexbox when items should flow according to content and each line can legitimately distribute its own space.
Common Mistake: No Meaningful Item Basis
Items declared only as flex: 1 can keep sharing a single line from a zero-like basis instead of wrapping at the intended component width. Give them a meaningful preferred basis.
.card {
flex: 1 1 16rem;
}
The 16rem basis communicates the approximate minimum useful card measure while preserving flexibility. Add a real minimum only when content usability requires one.
Common Mistake: Using space-between for Card Rows
Space-between distributes each line independently. An incomplete line with two items can place one at each edge, creating a large empty center. That visual gap is free-space distribution, not the declared gutter.
Use gap for consistent card spacing. If cards need strict shared columns, use Grid. Use space-between for relationships that genuinely require opposite edges, such as two groups in one toolbar line.
Common Mistake: align-content on One Line
Align-content appears inactive when the container has one flex line or no extra cross-axis space. Wrapping must be enabled, enough items must actually wrap, and the container must be larger than the combined line cross sizes.
Use align-items when the goal is to align items within a single line. Use align-content only for the line collection.
Common Mistake: Rigid Percentage Arithmetic
Calculating card bases as calc(33.333% - 20px) can work for a fixed design, but it couples item sizing to a particular gap and column count. Changes require coordinated recalculation, and rounding can introduce unexpected breaks.
Prefer a content-based length basis for flowing Flexbox layouts or Grid fractions for exact column layouts. Let the layout model express the relationship instead of reproducing a track algorithm manually.
Common Mistake: Ignoring Oversized Single Items
Flex-wrap can move items to new lines, but it cannot solve an item wider than the entire container. A fixed 40rem control still overflows a 20rem viewport even when placed alone.
Use max-inline-size, responsive media rules, wrapping text, minimum zero, or an intentional scrolling region according to the content. Test the widest realistic value, not only average content.
A Systematic Debugging Workflow
First confirm the target establishes Flexbox and flex-wrap is not nowrap. Inspect flex-direction to identify the main axis and determine whether the container has a usable main-size constraint. Then inspect each item's basis, preferred size, margins, gap, and min/max constraints.
Check whether items are shrinking enough to remain on the current line or protected by intrinsic minimums. Inspect each line independently for growth and justify-content behavior. For cross-axis line placement, verify that multiple lines and extra cross space exist before testing align-content. Finally, ask whether the design requires Grid tracks instead.
1. Confirm display: flex and flex-wrap
2. Identify the main axis and available size
3. Inspect item bases, margins, and gaps
4. Check shrink factors and minimum sizes
5. Inspect each flex line independently
6. Separate align-items from align-content
7. Test the incomplete final line
8. Reconsider Grid for shared columns
Complete Responsive Example
This course list uses content-driven wrapping. Every course starts around 14rem, grows to share its line, and moves to a new line when the container cannot support another useful item.
<div class="course-list">
<a class="course" href="#">CSS</a>
<a class="course" href="#">Java</a>
<a class="course" href="#">Selenium</a>
<a class="course" href="#">SQL</a>
<a class="course" href="#">Docker</a>
</div>
.course-list {
display: flex;
flex-wrap: wrap;
gap: 1rem;
}
.course {
flex: 1 1 14rem;
min-width: 0;
padding: 1rem;
}
The final line may contain wider courses because it is independent. That is acceptable for a flowing course picker. If the requirement changes to aligned catalog columns, replace the outer layout with Grid rather than forcing Flexbox to imitate shared tracks.
Common Interview Questions
What does flex-wrap do? It controls whether flex items remain on one line or may be collected into additional flex lines.
What is its initial value? nowrap, so a flex container is single-line by default.
Which values are commonly used? nowrap, wrap, and wrap-reverse.
What does wrap-reverse reverse? It reverses the cross-axis stacking direction of the flex lines, not the item sequence within each line.
Why can the final row contain wider items? Every flex line calculates and distributes its own free space independently.
What does align-content control? It distributes multiple flex lines through available cross-axis space.
How does align-content differ from align-items? Align-content acts on the collection of lines; align-items aligns items inside each line.
Why might column wrapping not occur? An auto-height column can continue growing along its main axis, so no constrained main size forces a new line.
Does flex-wrap control text wrapping? No. It wraps flex items; text wrapping inside an item is controlled separately.
When is Grid preferable? Use Grid when rows must share aligned column tracks or the layout is fundamentally two-dimensional.
Practical Review Checklist
- Enable
flex-wrap: wrapexplicitly when multiple lines are acceptable. - Give items a meaningful flex-basis for content-driven responsive wrapping.
- Use gap for predictable gutters between items and lines.
- Include gaps, margins, padding, and borders when reasoning about line fitting.
- Remember that every flex line sizes and justifies itself independently.
- Test incomplete final lines with one, two, and several remaining items.
- Use align-items for items within lines and align-content for the line collection.
- Provide a constrained main size when intentional column wrapping is required.
- Handle oversized content and automatic minimum sizes inside each item.
- Keep DOM, reading, and keyboard order meaningful when lines wrap.
- Avoid reverse directions unless their visual sequence is genuinely required.
- Test zoom, localization, long labels, dynamic counts, and narrow containers.
- Use Grid when shared two-dimensional tracks are the real requirement.
- Use DevTools Flexbox overlays to inspect line boundaries and item sizes.
Key Takeaway
flex-wrap determines whether a flex container remains one line or can create additional lines. No-wrap keeps every item in one line and relies on shrinking or overflow management. Wrap fills the current line, starts another when the next item does not fit, and stacks those lines along the cross axis. Wrap-reverse changes that cross-axis stacking direction without changing the underlying source sequence.
Use wrapped Flexbox for content-driven one-dimensional groups such as tags, actions, filters, and toolbars. Give items a sensible basis, use gap for gutters, and remember that every line distributes its space independently. Use align-items within lines and align-content between lines. When the design requires stable columns shared across rows, choose CSS Grid instead of forcing Flexbox to behave like a two-dimensional track system.