classier-react
automatically lets you access your stylesheet utilty classes as props on Box and can generate react components for the elements in your CSS modules.
const Button = props => (
<Box rounded bg="blue" py={2} px={4} {...props} is="button" />
)
We know awesome stylesheets are out there for browsers, its just awkward to make use of them when working with JSX. Cramming everything into that className
string feels wrong and our brains have to remember how the styles were written.
classier-react
solves the problem by simply translating from props to CSS classes. Its not generating code and its not pushing the browser to its limits.
Think of it like classnames
with superpowers.
npm install classier-react
You'll have to have configured your app with a stylesheet to use the tool. Webpack can have a style loader or you might even include your favorite library straight in the <head>
tag.
See the TailwindCSS Recipe to add the classes used in the examples to a create-react-app
app.
Note: This example uses utility classes from TailwindCSS.
You'll define your presentational components:
import { Box, Comp } from 'classier-react'
const Card = props => (
<Box
rounded
shadow={['md', { hover: 'lg' }]}
maxW="sm"
overflow="hidden"
{...props}
/>
)
const CardHeroImage = ({ src, ...rest }) => (
<Comp w="full" border={[1, 'black']} {...rest}>
<img src={src} />
</Comp>
)
const CardTitle = ({ size = 5, ...rest }) => (
<Box is={'h' + size} text="xl" font="bold" mb={2} {...rest} />
)
const CardBody = props => <Box px={6} py={4} {...props} />
And then consume them as usual:
<Card maxW="md">
<CardHeroImage src={image} border={false} />
<CardTitle size={4}>So Classy</CardTitle>
<CardBody font="semibold">Lorem ipsum...</CardBody>
</Card>
Under the hood, classier-react
assumes any unknown props are declared as modifiers in your stylesheet. Props are translated to these declarations according to simple rules:
-
Any props with an explicit
false
value are omitted -
prop values are appended to their names
-
each value of an array will generate its own prop class
-
each key of an object will generate a variant prop class
-
-
camelCase words become kebab-cased
-
Sentence-casing is preserved but not added
<Comp />
only injects the props it merges, it can't make sure they are rendered. If you're wrapping or writing a component, you'll want to to pass any props you don't use or specifically ignore onward to what is rendered.
An unsafe, but easy, way to this is to make use of the spread operator:
const MyComponent = ({ option, ...rest }) => <Box {...rest} />
classier-react
supports using CSS Modules through dynamic object keys:
import styles from './styles.css'
...
<Box {...{
[styles.fontSize]: 'md'
}} {...rest} />
You can also use cx
and pass around the resulting string yourself:
import { cx } from 'classier-react'
...
const containerClassName = cx(props.styled)
import { Box, Text, Comp, cx, configure } from 'classier-react'
Renders a tag with its unknown props translated to CSS classes.
- is: the tag to render as (default: 'div')
Renders a span with all its props translated to CSS classes.
A HOC for injecting or "composing" style props. Merges its style
, className
, and the rest of its props as classes into the props of a child component.
Transform the passed props into a className string. Called by Box and Comp.
Lets you change the global behavior of cx
-
kebabCase - Transform names and values from camelCase. Reverses
style-loader
. (default: true) -
keepSentence - When kebabing, lower-case everything but the first word (default: true)
-
join.words - the string to insert between the words in a camelCase identifier (default: '-')
-
join.value - the string used to separate a value (default: '-')
-
join.variant - the string used to separate a variant from its modifier(default: ':')
-
join.block - the string to insert before nested blocks or elements (default: '-')
-
join.modifier - the string used to separate the block identifier from the modifier name (default: '-')