Distribution
You are given a plain request in prose — “a file row with an icon, the file name, the size and a delete button” — and you return, for every participant that request implies, one situation code and one className. The request never states a width and you never estimate one: the width follows from what each participant does when there is space left over and what it does when there is not enough.
Law
A row has one width and more than one claim on it. Distribution is the decision of who takes the surplus, who gives way to the deficit, and who holds still through both.
The space is divided among participants. A participant is a direct child of the distributing parent, or a seam between two of them. Every participant answers the same two questions — what do you do when there is space left over, and what do you do when there is not enough — and the pair of answers is the code.
When the two answers disagree, the deficit decides the code. A child may take surplus and still refuse the deficit; it is named by its refusal, because the refusal is the fact that breaks the row. Surplus is a matter of appearance. Deficit is a matter of whether the row still holds its contents.
This is binding, not advisory. Any parent that lays its children along an axis — a flex row, a
flex column, a grid — gives every one of its participants a distribution situation, and that
situation has a code below. There is no row too small to have one: an icon beside a label is
DIST-3 next to DIST-1 for the same reason a fixed rail beside a result region is DIST-5 next
to DIST-1. “It is only an icon and a label” is not an exemption — it is the row where the first
long name in production pushes the icon off the card.
Situation codes
The code names the SITUATION — one participant’s role in dividing one axis of one parent. The className column names what that situation emits, and one of the codes emits nothing.
| Code | Situation | className |
|---|---|---|
DIST-0 | The participant takes its natural size and nothing is declared about it | no distribution class |
DIST-1 | One child takes the whole surplus and absorbs the whole deficit | min-w-0 flex-1 |
DIST-2 | Several children divide the axis between them in equal measure | min-w-0 flex-1 on each · grid-cols-<n> |
DIST-3 | A child that must never shrink, whatever the row is asked to hold | shrink-0 |
DIST-4 | A child that must be permitted to shrink, though it takes no surplus | min-w-0 |
DIST-5 | A child that holds a measure decided by layout, not by its content | w-64 shrink-0 · track 16rem |
DIST-6 | No child takes the surplus; a chosen seam takes it | ml-auto · parent justify-between |
DIST-0 IS A SITUATION, NOT A BLANK. A flex child that declares nothing is not neutral: it already
refuses to grow, and it already agrees to shrink — but only down to the width of its own content,
and not one pixel further. That floor is invisible in every mockup and decisive in production. The
code exists because “nothing declared” is a case a reader must be able to recognise, cite and be
corrected against. A situation with no name is a situation nobody can be shown to have got wrong,
and this is the situation that is got wrong most often — not by choosing it, but by arriving at it.
min-w-0 is a permission, not a style. A flex child’s minimum size is its content. Until that
minimum is released, the child does not shrink: it holds its full content width and pushes its
sibling out of the row instead. Nothing appears broken in the class list — the row simply stops
being a row. This is why DIST-4 exists as a code of its own, and why DIST-1 and DIST-2 carry
min-w-0 in their emission rather than leaving it to be remembered. A truncation, a clamp or a
scroll box inside a row is inert until every link of the chain between the row and that element has
been given permission to shrink. One min-w-0 on the outer child does not release a nested child
three levels down. On the block axis the same law reads min-h-0.
A declared width does not hold. Writing a width on a flex child states a preference, not a rule.
Flex shrinking is on by default, so that child gives up its declared measure the moment the row is
short — quietly, proportionally, and without any sign that a number was ever written. DIST-5 is
therefore always two declarations: the measure, and the refusal to give it up. In a grid the same
fact reads differently: a 1fr track has an automatic minimum, so a track holding long content
refuses to shrink and stretches the grid past its container. minmax(0,1fr) is the grid spelling of
min-w-0, and it is required for the same reason.
The seam is a participant. Free space that no child claims does not vanish; it collects somewhere.
DIST-6 is the decision to put it in a chosen seam instead of inside a child — the difference
between a title that stretches and a title that stays its own width while the action moves to the
far edge. This module owns who receives the space; the resting distance between siblings is a
different decision. A seam given surplus by DIST-6 is a gap that grew, not a gap that was chosen
larger.
Reading a request
- List the distributing parents the request states, and for each one name its axis. “A file row with an icon, the file name, the size and a delete button” states one parent, one inline axis.
- Do not invent a participant the request never mentions. A rail, a second column or a menu is not in that request. Resolve what is stated; resolve the rest when it arrives.
- Resolve outermost first, then each nested distributing parent. A participant’s code belongs to one axis of one parent; a child never inherits the code of the row inside it.
- For each participant ask the two questions — what does it do with surplus, what does it do with deficit — and read the sections below. The first code whose situation matches is the answer. When the two answers disagree, the deficit decides.
- Check the row can hold. At most one child is
DIST-1per axis per parent, and at least one participant must be able to absorb the deficit. A row of onlyDIST-3andDIST-5has declared in advance that it will overflow. - If two codes both match, prefer the code that declares less. If one parent mixes roles that cannot coexist, nest before choosing.
DIST-0 — nothing declared, and that is still a behaviour
Situation. Nothing in the row is long enough to compete for space: every child is short, closed content, and their total width is always less than the row. Nobody needs priority, nobody needs protection.
Recognition signs
- Every value in the row comes from a closed set: fixed labels, icons, numbers of known length.
- No child needs to reach the right edge of the row.
- No child is cut, wrapped or scrolled — because there has never been a deficit.
Ask yourself. Is there any real data that makes the children’s total width exceed the row? If
there is none — DIST-0.
Boundary
DIST-3:DIST-0is “there has never been a deficit”;DIST-3is “there may be one, but this child is exempt from giving way”. If even one child in the row comes from user-entered data, the row is no longerDIST-0.DIST-4: both take no surplus, butDIST-0stops at the content floor and pushes its sibling out;DIST-4is when that floor is the thing that must be removed.
Common business situations. A cluster of short status labels · icon + count · a fixed two-level breadcrumb · level badges · page-number pagination · a social icon cluster · a unit label beside a number.
DIST-1 — one child takes the whole row
Situation. Exactly one thing in the row is real content of unpredictable length, and everything else is an accessory around it: avatar, icon, badge, button, timestamp. That content both takes the surplus and is the one that gives way to the deficit.
Recognition signs
- Exactly one child comes from user data or business data.
- The remaining children have widths that can be predicted before the page runs.
- If that content grows longer, the thing that must get smaller is it, not the accessories.
Ask yourself. If the longest possible string lands in this row, who gives way? If there is only
one such participant and it is also the one entitled to the leftover space — DIST-1.
Boundary
DIST-2:DIST-1is one child taking everything;DIST-2is several dividing it. Two children both carryingflex-1are not twoDIST-1— that isDIST-2misspelled.DIST-4:DIST-4gives way but takes no surplus. If the child must shrink yet must not stretch to the edge, it isDIST-4, notDIST-1.DIST-3carryinggrow: if the child grows but must never be cut, the deficit decides — it isDIST-3, and the row must find someone else to give way.
min-w-0 is part of this code, not an addition. Without it the child grows exactly as expected when
wide and does not shrink when narrow — it pushes its sibling out of the row. This is the failure
that reports nothing: the class list still reads correctly, only the row has stopped being a row.
Common business situations. Person name + action button · lesson title + progress badge · file name + size · thread title + timestamp · course name + price · search box in a toolbar · card title
- overflow menu · branch name + build status · wallet address + text button.
DIST-2 — several children divide the axis equally
Situation. Nobody in the row outranks anybody. The children are peer items, and equal width is the message itself: these things can be compared with each other.
Recognition signs
- The children are of one kind, in one role, usually produced from one array of data.
- Equal width is what the reader relies on to compare, not an accident of appearance.
- Adding or removing an item is ordinary for this screen.
Ask yourself. Is equal width here a business statement (“these things rank the same”), or does it merely happen to look even?
Boundary
DIST-1: see above.DIST-5: if one of the columns must hold a fixed measure, that column isDIST-5and only the rest divide what is left.- Equal share of the axis versus equal share of the surplus are two different things.
flex-1produces equal columns;growkeeps each child’s content width and divides only the leftover. Both areDIST-2; the discriminator is whether equality is between the columns or between the additions.
The number of columns is a layout decision, not a decision of each child. When the item count changes with the data, declare the column count on the parent instead of letting each child compute its own fraction.
Common business situations. Three overview metric tiles · a segmented button group · a course card grid · three pricing tiers · an answer-choice button group · a seven-day strip · a statistics strip in a header · a Cancel/Confirm pair spread across the full width on mobile.
DIST-3 — never shrink, whatever the row must hold
Situation. Something in the row loses everything when it loses a part: an icon squashed into an oval, a button with its word swallowed, a number cut in half. These are not allowed to be the one that gives way.
Recognition signs
- Reading only part of it makes the reader understand something wrong, not merely less.
- It is square, round, or holds a ratio that must be kept.
- It is something the user must be able to press — the touch target must not shrink with a sibling’s width.
Ask yourself. If this got 30% smaller, would the reader be misled, or simply read less? If
misled — DIST-3.
Boundary
DIST-0:DIST-0is a row that has never been short;DIST-3is a row that can be short with this child exempted. Once aDIST-1stands beside them, every accessory in the row needs to be stated asDIST-3.DIST-5:DIST-3takes its measure from its own content and locks it;DIST-5takes its measure from a layout decision.DIST-1: a child carrying bothgrowandshrink-0is stillDIST-3— the deficit decides.
shrink-0 says exactly one thing; flex-none says two. flex-none forbids both shrinking and
growing, and refusing to grow is already the default. Say the one thing you mean, so the next reader
does not have to guess which half was intentional.
Common business situations. Avatar · status icon · icon-only button · notification count badge · a checkbox in a row · a price · an order code · a lesson duration · a “New” badge · a chevron · a square thumbnail in a list row.
DIST-4 — must be permitted to shrink, but takes no surplus
Situation. This child must give way when the row is narrow, but must not swell when the row is wide. It takes exactly what it needs and returns space when space is demanded.
Recognition signs
- Its content is of unpredictable length.
- If it stretched to the edge the layout would misstate itself: an identity cluster torn away from its avatar, a small chip turned into a long bar.
- Inside it there is a
truncate, aline-clampor a scroll box — and those are not running.
Ask yourself. Must this get smaller when the row is narrow, and should it hold still when the
row is wide? If both are true — DIST-4.
Boundary
DIST-1:DIST-1gives way and takes;DIST-4only gives way.DIST-0: both take no surplus, butDIST-0stops at the content floor whileDIST-4is exactly the case where that floor must be lifted.
This is the most frequently missed code, and missing it produces no error to read. Every truncate
inside a row needs min-w-0 on every link between the row and the element that is cut. One
min-w-0 on the outermost child does not unlock a child three levels in. On the block axis the law
reads min-h-0: a column that must scroll inside a bounded parent grows past its ceiling instead of
scrolling until its minimum height is released.
Common business situations. A name + username cluster beside an avatar · a long tab label · a
filter chip carrying a user-chosen word · a folder name in a breadcrumb · a text cluster inside
another DIST-3 · a 1fr grid column holding long text · a scroll region inside a flex column.
DIST-5 — a measure decided by layout
Situation. This child’s width is a layout decision, not a consequence of content. The filter rail is 16rem wide because that is the size chosen for the rail, not because the longest label inside it measures that much.
Recognition signs
- If the content inside changes, the width must stay the same.
- The same width repeats on other screens — it is a constant of the product.
- The other side of the row is the side that adapts.
Ask yourself. Where does this number come from — from the longest content inside, or from a
layout decision already settled? If from the layout decision — DIST-5.
Boundary
DIST-3: see above.DIST-3locks a content size;DIST-5locks a number.DIST-2: if every column is decided by layout and they are equal, that isDIST-2in grid form, not severalDIST-5.
Writing the width alone does not hold it. Flex shrinking is on by default, so a child with
w-64 quietly becomes narrower than 64 when the row is short, with no sign that a number was ever
there. DIST-5 is always two declarations: the measure, and the refusal to give it up. In a
grid the same fact reads differently: a 1fr track has an automatic floor, so a track holding long
content stretches the whole grid past its container. minmax(0,1fr) is the grid spelling of
min-w-0, and it is required for the same reason.
Common business situations. A filter rail · a navigation sidebar · a cart pane pinned right · an inspector column · a rank-number column in a table · a fixed avatar column in a conversation list · the label column of a two-column form.
DIST-6 — the surplus falls into a seam, not into any child
Situation. Every child in the row wants to keep its own width, but the row must still span the full measure: one side sits hard left, the other hard right. The leftover has to go somewhere — and it goes into the space between.
Recognition signs
- There is an edge that one child is required to reach.
- No child should swell: swelling would misstate the meaning (a title dragged long, a button widened for no reason).
- Said aloud, the request is “push this to the right”, not “make that one wider”.
Ask yourself. Is the thing I want to grow a child, or the seam between children?
Boundary
DIST-1: this is the most expensive confusion in the module.flex-1on the title also pushes the button right — but it simultaneously turns the title into the participant that absorbs the whole deficit, and the title’s press target now stretches across the empty space. If the intent is to push, useDIST-6.- The resting distance between siblings is a separate decision;
DIST-6owns who receives the leftover. A seam widened byDIST-6is a seam that was stretched, not one that was chosen larger.
Never use an empty element to push. A <div className="flex-1" /> is a child with no content and no
meaning, and screen readers still traverse it as an element. Surplus is claimed by a seam, not by a
fake child. And justify-between with three children answers a different question: it divides the
surplus among every seam. When only one seam should open, group the children into two, or put
ml-auto on exactly the child that opens that seam.
Common business situations. A card header: title left, menu right · a dialog footer: secondary button left, primary right · a table row: label left, value right · a toolbar: filter group left, create button right · a list row: content left, chevron right · a total line.
Inputs
| Input | Evidence required |
|---|---|
| parent | The immediate distributing parent: flex row, flex column, or grid |
| axis | Inline (width) or block (height); each axis is a separate situation |
| participants | Direct children, plus any seam that has been given a role |
| surplus rule | Which participant is entitled to space left over |
| deficit rule | Which participant gives way first, and which must never give way |
| measure source | Whether a size comes from content or from a layout decision |
Rules
- Every participant of a distributing parent resolves to exactly one code, on exactly one axis.
- Deficit behaviour decides the code; surplus behaviour never overrides it.
- Every row contains at least one participant able to absorb the deficit. A row of
DIST-3andDIST-5only has declared, in advance, that it will overflow. - At most one child is
DIST-1per axis per parent. Two children claiming the whole surplus isDIST-2misspelled. min-w-0is required on every link of the chain from the row to the element that yields.- A declared measure is always paired with a refusal to shrink.
- Empty elements are never used to push. Space is claimed by a seam, not by a spacer child.
- Percentage and fraction widths are not distribution declarations in a parent that also draws a seam: the seam is added on top of them and the row overruns.
- The code does not change with viewport. A narrower screen makes the deficit more likely, not different.
- Skeleton and loaded content carry the same code on the same participant.
Exceptions
Exceptions are PART of the rule, not relief from it. Each is closed and cites the situation it applies to.
- A grower that must never be cut. A child that takes surplus but must keep its content intact
is
DIST-3carryinggrow, notDIST-1. The deficit decides. Some other participant in that row must then beDIST-1,DIST-2orDIST-4, or the row has nobody to give way. - Equal share of the row versus equal share of the surplus.
DIST-2emitsflex-1when the columns must end up equal to each other, andgrowwhen each child keeps its content measure and only the leftover is split. Both areDIST-2; the discriminator is whether equality is between the columns or between the additions. - Numbers, prices, identifiers and controls are
DIST-3even beside aDIST-1sibling. A value the reader cannot verify once shortened is not allowed to be the participant that gives way. - A single child is not a distribution situation. One child in a row divides nothing; give it a code only when a second participant exists.
- Two codes both match. Prefer the code that declares less:
DIST-0overDIST-3when nothing in the row can push,DIST-4overDIST-1when the child must yield but was never meant to fill. Ask one discriminating question only when the requester states that the larger role is required. - Responsive. A participant changes code only when the parent it belongs to changes — a rail that becomes a stacked block above the content is a different parent, not the same rail behaving differently.
- Block axis. The same code set, read as
min-h-0,shrink-0andflex-1on the block axis. A scroll region inside a flex column does not scroll until its minimum height is released.
Output
One block per participant, outermost parent first:
parent: <flex row | flex column | grid>
axis: <inline | block>
participant: <the child, or the seam>
surplus: <takes all | equal share | none | into the seam>
deficit: <absorbs | refuses | content floor>
situation: <DIST-0 | DIST-1 | DIST-2 | DIST-3 | DIST-4 | DIST-5 | DIST-6>
className: <no class | min-w-0 flex-1 | shrink-0 | min-w-0 | w-* shrink-0 | ml-auto>
reason: <business fact that excludes the adjacent code>Worked example
Request. “A file row: a file-type icon, the file name, the file size and a delete button.”
The request states one distributing parent on one axis: the row, inline. It states four
participants. It states no rail, no second column and no pinned edge, so no seam has been given a
role and there is no DIST-6 to resolve. It states no block axis, so no height situation is
resolved either.
parent: flex row
axis: inline
participant: file-type icon
surplus: none
deficit: refuses
situation: DIST-3
className: shrink-0
reason: a squashed icon misleads rather than shortens, which excludes DIST-0 in a row that already carries user dataparent: flex row
axis: inline
participant: file name
surplus: takes all
deficit: absorbs
situation: DIST-1
className: min-w-0 flex-1
reason: the file name is the row's only unpredictable content and is the one thing entitled to the leftover, which excludes DIST-4parent: flex row
axis: inline
participant: file size
surplus: none
deficit: refuses
situation: DIST-3
className: shrink-0
reason: a size the reader cannot verify once cut is not allowed to be the participant that gives way, which excludes DIST-4parent: flex row
axis: inline
participant: delete button
surplus: none
deficit: refuses
situation: DIST-3
className: shrink-0
reason: the press target must survive the longest file name, which excludes DIST-4The row holds because exactly one participant, the file name, can absorb the deficit. If the request
later says the size must sit hard against the right edge while the name stays its own width, the
name becomes DIST-4 and the surplus moves into a chosen seam — DIST-6.
Scope
This module governs one axis of one distributing parent: flex or grid. A block parent whose children already occupy the full measure divides nothing and has no situation here. What happens to the content inside a participant once it has yielded — cut, wrapped, clamped or scrolled — is a separate decision; this module decides only whether yielding is permitted at all.
It states a rule true of any front end. It names no product, no component library, no registry key
and no repository. Every example is an ordinary className on ordinary markup.