When we first began building Artsy's Design System we wanted something that could serve as a good foundation for low and high-level components, while also being intuitive for our development team. Some of us were facinated with functional css but having worked with React, styled-components and various CSS-in-JS libraries, we wanted something that was less vanilla CSS than React props, something that we could easly use with TypeScript. Pretty quickly we stumbled upon a brilliant library by Brent Jackson called styled-system that combined all of these things. Fans of Tailwind CSS should feel right at home here.
Styled System bills itself as a way to "build custom UI components with constraint-based style props based on scales defined in your theme." There's a lot here, but in short what it means is: Take some values defined in a theme, define some function mixins to consume values in the theme, and map the output to React component props.
For example:
What we're doing is creating a new primative component called Box
that
mixes-in a space
function from styled-system
. This function then "decorates"
the component with a handful of props
that then read in the theme and allow the develper quick ways to access the
values. One of those props is p
(shorthand for padding
), and by passing in
2
we're saying "look at theme.space
, find the key for p={2}
and return the
value" - which equals 20px
. And with TypeScript, we get really nice
intellisense as well as type-checking of the values passed into the prop.
At scale and across a big dev team, this works well after the basics are understood. Our UI becomes like lego blocks, where the theme ("constraints") defines the shape of the pieces that are available. Design drift no more.
A fuller example of Box
from the Palette codebase:
You can see that not only is there the space
mixin, but also background
and
position
and others, each providing their own set of props that we can then tap
into directly on the Box
component.
Similarly, lets define a Flex
component:
Now with this defined, we can then create something more complex:
Under the hood we're laying out the component into a container that displays a
message and, if isPriority
is set, optionally shows an icon. The contents are
distributed evenly across the containing space thanks to the justifyContent
prop being set to space-between
on the <Flex>
component container. No
long-hand css required, and everything is type-checked. In fact, unless you're
building something unconventionally complex, you should never need to use
vanilla css or conventional styled components again; everything you could need
is defined within our primatives in Palette.
As styled-system can do much more, check out the API docs for a full list of functionality.