Layout components and spacings

September 3, 2026 · View on GitHub

This guide covers UIKit's layout foundations: a shared spacing scale (--g-spacing-*, used everywhere via tokens and props) and a responsive grid (Container/Row/Col), plus the flexbox-based Flex/Box primitives built on top of them. Compose pages from these instead of raw divs and inline styles.

English | Русский

Spacing

Spacing in UIKit is a scale, not free-form pixels. You reference a step (1, 2, … 10) and the design system turns it into a concrete size. Sticking to the scale is what keeps rhythm consistent across the whole app, and lets you rescale everything from a single variable.

The scale

Every step is a multiple of a base unit (--g-spacing-base, 4px by default), so step×4px\text{step} \times 4\text{px}:

StepCSS variableSize
0--g-spacing-00
0.5--g-spacing-half2px
1--g-spacing-14px
2--g-spacing-28px
3--g-spacing-312px
4--g-spacing-416px
5--g-spacing-520px
6--g-spacing-624px
7--g-spacing-728px
8--g-spacing-832px
9--g-spacing-936px
10--g-spacing-1040px

Because every step is derived from --g-spacing-base, changing that one value rescales the entire spacing system proportionally (see Customization).

Ways to apply spacing

There are three ways to consume the scale — pick by context:

1. Component props — spacing between children of Flex/Box, via the gap prop:

import {Flex} from '@gravity-ui/uikit';

<Flex gap={5}>
  <Button />
  <Button />
</Flex>; // 20px between children

2. CSS custom properties — the same steps as --g-spacing-{step} variables, for use in your own styles (e.g. --g-spacing-half for the 0.5 step):

.example-class {
  margin-right: var(--g-spacing-5); /* 20px */
  padding: var(--g-spacing-2) var(--g-spacing-4);
}

3. The spacing() utility — for one-off margins/paddings on any element without hand-writing class names. It returns a generated class name string:

import {spacing} from '@gravity-ui/uikit';

<>
  <Button className={spacing({mr: 5})}>button 1</Button>
  <Button className={spacing({mt: 2, px: 4})}>button 2</Button>
</>;

sp is a shorter alias: import {sp} from '@gravity-ui/uikit'sp({mr: 5}).

Supported keys (each takes a scale step):

KeyProperty
mmargin
mt mr mb mlmargin-top/right/bottom/left
mxhorizontal margin (left + right)
myvertical margin (top + bottom)
ppadding
pt pr pb plpadding-top/right/bottom/left
pxhorizontal padding (left + right)
pyvertical padding (top + bottom)

You can pass a second argument to merge extra class names: spacing({mr: 5}, myClassName).

Rule of thumb: gap for spacing between siblings in a Flex/Box; the spacing()/sp() utility for one-off offsets on an element; raw --g-spacing-* variables inside your own CSS. Always use scale steps, never hard-coded pixels.

Customization

Override the base unit to rescale the whole system. Do it via CSS at the project level:

:root {
  --g-spacing-base: 5px; /* now step 5 = 25px, etc. */
}

Or through the layout theme, which keeps the JS Space values and CSS variables in sync:

import {ThemeProvider, LayoutTheme} from '@gravity-ui/uikit';

const config: LayoutTheme = {
    spaceBaseSize: 5,
};

export const App = () => {
    return (
        <ThemeProvider layout={{config, fixBreakpoints: true}}>
            {...}
        </ThemeProvider>
    );
};

Screen sizes:

We use mobile-first approach. It means that you should adapt your app for desktop after completing development of mobile version. The default breakpoints are:

  • xs - < 576px
  • s - ≥ 576px;
  • m - ≥ 768px;
  • l - ≥ 1080px;
  • xl - ≥ 1200px;
  • xxl - ≥ 1400px;
  • xxxl - ≥ 1920px;

To override a breakpoint use the breakpoints property in the layout config:

const APP_LAYOUT_THEME: LayoutTheme = {
    spaceBaseSize: 4,
    components: {
        container: {
            gutters: 3,
            media: {
                l: {
                    gutters: 5,
                },
            },
        },
    },
    breakpoints: {
        s: 320,
        l: 980,
    },
};

<ThemeProvider layout={{config: APP_LAYOUT_THEME}}>
    {...}
</ThemeProvider>;

Box

The Box component is a developer friend and basic block to build other components. Aware about spacing, its own sizes and most commonly used CSS properties.

Use it to declaratively describe elements with a fixed height/width. It also has built-in support for the most commonly used properties, such as overflow. It is mainly used as a base unit for other components such as Flex and Card.

