Layout

May 29, 2026 · View on GitHub


Core layout primitives

These are the fundamental building blocks for spacing, alignment, and visual structure. Use them to compose any UI inside a page.

Box

Box provides a set of padding options which can be used to create container elements with internal spacing. All padding props accept a numeric value or a responsive object {mobile, tablet?, desktop}.

<Box paddingX={16} paddingY={32}>
  <Text2>Example</Text2>
</Box>

:warning: Do not use Box to add external spacings or distribute items, instead use Stack or Inline.

You can also use Box as a fixed width container:

<Box width={80}>
  <Text2>Example</Text2>
</Box>

Stack

Vertically distributes its children using the given space separation.

<Stack space={24}>
  <Child1 />
  <Child2 />
  <Child3 />
</Stack>

Inline

Horizontally distributes its children using the given space separation. This component can be considered as a horizontal Stack, and it covers the most common row-layout use cases you might otherwise solve with display: flex.

It supports:

  • horizontal distribution via space={number} or space="between" | "around" | "evenly"
  • vertical alignment of children via alignItems="flex-start" | "flex-end" | "center" | "stretch" | "baseline"
  • wrapping via wrap and row spacing via verticalSpace

:information_source: Check Inline in Storybook to learn more about it.

numeric space

<Inline space={16} alignItems="center">
  <Child1 />
  <Child2 />
  <Child3 />
</Inline>

between

Distribute items evenly. The first item is flush with the start, the last is flush with the end

<Inline space="between">
  <Child1 />
  <Child2 />
  <Child3 />
</Inline>

around

Distribute items evenly. Items have a half-size space on either end

<Inline space="around">
  <Child1 />
  <Child2 />
  <Child3 />
</Inline>

evenly

Distribute items evenly. Items have equal space around them

<Inline space="evenly">
  <Child1 />
  <Child2 />
  <Child3 />
</Inline>

nesting

Nest Inline components to compose richer rows. A common pattern groups a leading icon and label on the left with a value on the right via space="between":

<Inline space="between" alignItems="center">
  <Inline space={8} alignItems="center">
    <IconTruckRegular size={24} color={skinVars.colors.neutralHigh} />
    <Text2 regular>Envío:</Text2>
  </Inline>
  <Text2 regular>Mañana, gratis</Text2>
</Inline>

The outer Inline distributes the two groups to opposite ends; the inner Inline keeps the icon tightly grouped with its label at a fixed gap.

Grow

Use the expand prop to make one or more children of an Inline grow to fill the remaining horizontal space. It takes the index (or an array of indexes) of the children that should grow. Indexes follow React.Children.toArray order, so empty nodes (null, false) are skipped but rendered elements always count. You don't wrap the growing child in anything — Inline already wraps every child in its own element:

<Inline space={56} alignItems="center" expand={1}>
  <Text7>4,6</Text7>
  <InfoRating
    value={4}
    icon={{
      ActiveIcon: IconStarFilled,
      InactiveIcon: IconStarLight,
      color: skinVars.colors.textPrimary,
    }}
  />
  <Text3 regular>150 valoraciones</Text3>
</Inline>
<Inline space={16} alignItems="center" expand={[1, 2]}>
  <IconTruckRegular size={24} color={skinVars.colors.neutralHigh} />
  <TextField name="firstName" label="First name" fullWidth />
  <TextField name="lastName" label="Last name" fullWidth />
</Inline>

Common mistakes. Inline wraps each child in its own element, so growing a child by wrapping it in a <div style={{flex: 1}}> (or flex-grow) does nothing useful. Neither does <Box style={{...}}>Box has no style prop, so a flex or width passed that way is silently dropped and the row collapses or overflows its container. Reach for expand (and <Box width={N}> for any fixed sibling) instead.

Align

Positions its children within a container using CSS grid alignment. Useful for centering content or placing it at specific positions within a defined area.

<Align x="center" y="center" height="100%">
  <Text2 regular>Centered content</Text2>
</Align>
<Align x="end">
  <ButtonPrimary onPress={() => {}}>Action</ButtonPrimary>
</Align>

Grid / GridItem

A low-level CSS Grid component for creating custom grid layouts. For page-level column layouts, prefer GridLayout instead. Grid is ideal for card grids, image galleries, or any layout needing explicit row/column control.

<Grid columns={3} gap={{mobile: 8, desktop: 16}}>
  <Card1 />
  <Card2 />
  <Card3 />
