raam (estonian) ˈrɑːm n. frame.

Beautifully boring cosmetic-free React.js components for structure and layout.

Use raam's layout primitives to build resilient theme-driven designs fast.


Components

  1. Wrap
  2. Inline
  3. Stack
  4. Feature Candidates

Wrap

A Flex-based layout that renders and 'wraps' children inline spaced by the defined gap.

Here gap is accessing the value from theme.space[3].

// import { Wrap } from "raam";
// import { Box } from "your-components";

<Wrap gap={3}>
  {Array.from({ length: 32 }).map((item, i) => (
    <Box
      key={i}
      sx={{
        width: "2rem",
        height: "2rem",
        backgroundColor: "primary",
        filter: i > 0 && `hue-rotate(${i * 2}deg)`,
      }}
    />
  ))}
</Wrap>

Responsive

As the gap prop is powered by Styled System, you have the ability to create responsive styles.

Here gap is accessing the value from theme.space[3], then theme.space[4] at breakpoint[1] etc.

// import { Wrap } from "raam";
// import { Box } from "your-components";

<Wrap gap={[2, 3, 4]}>
  {Array.from({ length: 32 }).map((item, i) => (
    <Box
      key={i}
      sx={{
        width: "2rem",
        height: "2rem",
        backgroundColor: "primary",
        filter: i > 0 && `hue-rotate(${i * 2}deg)`,
      }}
    />
  ))}
</Wrap>

Example

Let's take a look at a more real-world example; a "tag"-list at the bottom of an article:

// import { Stack, Wrap } from "raam";
// import { Box, Heading, Link } from "your-components";

<Stack padding={3}>
  <Heading as="h2">Tags</Heading>

  <Wrap as="ul">
    {Array.from({ length: 8 }, (v, k) => k + 1).map(item => (
      <Link key={item} href={`#list-item-${item}`}>
        Tag {item}
      </Link>
    ))}
  </Wrap>
</Stack>

Inline

If you'd rather let items flow elegantly in a single line, make use of Inline.

Scroll behaviour can be removed with an overflow: 'hidden'.

// import { Inline } from "raam";
// import { Box } from "your-components";

<Inline gap={3}>
  {Array.from({ length: 32 }).map((item, i) => (
    <Box
      key={i}
      sx={{
        width: "2rem",
        height: "2rem",
        backgroundColor: "primary",
        filter: i > 0 && `hue-rotate(${i * 2}deg)`,
      }}
    />
  ))}
</Inline>

or with some more chaotic values…

// import { Inline } from "raam";
// import { Box } from "your-components";

() => {
  const size = () => `${Math.floor(Math.random() * 4) + 1}rem`;

  return (
    <Inline gap={3} flexWrap="nowrap">
      {Array.from({ length: 32 }).map((item, i) => (
        <Box
          key={i}
          sx={{
            width: size(),
            height: size(),
            backgroundColor: "primary",
            filter: i > 0 && `hue-rotate(${i * 2}deg)`,
          }}
        />
      ))}
    </Inline>
  );
};

Stack

Popularised by Seek's "Braid", a Flex-based layout that renders children on top of each other, spaced by the defined gap.

// import { Stack } from "raam";
// import { Box } from "your-components";

<Stack gap={3}>
  {Array.from({ length: 4 }).map((item, i) => (
    <Box key={i} sx={{ height: "2rem", backgroundColor: "primary" }} />
  ))}
</Stack>

"Hold up, why don't you just…"

Flex

A display: flex;-based layout primitive that aims to address the gap.

Stack, Wrap and Inline are all effectively "presets" of Flex. Don't like that? It's OK, you can use Flex directly without opinionated defaults.

Caveats

TL;DR: Mind the Gap

At the time of raam's release, usage of gap in flex-based layouts is only supported by Firefox. To address this shortcoming, fallbacks are used:

  1. In nowrap based layouts, margins are used in a single direction excluding the first-child.
  2. In wrap based layouts, negative margins are used on the outer component to counteract margins inside.
    It will not affect adjacent margins, but you will experience issues if you try to adjust it directly - instead consider wrapping the element.

Feature Candidates

Article

A layout primitive to control vertical rhythm and flow for typographic content.


Getting Started

Installation

WIP

This project is in development and comes with caveats:

  1. Only supports React.js apps with Emotion or Theme UI pre-installed (for the time being).
  2. Prone to regular unannounced changes.

npm i raam --save
or
yarn add raam

Configuration

All components use a shared set of props:

Acknowledgements

Without these projects/people, this project wouldn't exist…