React component library layered atop emotion
and @styled-system/css
. Built with Typescript.
roses
is a simple, extendable design system. It's written with typescript and builds upon an opinionated extension of the system-ui
interface, so type support is first-class.
It builds on the following libraries, so it's best to be familiar with them as well:
roses
opts for styling using @styled-system/css
For more context and alternatives, see Related Projects
TLDR:
sx
prop using @styled-system/css
.componentStyles
and variants
keys- use the themed()
HOC which will first apply any componentStyles
you've defined and add sx
and variant
props.emotion
component in the context of a styled-system
theme.roses
began as work on a design system for my own use- an extension of rebass
using styled-components
to build a library of reusable, themable components. Over time (and having never built a design system on my own) a couple pain points crept in:
Emotion as the css-in-js library: Early on I ran into some wrinkles around the styled-components' @types package. This was part of the motivation for switching to emotion
. Additionally, it is smaller and (as of early 2019) rumoured to be more performant than styled-components.
Responsive, theme-aware styles in a single prop: Collaborators were less enthusiastic about the many styled-system
props, especially when combined with the need to define Ts interfaces, account for the presence of a theme
and know which props you could use where. By electing to restrict themed styles to a single prop, the total surface area of props to maintain and remember is greatly reduced. It is also designed to be more friendly to users who aren't completely sold on css-in-js. Notably this prop is baldly stolen from theme-ui.
Define core component styles and variants on the theme: Because the system-ui
theme spec is wide open, different libraries have augmented it with their own keys. This is fine, but I wanted to introduce a bit of stability and the ability to define core component styles like those exported from rebass within the theme itself. @styled-system/css
makes this pretty straightforward:
theme.componentStyles
key which includes style rules as well as its nested variants
. The result is much less overhead in defining components that are at their hearts the composition of a div
and a few style objects.theme-ui
pattern of using theme.styles
, and a base set of these styles is included with the default theme- see baseTheme and defaultTheme which extends it.Add the package and any missing peer dependencies:
yarn add roses @styled-system/css @emotion/core @emotion/styled
# if using ts
# yarn add -D @types/styled-system__css @types/styled-system etc ...
ThemeProvider
All of your components must to be wrapped in an emotion ThemeProvider
containing a theme object. You can bring your own from the emotion-theming
package or import it directly for some extra type hints:
import { RosesTheme, defaultTheme } from "roses"
// import { ThemeProvider } from 'emotion-theming'
const theme = {
...defaultTheme,
colors: {
...defaultTheme.colors,
white: "black",
black: "white",
},
}
// RosesTheme is just a rebranded ThemeProvider.
export const App = props => {
return <RosesTheme theme={theme}>{props.everythingElse}</RosesTheme>
}
The defaultTheme
export is an extension of the theme-ui base
preset
Basic component styles can be defined under the theme componentStyles
key. Rebass apparently uses a similar, undocumented approach but keys are at the top level- this one I didn't know about.
Given a theme:
// extending the default theme..
{
...defaultTheme
breakpoints: ["780px"], // just a single breakpoint.
radii: [0, "2px", "4px", "8px"],
componentStyles: {
Rectangle: {
color: ["black", "red"] // at 1st breakpoint the text turns red for some reason.
padding: 1, // indexed to `space` key
mx: 3,
variants: {
hot: {
bg: "primary"
},
cold: { ... }
}
},
Widget: { ... }
}
}
We can make a `Rectangle using the full api:
const Rectangle = themed({
name: "Rectangle",
component: "div",
})
... Or a string shorthand - with a default base component of styled('div')({boxSizing: 'border-box'})
:
const Widget = themed("Widget")
Since this is all just emotion in the context of a system-ui theme under the covers, you can also build more complex components (whose styles probably won't belong in your theme). See the emotion
/@styled-system/css
docs for more details.
Component variant styles can be defined via a special variants
key, are accessible via the variant
prop and applied over the base styles:
theme.componentStyles.Card = {
p: 2,
m: 1,
display: "inline-block",
borderRadius: 2,
variants: {
shadow: {
boxShadow: "0 0 16px rgba(0, 0, 0, .25)",
},
},
}
// later...
<Card variant="shadow">{ /* etc */ } </Card>
sx
propheavily inspired by theme-ui
's sx
prop.
The final styles applied come from the sx
prop.
theme-ui
introduced the sx
prop. It seemed like a good idea, so roses
decided to copy it. Similar to a vanilla react component's styles
prop, sx
accepts a [SystemStyleObject
]. This is a familiar extension of the vanilla styles
api with the responsive, theme-aware values and shortcuts that styled-system/css
introduced. sx
is a functional copy of theme-ui
's version: It passes your styles on to the emotion css prop: <Box sx={myStyles} />
==
<Box css={{styledCss(myStyles)}}/>
.
roses
is heavily inspired by these projects:
styled-components
emotion
and includes built-in support for MDX.styled-system
, rebass
and theme-ui
grew.MIT for now.
Docs, PRs and Bug reports welcome. Contributors agree that this project may be relicensed in the future.