Skip to content

Import

import { Space } from '@dnb/eufemia'

Description

The Space component provides margins within the provided spacing patterns.

Relevant links

The reason this exists is to make your syntax as clean as possible. This way, you see directly in words what the spacing is for every affected component.

Spacing Table

PixelTypeRemCustom Property
8x-small0.5--spacing-x-small
16small1--spacing-small
24medium1.5--spacing-medium
32large2--spacing-large
48x-large3--spacing-x-large
56xx-large3.5--spacing-xx-large

NB: In some circumstances you may be in need of using 0.25rem (4px) - therefore xx-small also exists, but as a single type. So, combining xx-small and small would not result in 0.25rem, but still remain 1rem.

Value Format

There are a couple of different ways you can define the spacing types and values:

  • Types: small small x-small (combine types up to 10rem)
  • number: 2.5 (equivalent to rem)
  • string(rem): 2.5rem
  • string(px): 40px (gets converted to rem)
  • boolean: true (equivalent to small), false (equivalent to zero)

To get a spacing of e.g. 2.5rem (40px), you may combine types large and x-small.

{/* All of these methods will result in the same spacing */}
<Space top="large x-small" right="2.5" bottom="2.5rem" left="40px" />

With React, you can also use an object with the different directions:

{/* All of these methods will result in the same spacing */}
<Space
  space={{
    top: 'large x-small',
    right: '2.5',
    bottom: '2.5rem',
    left: '40px',
  }}
/>

Components and Spacing

Every component supports the spacing patterns, so it's possible to send in the top, right, bottom, left and space properties directly, like:

<Button top="large x-small medium" />
<Button
  space={{
    top: 'large x-small medium',
  }}
/>

Spacing shorthands

A shorthand for getting 1rem (most used) is to simply send in a boolean set as true. No given value in JSX means true, so you only need the property key:

{/* Equivalent to top="small" */}
<Button top />
{/* Equivalent to top="small" right="small" bottom="small" left="small" */}
<Button space />

In order to set all four directions at once, you can provide a string as the space value:

<Button space="large x-small medium" />

Does it not work as expected?

Is margin not giving the expected spacing? That may be due to Margin Collapsing. Margins collapse in the following situations:

  • Adjacent siblings
  • Completely empty boxes
  • Parent and first or last child element

The best solution is to only use one direction of margins, e.g. bottom. Or you can set the collapse property to false.

Margin collapsing

In order to help handle unwanted margin collapsing in typography elements, see this example.

Conditional Reset

For resetting spacing (margin: 0) only when no spacing is defined, you can make use of dnb-space__reset.

Style and Spacing

Every Eufemia component that supports spacing props uses CSS custom properties (e.g. --margin-t-s) on the style attribute to drive responsive margins. When you pass a style prop to a component, your styles and the spacing styles are merged together — spacing properties take precedence.

This means you can safely combine your own styles with spacing:

<Space style={{ color: 'var(--color-sea-green)' }} top="medium">
...
</Space>

If you work with raw DOM elements and set styles via setAttribute('style', ...), make sure you preserve any existing style values when adding new ones, so the spacing custom properties are not lost.

const existing = element.getAttribute('style')
const merged = existing
? `${existing.replace(/;?\s*$/, '')}; ${style}`
: style
element.setAttribute('style', merged)

Demos

Spacing method #1

Space component. The RedBox is only to visualize the result.

<RedBox>
  <Space top="large x-small">
    <Input label="Input" />
  </Space>
</RedBox>

Spacing method #2

Define the space directly.

<Input label="Input A" bottom="small" />
<Input label="Input B" />

Spacing method #3

Using createSpacing or applySpacing.

