Standardizing how components are spaced in ReactNative
React Native Spacing System
Using margin and padding to control spacing between components introduces too many ways to accomplish the same goal. React Native Spacing System seeks to standardize your React Native code and increase legibility though the usage of spacing components. Types for TypeScript and Flow are both supported!
Installation
npm install react-native-spacing-system
or
yarn add react-native-spacing-system
Sentiment & Rationalization
Inspired by Nathan Curtis's Medium article Space In Design Systems and this react-spacing library by Nathan Winder (are they the same person?), I figured I'd do something similar for React Native with slight tweaks.
For the full sentiment and rationalization, please check out my Medium blog post: Enforcing Component Spacing in React & React Native.
Features
Debug
Each component supports a debug mode where their spacing is highlighted.
Import the DebugContext
and use the Provider
to toggle debug mode on and off.
import * as React from "react";
import { DebugContext } from "react-native-spacing-system";
import ComponentWithSpacingSystemComponents from "./ComponentWithSpacingSystemComponents";
const SomeComponent = () => {
return (
<DebugContext.Provider value={{ debug: booleanValue }}>
<ComponentWithSpacingSystemComponents />
</DebugContext.Provider>
);
};
You can also control debug mode of each type of spacing component as well as their border highlighting.
Expected Type (TypeScript)
type DebugContextProps = {
debug: boolean;
inset?: {
debug?: boolean;
color?: string;
};
queue?: {
debug?: boolean;
color?: string;
border?: boolean;
borderColor?: string;
};
stack?: {
debug?: boolean;
color?: string;
border?: boolean;
borderColor?: string;
};
};
Expected Type (Flow)
type DebugContextProps = {|
debug: boolean,
inset?: {|
debug?: boolean,
color?: string
|},
queue?: {|
debug?: boolean,
color?: string,
border?: boolean,
borderColor?: string
|},
stack?: {|
debug?: boolean,
color?: string,
border?: boolean,
borderColor?: string
|}
|};
Stack:
Queue:
Inset:
Stack
Stack
is a vertical spacing component, think of a pile of plates at a buffet.
Usage
Stack takes size: number
, debug?: boolean
and debugOptions?: {color?: string, border?: boolean, borderColor?: string}
.
import * as React from "react";
import { View } from 'react-native';
import { Stack } from "react-native-spacing-system";
import { BuffetPlates } from "./BuffetPlates";
import { KitchenCounter } from "./KitchenCounter";
/*
Creates a vertical space with size of 16 between
<BuffetPlates /> and <KitchenCounter /> components.
*/
const QueueExample = () => {
return (
<View>
<BuffetPlates />
<Stack size={16} />
<BuffetPlates />
<Stack size={16} />
<KitchenCounter />
</View>
);
Queue
Queue
is a horizontal spacing component, think of people queueing for that new bubbletea joint.
Usage
Queue takes size: number
, debug?: boolean
and debugOptions?: {color?: string, border?: boolean, borderColor?: string}
.
import * as React from "react";
import { View } from "react-native";
import { Queue } from "react-native-spacing-system";
import { BubbleTeaJoint } from "./BubbleTeaJoint";
import { PatientPatron } from "./PatientPatron";
/*
Creates a horizontal space with size of 16 between
<BubbleTeaJoint /> and <PatientPatron /> components.
Only works when flex direction is row.
*/
const StackExample = () => {
return (
<View style={{ flexDirection: "row" }}>
<BubbleTeaJoint />
<Queue size={16} />
<PatientPatron />
<Queue size={16} />
<PatientPatron />
</View>
);
};
Inset
Inset
is a boundary spacing component, think of adding frames around a picture (the child).
Usage
Inset takes children: ReactNode
, debug?: boolean
, debugOptions?: {color?: string}
, flex?: number
, and paddings: PaddingCombinations
.
The allowed PaddingCombinations
are as follows:
{all: number}
{horizontal: number, vertical: number}
{horizontal: number, bottom?: number, top?: number}
{vertical: number, left?: number, right?: number}
{left?: number, top?: number, right?:number, bottom: number}
import * as React from "react";
import { Inset } from "react-native-spacing-system";
import { PictureNeedingAFrame } from "./PictureNeedingAFrame";
/*
Creates a padding of size 16 around
the <PictureNeedingAFrame /> component.
*/
const InsetExample = () => {
return (
<Inset all={16}>
<PictureNeedingAFrame />
</Inset>
);
};
Factory Methods
Utilize your own space mapping with Stack
, Queue
and Inset
by passing in the space mapping into the factory method provided.
stackFactory()
queueFactory()
insetFactory()
import { stackFactory } from "react-native-spacing-system";
const spacing = {
tall: 8,
grande: 12,
venti: 16
};
export const Stack = stackFactory(spacing);
<Stack size={16}/> // Error
<Stack size="venti"/> // Works
Flow
Depending on your version of flow, you may have to pass in the type of your space object.
/* @flow */
import { stackFactory } from "react-native-spacing-system";
type SpacingKey = 'tall' | 'grande' | 'venti'
type Spacing = {[key: SpacingKey]: number}
const spacing: Spacing = {
tall: 8,
grande: 12,
venti: 16
};
export const Stack = stackFactory<Spacing>(spacing);
<Stack size={16}/> // Error
<Stack size="venti"/> // Works