Minimal DOM
Fewest DOM nodes with React and Tailwind
Minimal DOM (React + Tailwind)
Same UI, fewest DOM nodes. Every element must earn its place. If you can delete it and nothing breaks (semantics, layout, behavior, required styling) → it shouldn’t exist.
A node is allowed only if it provides:
- Semantics/a11y — correct elements (
ul/li,button,label,form,nav,section), ARIA patterns, focus behavior - Layout constraint — needs its own containing block / positioning / clipping / scroll / stacking context (
relative,overflow-*,sticky,z-*,min-w-0) - Behavior — measurement refs, observers, portals, event boundary, virtualization
- Component API — can’t pass props/classes to the real root (and you tried
as/asChild/prop forwarding)
Before adding wrappers:
- Spacing → parent
gap-*(flex/grid) orspace-x/y-* - Separators → parent
divide-y / divide-x - Alignment →
flex/gridon existing parent - Visual (padding/bg/border/shadow/radius) → on the element that owns the box
- JSX grouping →
<>...</>(Fragment), not<div>
Styling children — props first, selectors second:
- Mapped component → pass
classNameto the item - Uniform direct children →
*:or[&>tag]:to avoid repeating classes
// bad: repeated classes
<div className='divide-y'>
<p className='px-3 py-2'>A</p>
<p className='px-3 py-2'>B</p>
</div>
// good: selector pushdown
<div className='divide-y [&>p]:px-3 [&>p]:py-2'>
<p>A</p>
<p>B</p>
</div>Tailwind selector tools:
*:direct children ·[&>li]:py-2targeted ·[&_a]:underlinedescendant (sparingly)group/peeron existing nodes →group-hover:*,peer-focus:*data-[state=open]:*,aria-expanded:*,disabled:*first:last:odd:even:only:— structural variants
Review checklist: Can I delete this node? → delete. Can gap/space/divide replace it? → do it. Can I pass className? → do it. Can [&>...]: remove repetition? → do it.