DEV Community

ahpoi
ahpoi

Posted on

5 ways to manage layout space in React

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.


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"
    }
});

Enter fullscreen mode Exit fullscreen mode

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.

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"
})

Enter fullscreen mode Exit fullscreen mode

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.

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>

Enter fullscreen mode Exit fullscreen mode

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.

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>
Enter fullscreen mode Exit fullscreen mode

5. Stack Component + Component with Box Properties

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

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>
Enter fullscreen mode Exit fullscreen mode

Sample implementation of Stack/Box components

Stack


const Stack = styled.div(props => ({
    "&>*+*": {
        marginTop: `${props.space} !important`
    }
}))
Enter fullscreen mode Exit fullscreen mode

Popular libraries implementation:

Box

Popular libraries:


/**
 * 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})
}))

Enter fullscreen mode Exit fullscreen mode

Top comments (0)