Drupal Paragraphs spacing: solving the gaps in component-based layouts
You can build a beautiful paragraph system and still watch it fall apart the first time an editor stacks two white sections together. Spacing is the detail that quietly decides whether a component-based layout feels polished or broken.
Drupal Paragraphs spacing - the vertical margins and padding between and inside Drupal Paragraphs components - is one of those problems that never shows up in the demo and always shows up in production. You design each paragraph type to look great in isolation. Editors love the new flexibility. Then they stack two white paragraphs and the gap between them is enormous. Or they remove a title and a strange empty band appears where the heading used to be.
Every paragraph-based system hits this eventually. We have run into it on our own Droopler distribution, on client projects, and we designed for it deliberately on a recent corporate rebuild. This post covers why spacing issues are inevitable, the three approaches to solving them, a concrete implementation with code, and the real-world scenarios that decide which approach you actually need.
In this article:
- Why spacing issues always emerge
- Three approaches to spacing control
- Implementing spacing controls on your paragraphs
- Real-world spacing scenarios and how to solve them
- Best practices for paragraph spacing
Why spacing issues always emerge
When you first build a paragraph type, you give it a fixed vertical rhythm: some margin above, some below, some internal padding. It looks perfect, because you are testing it against the "happy path" - one paragraph, with all its fields filled in, sitting between two other well-behaved paragraphs.
Real content does not stay on the happy path. The same fixed spacing that looks balanced in the demo starts producing problems as soon as editors combine components in ways you did not anticipate:
- Two same-background paragraphs stacked. When a white section sits directly on top of another white section, their margins add up. Instead of one clean divider, you get a cavernous gap that visually splits the page in two.
- Optional fields left empty. A paragraph with a hidden or empty title field leaves behind the space that the title would have occupied. The result is a band of whitespace that looks like a mistake.
- Sections that should read as one. Sometimes an editor wants two paragraphs to feel like a single continuous block - no visible seam. Fixed margins make that impossible, because there is always a gap pushing them apart.
- Different content densities. A dense data table and a short call-to-action need different breathing room. One fixed value cannot be right for both.
The root cause is simple: spacing is contextual, but CSS, by default, is absolute. A margin value does not know whether the paragraph above it is white or dark, full or empty, meant to be separate or meant to be joined. The editor knows. The system does not - unless you give the editor a way to tell it.
Three approaches to spacing control
There is no single correct way to handle Drupal Paragraphs spacing. There are three, and the right one depends on how varied your content is and how much control your editors need.
Approach 1: fixed spacing with no controls
Every paragraph type ships with a single, hard-coded spacing value. There are no options in the admin form.
- Pros: simple to build, perfectly consistent, and editors never have to make a decision.
- Cons: breaks on every edge case above, offers zero flexibility, and quietly generates support tickets whenever real content collides with the fixed values.
- Best for: simple sites with predictable layouts, where editors assemble pages from a narrow, well-understood set of patterns.
This is where most projects start. It is also where most projects eventually get stuck, because the first awkward gap turns into a developer request that fixed spacing cannot solve from the editor's side.
Approach 2: selectable spacing with editor controls
Each paragraph exposes spacing options directly in the editing form. The editor chooses the margin and padding from a small set of named sizes.
- Margin control: none / small / medium / large
- Padding control: none / small / medium / large
- Pros: flexible enough to handle edge cases without a developer, and it puts the contextual decision where the context actually lives - with the editor on the page.
- Cons: slightly more complexity in the admin form, and without guardrails it can lead to inconsistent spacing across a site.
- Best for: corporate sites with varied content and component-based systems where the same paragraph appears in many different contexts.
This is the approach we recommend for any serious reusable component library. It is also what we ended up adding to both Droopler and client projects after fixed spacing proved too rigid.
Approach 3: automatic, context-aware spacing
Instead of asking the editor, you let CSS detect context and adjust. Adjacent sibling selectors and margin-collapsing rules can, for example, remove the doubled margin when two white paragraphs sit next to each other.
- Pros: invisible to editors, no extra fields, and it fixes the most common cases automatically.
- Cons: limited reach, harder to debug, and fragile as the component library grows. Worst of all, it changes spacing in ways the editor cannot see or control - reorder two paragraphs and their margin or padding can suddenly shift, with no obvious reason and no way for the editor to fix it.
- Best for: simpler layouts, and only for a tiny set of truly obvious cases.
In practice, we recommend approach 2 as the default for any non-trivial site. Editor controls keep spacing predictable: what the editor sets is what they get, and reordering or duplicating a paragraph never produces a surprise. That predictability is exactly what automatic rules sacrifice. The moment spacing changes on its own - an editor moves a section and its padding silently changes - trust in the CMS erodes faster than any oversized gap would have cost you. If you use automatic rules at all, keep them to a minimum and let editors stay in control of everything else.
Implementing spacing controls on your paragraphs
Adding selectable spacing to a paragraph type is not a large piece of work. The mechanics are the same pattern you already use for color variants: a select field that maps to a CSS class.
The implementation comes down to four steps.
- Add the fields. Create two list (text) fields on the paragraph type, for example `field_margin` and `field_padding`. Give each the same options: none, small, medium, large.
- Render the values as classes. In the paragraph template, read the field values and apply them as modifier classes on the wrapper element.
- Define a spacing scale in CSS. Use custom properties so the whole scale lives in one place and stays consistent across components.
- Set sensible defaults. Pre-select medium so editors only change spacing when they need to, not on every paragraph.
Here is the Twig side, reading the two fields and adding modifier classes:
{% set spacing_classes = [
'paragraph--margin-' ~ (content.field_margin['#items'].value|default('medium')),
'paragraph--padding-' ~ (content.field_padding['#items'].value|default('medium')),
] %}
<div{{ attributes.addClass('paragraph', spacing_classes) }}>
{{ content|without('field_margin', 'field_padding') }}
</div>And the CSS, with the scale defined once as custom properties:
:root {
--space-s: 1.5rem;
--space-m: 3rem;
--space-l: 5rem;
}
.paragraph--margin-none { margin-block: 0; }
.paragraph--margin-small { margin-block: var(--space-s); }
.paragraph--margin-medium { margin-block: var(--space-m); }
.paragraph--margin-large { margin-block: var(--space-l); }
.paragraph--padding-none { padding-block: 0; }
.paragraph--padding-small { padding-block: var(--space-s); }
.paragraph--padding-medium { padding-block: var(--space-m); }
.paragraph--padding-large { padding-block: var(--space-l); }If you add a touch of automatic behavior on top - and we would keep it to an absolute minimum - limit it to one or two unambiguous cases. A single adjacent sibling rule, for example, removes the doubled gap between two same-background sections:
.paragraph--bg-white + .paragraph--bg-white {
margin-block-start: 0;
}This is exactly the model we settled on for Droopler. The key decision there was to expose two separate controls rather than one. Margin and padding solve different problems: margin pushes a paragraph away from its neighbors, while padding adjusts the space inside the paragraph, between its background edge and its content. We give editors three sizes for each. That combination covers almost every situation an editor runs into, without overwhelming them with pixel-level settings.
Read also: a quick way for editing and customizing a Drupal paragraph and the Geysir module for faster paragraph editing.
Real-world spacing scenarios and how to solve them
The reason we feel strongly about editor-side controls is that we have watched these exact scenarios play out across projects. None of them are hypothetical.
- Two white paragraphs stacked. This is the classic. Two sections with the same background create a doubled margin and a huge gap. The fix: the editor sets the second paragraph's top margin to none, and the two sections read as one.
- A hero followed by a content section. A hero needs different breathing room than two content blocks in sequence. With selectable margins, the editor tightens or loosens the transition without a ticket.
- A paragraph with no title. Remove the title and the space it reserved becomes an awkward empty band. The editor drops the padding a size to compensate, and the gap disappears.
- A full-bleed image paragraph. Edge-to-edge imagery usually wants zero padding so nothing frames it. A "none" padding option handles it instantly.
- Two paragraphs that should merge into one block. When an editor wants no visible seam between sections, zero margin between them is the only thing that works - and fixed spacing simply cannot deliver it.
On one client project, spacing was not a minor polish item. It was one of the most persistent sources of friction. The platform used a similar component model, built a little differently, and the constant battle was that the right amount of space depended entirely on what was in the content. Sometimes a section needed more room to look right, sometimes less, and stacked same-color sections always blew out. We eventually had to add explicit controls - small, medium, large - so editors could resolve it themselves. Droopler followed the same path: spacing controls were not there at the start, the same problems appeared, and we added margin and padding settings in response.
There is a planning lesson buried in that history. On a recent corporate rebuild, we deliberately architected the paragraph system so spacing controls could be added later without restructuring anything. They were not in the initial scope, but everyone involved knew, from experience, that the request would come. Designing for it upfront turns a future rebuild into a future configuration change.
Best practices for paragraph spacing
A few rules consistently keep spacing manageable as a component library grows.
- Start without controls, but architect for them. It is fine to launch with fixed spacing on a small site. What is not fine is building the system in a way that makes adding controls later a painful rebuild. Leave the door open.
- Use CSS custom properties for the scale. Define small, medium, and large once. When the design evolves, you change three values instead of hunting through every component.
- Limit the options. Three or four named sizes are enough. Pixel-perfect control sounds appealing but produces inconsistent pages and decision fatigue. Constraints are a feature.
- Document the spacing logic for editors. A short visual guide - what none, small, medium, and large look like - turns guesswork into confident choices. The best place for it is a live example page on staging.
- Test with real content combinations. Spacing problems only appear when paragraphs meet each other. Test stacked same-background sections, empty optional fields, and merged blocks, not isolated paragraphs in a vacuum.
The thread running through all of these is the same one behind every good paragraph system: design for how editors actually combine components, not for how each component looks on its own.
Want spacing that just works on your Drupal site?
This post draws on real production experience - building spacing controls into our Droopler distribution, fighting and fixing the same problems on client projects, and architecting a recent corporate Paragraphs system so spacing controls could be added the moment they were needed. The pattern repeats on every component-based build, which is exactly why it is worth planning for from the start.
Wrestling with spacing gaps in your own paragraph layouts, or planning a component system you want to get right the first time? Our team builds editor-friendly Paragraphs implementations, from spacing and color controls to clean Twig and CSS architecture. Visit our Drupal development services to see how we can help.