Spacing Is a Component’s Problem Until It Isn’t

Every UI component needs breathing room, but deciding who owns that spacing is one of the messier questions in design system work. Take a <Card /> component. If it’s used inside a <Grid /> that applies gap: 1rem, any margin you bake into the card itself will fight the grid’s gap. Hard-coded directional margins like margin-block-end: 1rem; margin-inline-end: 1rem; also assume a fixed flow direction and a rigid value—neither of which survives real-world usage.

Example of a component spacing where a card component is to the left of an accordion component and above an article, with 50 pixels of spacing between all three elements. Lorem i-sum text throughout in a mono font. The card has a Calvin and Hobbes comic image.
Adding space to the inline start and block end of a card component.

Three Ways Teams Approach It

Eric Bailey has walked through the common strategies, and they each come with tradeoffs:

  • Bake spacing into every component. Self-contained but inflexible; components that always carry margins are hard to place in tight layouts.
  • Pass spacing in as a prop. Something like <Card space="xxl" /> works, but you quickly need multiple props—one per direction—and the API gets noisy.
  • Use a dedicated <Spacer /> or <Layout /> wrapper. Clean separation of concerns, but verbose markup and extra DOM nodes.

At the extreme end of the spectrum, Max Stoiber has argued for never using margin at all. That stance is overly dogmatic, but it points at a useful instinct: letting content components stay oblivious to where they’re placed, and pushing layout decisions one level up.

Adam Argyle predicted years ago that margin usage would fall as gap usage rises. That prediction is aging well—especially now that flexbox supports gap and developers are comfortable reaching for Flexbox and Grid at both macro and micro layout scales. The more spacing happens at the container level with gap, the less components need to know about their neighbors.