<Box> and <BoxContainer> are simple atomic layout components with a declarative React API that support the NDS Grid Guidelines.

Used to

  1. Codify standardized component and page level layouts at NerdWallet.
  2. Bridge the gap between Design and Eng.
  3. Obviate need for much of the custom media query logic previously required.

See the NDS Grid Guidelines for a more comprehensive picture on the rationale behind Box at NerdWallet, as well as descriptions of the difference between adaptive and fluid layouts, etc.

Usage

import Box, { BoxContainer } from '@nerdwallet/react-box';

Loading examples...

<BoxContainer>

children

node

Required

<Box>

children

node

Default

null

className

string

Default

null

component

elementType

React component or HTML element to use instead of div.

Default

'div'

isReactNative

boolean

Boolean flag to indicate if a stylesheet should be created for React Native.

Default

false

notWide

Object

Object to indicate the behavior of the flex container in the narrower (>=768) breakpoint.

{

/**

Remove the horizontal padding around the left, right, or both sides of Box. Intended to be used on the outer columns of the Grid (reason for the name of the prop).

*/

noGutter: 'left' | 'right' | 'both'

/**

Align items (symmetric to flexbox) along the cross-axis.

*/

direction: string

/**

Arrange the boxes based on cross and main axis within the narrower breakpoint. Behaves like the justify-content CSS property and supports the standard.

*/

justify: 'center' | 'flex-end' | 'flex-start' | 'space-around' | 'space-between' | 'space-evenly' | 'start'

/**

Number to indicate how many columns to fill the flex container in the smaller (<= 767) breakpoint. If this is set with a prop other than the default, we apply display-flex.

*/

columns: 'auto' | 0 | 1 | 2 | 3 | 4

/**

Flag to indicate if flexbox items should wrap or nowrap. Default is wrap.

*/

wrap: 'wrap' | 'nowrap'
}

Default

{
  columns: 'auto',
  direction: 'row',
  display: 'flex',
  noGutter: null,
  justify: 'flex-start',
  wrap: 'wrap',
}

wide

Object

Object to indicate the behavior of the the flex container in the wider (>=768) breakpoint.

{

/**

Remove the horizontal padding around the left, right, or both sides of Box. Intended to be used on the outer columns of the Grid (reason for the name of the prop).

*/

noGutter: 'left' | 'right' | 'both'

/**

Align items (symmetric to flexbox) along the cross-axis.

*/

direction: string

/**

Arrange the boxes based on cross and main axis within the narrower breakpoint. Behaves like the justify-content CSS property and supports the standard.

*/

justify: 'center' | 'flex-end' | 'flex-start' | 'space-around' | 'space-between' | 'space-evenly' | 'start'

/**

Number to indicate how many columns to fill the flex container in the wider (>= 768) breakpoint. If this is set with a prop other than the default, we apply display-flex.

*/

columns: 'auto' | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12

/**

Flag to indicate if flexbox items should wrap or nowrap. Default is wrap.

*/

wrap: 'wrap' | 'nowrap'
}

Default

{
  columns: 'auto',
  direction: 'row',
  display: 'flex',
  noGutter: null,
  justify: 'flex-start',
  wrap: 'wrap',
}

Within <BoxContainer>

<Box> is normally used within the context of a <BoxContainer>, which applies a constrained max-width and outer side margins, specified by the NDS Grid Guidelines:

<BoxContainer>
<Box notWide={{ columns: 2 }} wide={{ columns: 3 }}>
<div style={appComponent}>Fluid Inner</div>
</Box>
<Box notWide={{ columns: 2 }} wide={{ columns: 3 }}>
<div style={appComponent}>Fluid Inner</div>
</Box>
<Box notWide={{ columns: 0 }} wide={{ columns: 3 }}>
<div style={appComponent}>Fluid Inner</div>
</Box>
<Box notWide={{ columns: 0 }} wide={{ columns: 3 }}>
<div style={appComponent}>Fluid Inner</div>
</Box>
</BoxContainer>

This should generally be the use case for adopting Box in your flow.

As a replacement for <ContentContainer />

<BoxContainer> should be a drop in replacement for the older <ContentContainer /> component. Just compose children as you would've previously:

<BoxContainer>
<p>Auto margin content that adheres to a specific max-width.</p>
</BoxContainer>

Known Consumers

The following repos have adopted @nerdwallet/react-box to implement some of their layouts:

<Box> Design

Read more about the design of Box?

Box Design

<Box> is an atomic layout component. Along with breakpoints, and guidelines, it's one of the building blocks of the NDS grid system. This doc covers some of the original high level rationale around the implementation and design.

For more info on layout guidelines in general, see the NDS Grid Guidelines.

Features and Functionality

  • Designed for future-forward layouts
  • Internal media queries mapping to @breakpoint-wide from base-styles
  • Declarative, React API to offer familiar ergonomics
  • Maintained symmetry with pre-existing flexbox APIs to minimize overhead, confusion of learning a new syntax and ease adoption

API

Iterations

We iterated (and are still iterating) on various different APIs for <Box>. Here are some older iterations:

// Declaratively capturing the container / item
<Grid row={6}>
<GridItem><A /><GridItem>
<GridItem><B /></GridItem>
</Grid>
// Passing an entire layout object into the GridItem
<GridItem layout={customLayoutObject}>
<App />
</GridItem>
// Desktop vs. mobile sizing
<GridItem desktop={8} mobile={3}>
<A />
</GridItem>
<GridItem desktop={4} hideOn="mobile">
<A />
</GridItem>
// As a Grid
<Box>
<Box distribute="space-between" wide={60%} size={2}>
<A />
</Box>
<Box wide={6} size={2}>
<B />
</Box>
</Box>
// outer Box, composing inner Boxes which serve as containers that span a specified column width
<Box>
<Box size={4} wide={12}>
<div className={styles.custom}>This will span 100% of the container (12 columns).</div>
</Box>
<Box size={2} wide={6}>
<div className={styles.custom}>This will span 50% of the container (6 columns).</div>
</Box>
<Box size={2} wide={6}>
<div className={styles.custom}>This will span 50% of the container (6 columns).</div>
</Box>
</Box>

See the README.md and the Storybook examples for the current iteration.

Adoption

Right now there are numerous breakpoints all through the product; it will take some time for teams to converge on a single breakpoint. As such <Box> will most likely be a gradual adoption as teams gain resources and prioritization to build their layouts in line with the new grid system.

Maintainers

This component was created by Piper Chester.

See Also