It is also well suited for use as a base for data loading containers, for example:

import React, {Suspense} from 'react';
import {Flex, Loader} from '@gravity-ui/uikit';

// `Flex` extended from `Box` component and enriched flexbox model properties
<Flex centerContent width="100%" height="100%">
  <Suspense fallback={<Loader size="m" />}>
    <LazyLoadedComponent />
  </Suspense>
</Flex>;

Layout Grid

Main components to describe 12-th column grid layout for your app. Supports nested grids. This should be used when you have mobile and desktop app versions.

import {Row, Col} from '@gravity-ui/uikit';

<Row space="5">
  <Col size="4">...</Col>
  <Col size="4">...</Col>
  <Col size="4">...</Col>
</Row>;

Row

Props

  • space - specify horizontal spacing between child Col components;
  • spaceRow - specify vertical spacing between child Col components. By default, it takes values from the space prop.

Col

How many columns of your 12-th column layout will take content. Must be used as a child of Row component.

Props

  • size - column width in column number (if omitted the column will occupy all free space in the row)
import {Row, Col} from '@gravity-ui/uikit';

<Row
  /**
   * In this example we override default theme behavior.
   *
   * space={{s: '1', xl:'5'}}
   */
  space="5"
>
  <Col
    // Will be:
    // 12 for "xs" and "s"
    // 6 for "m" and "l"
    // 4 for "xl" and "xxl"
    size={[12, {m: 6, xl: 4}]}
  />
</Row>;

Grid system use negative margins under the hood. So you can specify background-color css property directly in Col components. Use wrapper components in such cases.

Container

Center you content. Almost always it should be one per page. Manage max width corresponding to current screen size

Props

  • gutters - left and right content padding. Needed when you content width equals screen width;
  • maxWidth - limits screen width for specific screen size;
  • spaceRow - ability to specify spacing between children Row components

Flex

CSS Flexbox model representation in jsx world. Has built-in spacing to manage space between children. All flex properties are available in props. For most used properties it supports object syntax config to override behavior in different screen sizes.

Examples

Space between children components in row direction

import {Flex, TextInput, Button} from '@gravity-ui/uikit';

<Flex space="5">
  <TextInput />
  <Button />
</Flex>;

Nested Flex example

import {Flex, TextInput, Button, Table} from '@gravity-ui/uikit';

<Flex direction="column" space="5">
  <Flex space="5">
    <TextInput />
    <Button />
  </Flex>
  <Table />
</Flex>;

Responsible example

import {Flex, TextInput, Button} from '@gravity-ui/uikit';

<Flex
  // direction: column will be applied to l, xl, xxl, xxxl screen sizes here
  direction={{l: 'column'}}
  space={{s: '5', m: '3'}}
>
  <TextInput />
  <Button />
</Flex>;

Hooks

useLayoutContext

Hook useLayoutContext provide ability to use LayoutTheme and helper functions to work with media queries.

It returns the following methods and objects:

  • theme - LayoutTheme object;
  • activeMediaQuery - returns current Screen sizes keys.
import {useLayoutContext} from '@gravity-ui/uikit';

const Component = () => {
  const {activeMediaQuery} = useLayoutContext();

  return (
    <>{activeMediaQuery === 'l' ? <Text>I render only on screen resolution "l"</Text> : null}</>
  );
};
  • isMediaActive - returns true if passed value is equal to or greater than the current active media. It is necessary to implement logic of adaptive elements for mobile-first approach.
import {useLayoutContext} from '@gravity-ui/uikit';

// this example will be shown on xl, xxl and xxxl screen sizes
const Component = () => {
  const {isMediaActive} = useLayoutContext();

  return (
    <>{isMediaActive('xl') ? <Text>I render on "xl", "xxl" and "xxxl" screen sizes</Text> : null}</>
  );
};
  • getClosestMediaProps - it works in a similar way as isMediaActive, but takes a map with screen media as an argument. Returns the nearest available value in the map taking into account the mobile-first approach.
import {useLayoutContext} from '@gravity-ui/uikit';

const mapOfPropsByScreen = {
  s: "i'm will be shown on 's' and 'n' screen size",
  l: "i'm will be shown on 'l' and 'xl' screen size",
  xxl: "i'm will be shown on 'xxl' and 'xxxl' screen size",
};

const Component = () => {
  const {getClosestMediaProps} = useLayoutContext();

  return <Text>{getClosestMediaProps(mapOfPropsByScreen)}</Text>;
};