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"
}
});
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"
})
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>
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>
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>
Sample implementation of Stack/Box components
Stack
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
/**
* 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})
}))
Top comments (0)