5 ways to manage layout space in React
Tags: react, javascript, webdev
Published: 2021-07-22 06:34:22


All the examples below are using `styled-components` but these could easily be implemented in other `css-in-js` or even plain css. 

For example, let's say we have to build a contact form, and we already have a set of reusable components (Heading, Paragraph and Button) and now we need to create the layout. 


## 1. Parent Wrapper Component: 

This allows the Consumer/Parent component to provide the spacing. We target the `tag` of the component by plain css. 

This approach keeps the spacing in the Parent component which is a good pattern however, it can get messy if we start having lots of nested components, or just plain `div` as now we need to start targeting `ids`. 

```react

import {H1, Paragraph} from "../components/atoms/typography";
import {Button} from "../components/atoms/button";

export const ContactForm = () =>
    <FormWrapper>
        <H1>Leave us a message</H1>

        <Paragraph>Lorem ipsum dolor sit amet, consectetur adipiscing elit</Paragraph>
        <Paragraph>Maecenas nec enim sed tortor tempus maximus vel ac felis</Paragraph>
        <Paragraph>Sed euismod diam vel enim molestie iaculis</Paragraph>

        <Button>Submit</Button>
    </FormWrapper>

const FormWrapper = styled.form({
    h1: {
        marginBottom: "16px"
    },
    p: {
        marginBottom: "12px"
    },
    button: {
        marginTop: "6px"
    }
});

```

## 2. Individual Component Wrappers: 

This pattern `wraps/override/extend` the component styles. This approach is not really recommended as you have to build a lot of wrapper components. 

```react
import {H1, Paragraph} from "../components/atoms/typography";
import {Button} from "../components/atoms/button";

export const ContactForm = () =>
    <form>
        <WrapperH1>Leave us a message</WrapperH1>

        <WrapperParagraph>Lorem ipsum dolor sit amet, consectetur adipiscing elit</WrapperParagraph>
        <WrapperParagraph>Maecenas nec enim sed tortor tempus maximus vel ac felis</WrapperParagraph>
        <WrapperParagraph>Sed euismod diam vel enim molestie iaculis</WrapperParagraph>

        <WrapperButton>Submit</WrapperButton>
    </form>

/**
 * Wrapping shared components (H1 / Paragraph / Button)
 */
const WrapperH1 = styled(H1)({
    marginBottom: "16px"
})

const WrapperParagraph = styled(Paragraph)({
    marginBottom: "12px"
})

const WrapperButton = styled(Button)({
    marginTop: "16px"
})

```

## 3. Stack Component 

Stack is a component that allows us to stack elements vertically together and apply a space between them. We can have a `HorizontalStack` or `Queue` for a horizontal layout.

One of personal favorite pattern however, it can create a lot of unnecessary wrapper `div` and once you have lots nested components, then you start abusing the `Stack` component for all spacing. 

```react
import {H1, Paragraph} from "../components/atoms/typography";
import {Button} from "../components/atoms/button";
import {Stack} from "../components/atoms/stack";

export const Form = () =>
    <form>
        <Stack space={"16px"}>
            <h1>Leave us a message</h1>
            <Stack space={"12px"}>
                <Paragraph>Please send us a message we are a friendly team</Paragraph>
                <Paragraph>Please send us a message we are a friendly team</Paragraph>
                <Paragraph>Please send us a message we are a friendly team</Paragraph>
            </Stack>
            <Button>Submit</Button>
        </Stack>
    </form>

```

## 4. Component with Box Properties

The individual components (`Heading`, `Button`) that exposes the `Box` properties (`margin`, `marginTop`, `padding` ..etc).

Also sometimes we use a shorthand eg: `mb => marginBottom` `p => padding`..etc.  
 
```react
export const Form = () =>
    <form>
            <Heading mb={"10px"}>Leave us a message</Heading>
   
                <Paragraph mb={"12px"}>Please send us a message we are a friendly team</Paragraph>
                <Paragraph mb={"12px"}>Please send us a message we are a friendly team</Paragraph>
                <Paragraph mb={"12px"}>Please send us a message we are a friendly team</Paragraph>
       
            <Button mt={"16px"}>Submit</Button>
    </form>
```

## 5. Stack Component + Component with Box Properties

These two combinations allow us to have the best of both world. 

```react
export const Form = () =>
    <form>
            <Heading mb={"10px"}>Leave us a message</Heading>
            <Stack space={"12px"}>
                <Paragraph>Please send us a message we are a friendly team</Paragraph>
                <Paragraph>Please send us a message we are a friendly team</Paragraph>
                <Paragraph>Please send us a message we are a friendly team</Paragraph>
            </Stack>
            <Button mt={"16px"}>Submit</Button>
    </form>
```

## Sample implementation of Stack/Box components 

#### Stack

```react

const Stack = styled.div(props => ({
    "&>*+*": {
        marginTop: `${props.space} !important`
    }
}))
```
Popular libraries implementation: 

- https://chakra-ui.com/docs/layout/stack
- https://basarat.com/gls/vertical/
- https://github.com/seek-oss/braid-design-system/tree/master/lib/components/Stack

#### Box 

Popular libraries: 
- https://styled-system.com/
- https://chakra-ui.com
- https://github.com/seek-oss/braid-design-system/tree/master/lib/components/Box


```react

/**
 * Our custom component exposing Box properties
 */
const Heading = styled.h1(props => ({
    marginBottom: props.mb,
    marginTop: props.mt,
    paddingTop: props.pt
    paddingBottom: props.pb
}))

/**
 * Example from styled system: 
 * The space function provides all the box properties. Check their API docs for more information. 
 */
import {space} from "styled-system";

const Heading = styled.p(props => ({
    ...space({...props})
}))

```