</Grid>
<Grid columns={4} gap={16}>
  <GridItem columnSpan={2}>
    <FeatureCard />
  </GridItem>
  <GridItem>
    <SmallCard1 />
  </GridItem>
  <GridItem>
    <SmallCard2 />
  </GridItem>
</Grid>

NegativeBox

Some components, like non boxed Lists, need to be rendered overflowing its container, because the hover effect is larger than the container. This can be achieved using a NegativeBox.

By default both sides get negative margins. Use the left or right props to apply margin on one side only.

Without NegativeBox

OutlinePreview

As you can see there are two problems. The hover is not filling available horizontal space and Row circles are not aligned with the content container. These problems are solved using NegativeBox.

With NegativeBox

<ResponsiveLayout>
  <NegativeBox>
    <RowList>
      <Row1 />
      <Row2 />
      <Row3 />
    </RowList>
  </NegativeBox>
</ResponsiveLayout>
OutlinePreview

Hover effect fills horizontal space and circles are aligned with the container edge.

Divider

A simple horizontal divider line. Theme-variant-aware (adapts its color to the current ThemeVariant context). Takes no props.

<Stack space={16}>
  <Text2 regular>Section A</Text2>
  <Divider />
  <Text2 regular>Section B</Text2>
</Stack>

HorizontalScroll

A container that enables horizontal scrolling for its children. Useful for scrollable rows of cards, chips, tags, or any horizontally overflowing content.

<HorizontalScroll>
  <Inline space={8}>
    <Chip value="Option 1">Option 1</Chip>
    <Chip value="Option 2">Option 2</Chip>
    <Chip value="Option 3">Option 3</Chip>
    <Chip value="Option 4">Option 4</Chip>
  </Inline>
</HorizontalScroll>

Boxed

A rounded container with background color and optional border. Theme-variant-aware: the background and border automatically adapt based on the current and specified variant. Useful for creating visually distinct sections or card-like containers without card semantics.

<Boxed>
  <Box padding={16}>
    <Text2 regular>Content inside a boxed container</Text2>
  </Box>
</Boxed>

Overlay

A full-screen fixed overlay that covers the viewport. Used internally by dialogs, drawers, and sheets, but available for custom overlay use cases.

<Overlay onPress={handleClose} disableScroll>
  <MyCustomModal />
</Overlay>

StackingGroup

Displays a group of items (typically avatars or icons) with optional overlapping. Shows a "+N" indicator when items exceed maxItems.

<StackingGroup stacked maxItems={3} moreItemsStyle={{type: 'circle', size: 40}}>
  <Avatar size={40} src={avatar1} />
  <Avatar size={40} src={avatar2} />
  <Avatar size={40} src={avatar3} />
  <Avatar size={40} src={avatar4} />
  <Avatar size={40} src={avatar5} />
</StackingGroup>

Page layouts

These components define the overall structure of a page or screen. They handle responsive breakpoints, constrain content width, and provide standard page patterns.

ResponsiveLayout

Creates a responsive container for your page content. The size of this container depends on the viewport size. Supports a variant prop to set background color and theme variant, and fullWidth to remove margin constraints.

<ResponsiveLayout>
  <MyFeature />
</ResponsiveLayout>
MobileTabletDesktop

HeaderLayout

The HeaderLayout is responsible for render the page header and related components. It uses the ResponsiveLayout internally so you must not wrap it inside one.

<HeaderLayout header={<Header title="Header" />} />
<ResponsiveLayout>
  <MyFeature />
</ResponsiveLayout>
MobileTabletDesktop

Components that include ResponsiveLayout internally

The following components manage their own ResponsiveLayout internally. Do not wrap them inside a ResponsiveLayout — that would create a double-nested layout that breaks spacing and alignment.

ComponentReason
HeaderLayoutWraps its header content in a responsive container
MainSectionHeaderLayoutContains its own responsive wrapper
HeroManages internal responsive layout for content and media
CoverHeroApplies responsive layout to its text content column
MasterDetailLayoutFull-width responsive grid managed internally
ButtonFixedFooterLayoutFooter buttons aligned via an internal responsive container
NavigationBarAll navigation bar variants (including MainNavigationBar and FunnelNavigationBar) center content using an internal ResponsiveLayout
TabsTab list constrained with ResponsiveLayout fullWidth
SuccessFeedbackScreenAll feedback screen variants contain their own page layout
LoadingScreenBrandLoadingScreen also uses an internal responsive text layout

These components are placed directly at the page level, side by side with ResponsiveLayout blocks, not inside them:

<MainNavigationBar sections={[...]} selectedIndex={0} />
<HeaderLayout header={<Header title="Page Title" />} />
<Tabs selectedIndex={0} onChange={setTab} tabs={[{text: 'Tab 1'}, {text: 'Tab 2'}]} />
<ResponsiveLayout>
  <Box paddingY={24}>
    <Stack space={16}>
      <Text2 regular>Content</Text2>
    </Stack>
  </Box>
</ResponsiveLayout>

GridLayout

A 12-column grid with predefined templates for common page layouts. Must be used inside a ResponsiveLayout.

Available templates:

  • Split layouts (use left/right props): '6+6', '8+4', '5+4', '4+6', '3+9'
  • Centered single-column layouts (use children): '10', '8'
  • No template (raw 12-column grid, use children)
<ResponsiveLayout>
  <GridLayout
    template="6+6"
    left={<LeftComponent />}
    right={<RightComponent />}
  />
</ResponsiveLayout>
MobileTabletDesktop

MasterDetailLayout

A common layout pattern with a list of items in a left sidebar and a detail view in the main content area. In mobile, this translates to a navigation of 2 levels: a first screen with the list and a second screen with the content.

<MasterDetailLayout isOpen={isOpen} master={listView} detail={detailView} />

The isOpen prop controls whether the master (when false) or detail (when true) view is shown in mobile.

Take into account that the detail view is always visible in desktop, so if you want to show an empty state in desktop when there isn't any selected item from the aside list, you can do something like this:

<MasterDetailLayout isOpen={isOpen} master={listView} detail={isOpen ? detailView : emptyCase} />
Mobile MasterMobile DetailDesktop

FixedFooterLayout

A layout with a footer that sticks to the bottom of the viewport. The footer becomes fixed when there is enough available height, and scrolls with the content otherwise. Includes an elevation shadow on mobile when content is scrollable.

<FixedFooterLayout
  footer={
    <Box paddingX={16} paddingY={8}>
      <ButtonLayout primaryButton={<ButtonPrimary onPress={handleSubmit}>Confirm</ButtonPrimary>} />
    </Box>
  }
>
  <ResponsiveLayout>
    <Box paddingY={24}>
      <Stack space={16}>{/* page content */}</Stack>
    </Box>
  </ResponsiveLayout>
</FixedFooterLayout>

ButtonFixedFooterLayout

A convenience wrapper around FixedFooterLayout specifically for pages that need a fixed footer with buttons. Handles the button layout, responsive padding, and footer visibility automatically.

<ButtonFixedFooterLayout
  button={<ButtonPrimary onPress={handleConfirm}>Confirm</ButtonPrimary>}
  secondaryButton={<ButtonSecondary onPress={handleCancel}>Cancel</ButtonSecondary>}
>
  <ResponsiveLayout>
    <Box paddingY={24}>
      <Stack space={16}>{/* page content */}</Stack>
    </Box>
  </ResponsiveLayout>
</ButtonFixedFooterLayout>

ButtonLayout

Arranges a primary button, secondary button, and/or link in a standardized layout. Handles responsive stacking and alignment.

<ButtonLayout
  align="full-width"
  primaryButton={<ButtonPrimary onPress={handlePrimary}>Accept</ButtonPrimary>}
  secondaryButton={<ButtonSecondary onPress={handleSecondary}>Cancel</ButtonSecondary>}
/>

DoubleField

Places two form fields side by side with configurable width ratios ('50/50', '40/60', '60/40'). Used inside forms to group related fields horizontally.

<DoubleField layout="50/50">
  <TextField name="firstName" label="First name" />
  <TextField name="lastName" label="Last name" />
</DoubleField>

Vertical rhythm

Vertical rhythm is an important concept in web design and development. It makes the page feel consistent and visually pleasant. It is important to maintain the rhythm across the site.

Elements inside our page content can be divided in 3 main groups:

  • Container: should have a top and bottom space of 24px
  • Sections: should have a 32px space between them
  • Elements: should have a 16px separation between them

This is how a page layout could look like:

<HeaderLayout header={<Header title="Header" />} />
<ResponsiveLayout>
  <Box paddingY={24}>
    <Stack space={32}>
      <Stack space={16}>
        <Title1>Section 1</Title1>
        <Text2 regular>
          Some example text
        </Text2>
      </Stack>

      <Stack space={16}>
        <Title1>Section 2</Title1>
        <NegativeBox>
          <RowList>
            <Row1 />
            <Row2 />
            <Row3 />
          </RowList>
        </NegativeBox>
      </Stack>
    </Stack>
  </Box>
</ResponsiveLayout>

:pencil2: View this example in playroom

Doubts?

Don't hesitate to ask at Mistica Teams