Space A
Space B
Inner Space
Has space when breakpoint is large
const Component = ({ className = null, style = null, ...props }) => {
  const params = applySpacing(props, {
    ...props,
    className: `my-component dnb-space ${className || ''}`.trim(),
    style,
  })
  return <div {...params} />
}
render(
  <>
    <RedBox>
      <Component top="small medium large">Space A</Component>
    </RedBox>
    <RedBox>
      <Component top>Space B</Component>
    </RedBox>
    <RedBox>
      <Component innerSpace="large">Inner Space</Component>
    </RedBox>
    <RedBox>
      <Component
        innerSpace={{
          large: true,
        }}
      >
        Has space when breakpoint is large
      </Component>
    </RedBox>
  </>
)

Responsive space

The space property supports media query breakpoints (small, medium, large) for responsive spacing. Provide an object with breakpoint keys to apply different values at each screen size.

Content

<RedBox>
  <Space
    space={{
      small: 'large x-small',
      medium: {
        top: '2rem',
        left: '16px',
        bottom: 'large',
        right: '5rem',
      },
      large: true,
    }}
  >
    <P>Content</P>
  </Space>
</RedBox>

Responsive innerSpace

The innerSpace property controls padding inside the Space component. It shares the same API as space.

Content

<RedBox>
  <Space
    innerSpace={{
      small: 'large x-small',
      medium: true,
      large: {
        top: '2rem',
        left: '16px',
        bottom: 'large',
        right: '5rem',
      },
    }}
  >
    <P>Content</P>
  </Space>
</RedBox>

inline and block shorthand

Both space and innerSpace properties support inline and block shorthand properties for more semantic spacing control.

  • inline applies spacing to left and right (horizontal)
  • block applies spacing to top and bottom (vertical)
space: inline=small (left/right), block=large (top/bottom)
innerSpace: inline=medium (left/right), block=x-small (top/bottom)
Combined: space block=large + innerSpace inline=medium, block=small
Responsive inline/block for both space and innerSpace
Different combinations per breakpoint
Mixed: space inline + top override, innerSpace block
{/* Basic inline/block usage for space (margin) */}
<Space
  space={{
    inline: 'small',
    block: 'large',
  }}
>
  <RedBox>
    space: inline=small (left/right), block=large (top/bottom)
  </RedBox>
</Space>
{/* Basic inline/block usage for innerSpace (padding) */}
<Space
  innerSpace={{
    inline: 'medium',
    block: 'x-small',
  }}
>
  <RedBox>
    innerSpace: inline=medium (left/right), block=x-small (top/bottom)
  </RedBox>
</Space>
{/* Combining both space and innerSpace with inline/block */}
<Space
  space={{
    block: 'large',
  }}
  innerSpace={{
    inline: 'medium',
    block: 'small',
  }}
>
  <RedBox>
    Combined: space block=large + innerSpace inline=medium, block=small
  </RedBox>
</Space>
{/* Media queries with inline/block for both properties */}
<Space
  space={{
    small: {
      inline: 'x-small',
    },
    medium: {
      block: 'medium',
    },
    large: {
      inline: 'large',
      block: 'small',
    },
  }}
  innerSpace={{
    small: {
      block: 'x-small',
    },
    medium: {
      inline: 'small',
    },
    large: {
      inline: 'medium',
      block: 'large',
    },
  }}
>
  <RedBox>
    <div>Responsive inline/block for both space and innerSpace</div>
    <div>Different combinations per breakpoint</div>
  </RedBox>
</Space>
{/* Mixing inline/block with traditional directional props */}
<Space
  space={{
    inline: 'small',
  }}
  top="x-large"
  innerSpace={{
    block: 'medium',
  }}
>
  <RedBox>Mixed: space inline + top override, innerSpace block</RedBox>
</Space>

Spacing with no margin collapse, due to the flex usage

I have bottom="small"
I have top="large"

All four values will result in an equivalent margin

I have four 2.5rem margins!And this are my CSS classes: dnb-space dnb-space__top--large dnb-space__top--x-small dnb-space__right--large dnb-space__right--x-small dnb-space__bottom--large dnb-space__bottom--x-small dnb-space__left--large dnb-space__left--x-small

Visual space testing

With dnb-core-style

Without