⚠ WIP
This page documents changes proposed in the RFC for V1, and therefore prone to bugs/sudden API changes. Please use with caution.
raam (estonian) ˈrɑːm n. frame.
Beautifully boring cosmetic-free primitives for structure and layout.
Getting Started
Choose your own boring adventure:
- Mixins - complimented by Recipes (recommended)
- Components
Mixins
JavaScript style functions to quickly roll-your-own resilient layout components (not just for React.js).
Installation
npm i --save raam
or
yarn add raam
Flexbox
At the time of writing, "flex-gap
" is only supported by newer versions of Edge, Chrome and Firefox.
It's often the case to approach new CSS features with a @supports
query, but unfortunately, this is not an option we can take advantage of.
flexbox()
aims to address this "gap
" in support, with a plain CSS polyfill powered by custom properties.
At the root of your component, flexbox({ ...options })
is called with your specified options.
This returns functional styles for:
.parent()
.child()
Item 1Item 2Item 3
How It Works
Under-the-hood, raam replaces gap with a set of custom properties to control parent and child margins. These are toggled off (back to initial
) depending on the requirements of specific flex properties; a technique heavily inspired by David Khourshid's "prop-and-lock" technique.
For example, when
flexWrap
isnowrap
(i.e. 'stack'-based layouts) the negative offset margin on the flex parent is toggled off.
In nowrap
based layouts, margins are used in a single direction excluding the first-child.
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.
Options
Name | Type | Default |
---|---|---|
gap | ResponsiveStyleValue | 1rem |
variant | wrap | hStack | vStack | hStack |
alignContent | ResponsiveStyleValue | |
alignItems | ResponsiveStyleValue | |
flexDirection | ResponsiveStyleValue | row |
flexWrap | ResponsiveStyleValue | nowrap |
justifyContent | ResponsiveStyleValue | |
justifyItems | ResponsiveStyleValue |
.child()
Name | Type | Default | Description |
---|---|---|---|
index * | number | Used in place of :*-child pseudo selectors | |
flex | ResponsiveStyleValue | 0 0 auto | |
flexBasis | ResponsiveStyleValue | ||
flexGrow | ResponsiveStyleValue | ||
flexShrink | ResponsiveStyleValue |
Types
ResponsiveStyleValue
Accepts either a single
value
for the style property's value, or an array ofvalue
or{ "@media query": value }
.For example, the following options are acceptable for
gap
:gap: "2rem"
gap: { initial: "2rem", "@media (min-width: 40em)": "1rem" }
Components
If rolling-your-own components hasn't got you hooked, you may be interested in a pre-built option.
Currently offering solutions for:
- Theme UI -
@raam/theme-ui
Migrating from an earlier version of raam?
Prior to version 1, raam exported a set of individual Theme-UI components. These have now moved to into a single
<Flex />
component with variants:
<Stack {...options} />
=><Flex variant="vStack" {...options} />
<Inline {...options} />
=><Flex variant="hStack" sx={{ overflowX: "auto" }} {...options} />
<Wrap {...options} />
=><Flex variant="wrap" {...options} />
Installation
npm i --save theme-ui @raam/theme-ui
or
yarn add theme-ui @raam/theme-ui
Flexbox
A flexbox
-based layout primitive that aims to address the gap
.
Props
Props for each
flexbox()
option.gap
also accepts a key fromtheme.space
(as a string or number), but if that's not found it'll render the provided string (e.g.em
orrem
) or number as apx
value.
as
: change the HTML element rendered (via Theme UI)raam makes an opinionated choice on how to render a component's children based on the element provided:
as
children
renderedas
div
(default)div
ol
li
(withlist-style-type
reset)ul
li
(withlist-style-type
reset)span
span
p
span
h1
-h6
span
sx
: apply themed styles to the component (via Theme UI).
Recipes
Box
Each recipe assumes you have a Box
component defined for base styles. In this case, an sx
prop is used to pass themed style values (like Theme UI).
You don't necessarily need to follow this approach, feel free to make it your own.
Wrap
A flex-based layout that renders and 'wraps' children inline, spaced
by the defined gap
.
Customisation
Let's make it more interesting, let's say we want the last item to fill the remaining available space.
When the index
indicates the "last child" (the array's length - 1),
we'll pass the additional flexGrow
parameter to the .child
and set it to 2
.
With the gap
prop, we also have the ability to create responsive
styles. In this example, we'll reduce the gap size on larger screens.
Stack
Popularised by Seek's "Braid", the "Stack" is a flex-based layout that renders children in a single column or row, spaced by the defined gap
.
VStack
Renders items in a single column.
"Hold up, why don't you just…"
- "…use
display: grid;
"
Grid is fantastic for page layouts, but has its caveats for a 'simple'Stack
:
- It doesn't behave reliably for all elements (e.g.
fieldset
)- Can lead to 'blow out'.
HStack
The default setting of flexbox
; the HStack
renders items in a single row and makes no assumptions on your overflow
.
Inline
If you'd rather let hStack
items scroll elegantly in a single line, add an overflowX
declaration alongside your .child()
styles.
or with some more chaotic values…
Combo
When combining flexbox()
styles, split them across different elements to avoid conflicts.
Let's take a look at a more real-world example; a "tag"-list at the bottom of an article:
- Padding is added to the
Stack
, not theWrap
directly.
Acknowledgements
Without these projects/people, this project wouldn't exist…