when divide-x, space-y and gap actually work together
Divide and space between utilities solve a specific problem that gap alone does not cover: visible divider lines between sibling elements and spacing in layout contexts without native flex or grid support. Anyone who understands how divide-x, divide-y, space-x and space-y work internally avoids unnecessary wrapper divs and picks the right tool for each use case.
Table of contents
- 1. What problem divide and space between utilities solve
- 2. The selector mechanics behind space-x and space-y
- 3. divide-x and divide-y: visible divider lines between children
- 4. Adjusting divider color, style and thickness deliberately
- 5. gap versus space-x/y: which utility wins when
- 6. Reverse variants and direction flipping in RTL layouts
- 7. Typical use cases: lists, table rows, breadcrumbs
- 8. Performance and selector overhead with many child elements
- 9. Divide, space between and gap compared
- 10. Summary
- 11. FAQ
1. What problem divide and space between utilities solve
Since gap gained widespread support across flexbox and grid, one might assume that divide and space between utilities became redundant. That is only partly true. gap creates pure whitespace between sibling elements but cannot draw a visible divider line between them. That exact gap is filled by divide-x and divide-y, which insert a border between neighboring child elements without having to maintain a separate border class for every single divider.
Divide and space between utilities in Tailwind thus cover two distinct but related needs: space-x/space-y inserts pure spacing between child elements, much like gap, while divide-x/divide-y additionally draws a visible divider line. Both utility families work through the same CSS selector trick and are therefore technically closely related, even though their visual result differs.
The practical benefit shows up mostly in contexts where divider lines are needed between list items, table rows or navigation entries, without adding a border-b to every element individually and accidentally giving the last element a superfluous line too. Divide and space between utilities handle this logic automatically and cleanly.
2. The selector mechanics behind space-x and space-y
Technically, divide and space between utilities rely on the same principle known in the CSS community as the "lobotomized owl selector": * + *, applied to direct child elements. space-x-4 generates internally a rule like .space-x-4 > :not([hidden]) ~ :not([hidden]) { margin-inline-start: 1rem; }. This rule matches every child element except the very first, because only elements with a preceding sibling receive the margin. That produces spacing exclusively between the elements, never at the outer edge of the container.
This selector approach is the reason divide and space between utilities need no extra configuration for the first or last element, unlike manually set margins, where you typically have to add last:mb-0 or similar exceptions. The downside of this technique: it generates a margin declaration for every affected child element, which in very complex, deeply nested structures means marginally more CSS selector matching effort than a single gap value on the parent element.
/* Generated CSS for space-x-4 (simplified) */
.space-x-4 > :not([hidden]) ~ :not([hidden]) {
margin-inline-start: 1rem;
}
/* Generated CSS for divide-y-2 */
.divide-y-2 > :not([hidden]) ~ :not([hidden]) {
border-top-width: 2px;
}
/* Only elements WITH a preceding sibling receive the margin/border,
the first child in the group is always left untouched */
3. divide-x and divide-y: visible divider lines between children
divide-y inserts a horizontal divider line between vertically stacked child elements, divide-x correspondingly inserts a vertical line between horizontally arranged elements. Both variants of the divide and space between utilities use the same * + * selector mechanics as space-x/space-y, but generate a border declaration instead of a margin. The result is a clean list of divider lines, without the first element getting a superfluous line at the top or the last element getting one at the bottom.
A common use case for divide-y from the divide and space between utilities are settings lists or activity feeds, where every entry should be visually separated from the next without inserting a separate, semantically meaningless divider element into the markup. Important to note: divide-y assumes the child elements have display: block or a comparable block context, with display: flex on the parent element without flex-col the divider line does not visually appear as expected.
<!-- Settings list with automatic divider lines, no border on first/last item -->
<ul class="divide-y divide-slate-200 rounded-xl border border-slate-200 overflow-hidden">
<li class="px-4 py-3 flex items-center justify-between">
<span>Notifications</span>
<span class="text-sky-700 text-sm">Enabled</span>
</li>
<li class="px-4 py-3 flex items-center justify-between">
<span>Two-factor authentication</span>
<span class="text-slate-400 text-sm">Disabled</span>
</li>
<li class="px-4 py-3 flex items-center justify-between">
<span>Newsletter</span>
<span class="text-sky-700 text-sm">Enabled</span>
</li>
</ul>
4. Adjusting divider color, style and thickness deliberately
Beyond the base utility divide-y, the divide and space between utilities offer further modifiers for color, stroke thickness and line style. divide-slate-200 sets the divider color, divide-y-2 or divide-y-4 the stroke thickness, and divide-dashed or divide-dotted change the line style away from the default solid. These modifiers combine freely, which is especially helpful for tables with visually highlighted category boundaries.
For design systems with defined divider colors, it pays to define the divider color through a @theme variable, instead of repeating it manually across the markup. That keeps the divide and space between utilities consistent with the rest of the color palette, and a later adjustment of the divider color requires only a single central change instead of many search and replace passes across the project.
<!-- Combining color, thickness and style modifiers on divide utilities -->
<div class="divide-y-2 divide-dashed divide-sky-300 rounded-xl border border-slate-200">
<section class="p-4">Quarter 1</section>
<section class="p-4">Quarter 2</section>
<section class="p-4">Quarter 3</section>
</div>
5. gap versus space-x/y: which utility wins when
In modern flexbox and grid layouts, gap replaces space-x/space-y in most cases, because gap generates no margin declarations on every child element but defines spacing centrally on the container. That has two practical advantages: gap works correctly with flex-wrap, because the spacing stays even across wrapped rows too, while space-x can lead to inconsistent horizontal spacing with wrapped flex items. For this reason the Tailwind maintainers now recommend gap as the default solution for most flex and grid layouts.
Divide and space between utilities nevertheless keep their place in two situations: first, when a visible divider line is actually needed, since gap fundamentally cannot generate a border. Second, in layout contexts without flexbox or grid, for example plain block elements, where gap is unavailable but space-y still works reliably. For pure spacing in flex or grid containers with no divider need, gap is the better choice today.
6. Reverse variants and direction flipping in RTL layouts
Tailwind offers space-x-reverse and space-y-reverse for situations where the visual order of child elements gets reversed through CSS, for example through flex-row-reverse. Without this reverse variant, the margin would still get calculated based on the original DOM order, which leads to incorrectly positioned spacing in a visually reversed layout. The reverse variant of the divide and space between utilities corrects this behavior by reversing the margin direction as well.
Since Tailwind v3, space-x and divide-x already use logical properties like margin-inline-start instead of physical properties like margin-left, which automatically targets the correct side in RTL (right-to-left, for example Arabic or Hebrew) layouts without needing a separate RTL configuration. This logical property foundation makes divide and space between utilities internationalization friendly out of the box, a detail that is frequently overlooked with manually set margin classes.
7. Typical use cases: lists, table rows, breadcrumbs
Breadcrumb navigations are a classic use case for divide-x from the divide and space between utilities: every breadcrumb entry gets separated from the next by a thin vertical line, without having to manually insert a separate divider element like a slash into the markup. That reduces the number of DOM nodes and simplifies maintenance, since the divider color can be adjusted centrally through a single class on the parent element.
A second common case is the vertical separation of form sections in a settings dialog, where divide-y visually delimits every section without a superfluous line appearing at the start or end of the list. For horizontal action buttons, for example in a toolbar, space-x works well for pure spacing, while divide-x additionally signals a visual grouping of several buttons as a cohesive unit.
8. Performance and selector overhead with many child elements
The * + * selector behind the divide and space between utilities is fundamentally performant, because modern browser engines evaluate CSS selectors right to left, and the right part of the selector (the universal selector) matches all elements quickly, while the left part (the preceding sibling) handles the actual filtering. For lists with a few hundred elements, the difference to gap is not measurable in practice.
With very large lists containing several thousand child elements, for example in virtualized tables, the additional selector matching effort of the divide and space between utilities can theoretically add a minimal amount of weight compared to a single gap declaration on the container. In practice, however, this difference is usually clearly overshadowed by other factors like DOM size and JavaScript rendering time, so premature optimization here rarely delivers the hoped for effect.
9. Divide, space between and gap compared
The following overview sorts the three related utility families by use case.
| Utility | Generates | Best for |
|---|---|---|
| gap | Pure whitespace on the container | Flexbox and grid layouts, including wrap |
| space-x / space-y | Margin on child elements | Block contexts without flex/grid |
| divide-x / divide-y | Border on child elements | Visible dividers, lists, breadcrumbs |
| space-x-reverse | Reversed margin direction | flex-row-reverse, RTL layouts |
In practice, many components combine gap for pure spacing with divide-y for additional visual separation, for example a list with gap-0 divide-y, where the divider line forms the only visual boundary between entries.
Mironsoft
Tailwind layout systems and Hyvä frontend architecture
Looking for clean list and divider patterns?
We build consistent lists, tables and navigation components with divide and space between utilities, clearly delineated from gap based layouts.
Layout audit
Analysis of existing spacing and divider patterns
Component library
Reusable list and table components
RTL review
Internationalization friendly spacing and dividers
10. Summary
Divide and space between utilities solve a problem that gap alone does not cover: visible divider lines between sibling elements and spacing in layout contexts without native flex or grid support. Both utility families are built on the same * + * selector but produce different effects, space-x/space-y as margin, divide-x/divide-y as border, each exclusively between child elements, never at the outer edge.
In modern flexbox and grid layouts, gap today handles most pure spacing tasks more reliably, especially with wrapped rows. Divide and space between utilities nevertheless remain indispensable once a visible divider line is needed or flexbox or grid are unavailable. Their logical property foundation also makes both utility families RTL ready automatically, with no extra configuration.
Divide and Space Between Utilities — Key Takeaways
Selector mechanics
The * + * selector matches only elements with a preceding sibling, the first child stays untouched.
divide vs. space
divide-* generates a border for visible dividers, space-* generates pure margin.
gap as default
In flex and grid layouts, gap handles most pure spacing tasks more reliably.
RTL readiness
Logical properties like margin-inline-start make both utility families RTL ready automatically.