react-c
v0.2.0
Published
Provides structure to your component's CSS by helping you write semantic class names.
Downloads
71
Maintainers
Readme
react-c
react-c provides structure to your component's CSS. To do so, it provides two methods to help you write properly-scoped CSS classes, an ES7 decorator to specify a namespace, and guidelines for writing clean CSS with LESS/SCSS.
With react-c, writing clean CSS for React is so simple that you no longer have any excuse to not do it.
Example
The best way to understand react-c is to see it in action, so let's have a look how it is used in a slightly simplified copy of numbat-ui's Paper component:
import React from "react"
import c from "react-c"
@c("nui")
class Paper extends React.Component {
static propTypes = {
rounded: React.PropTypes.bool,
}
static defaultProps = {
rounded: true,
}
render() {
return (
<div className={this.cRoot({rounded: this.props.rounded})}>
<div className={this.c('inner')}>
{this.props.children}
</div>
</div>
)
}
}
Rendering a Paper
component with the rounded
property set to true
will produce the following:
<div class="nui-Paper nui-Paper-rounded">
<div class="nui-Paper-inner">
...
</div>
</div>
This output in turn is styled using LESS or SCSS, using the &-
selector to prevent Carpal Tunnel Syndrome:
.nui-Paper {
//...
&-rounded {
//...
}
&-inner {
//...
}
&-rounded &-inner {
//...
}
}
Usage
1. Install with NPM:
npm install react-c --save
2. Import the module:
import c from 'react-c' // ES6
or
var c = require('react-c') // CommonJS
3. Add react-c to your component:
You have two options to do this. If you're building modules by extending React.Component
, I recommend using ES7 decorators:
@c("ns")
class MyComponent extends React.Component {
...
}
Otherwise, just pass your components to the c(prefix)
manually:
var MyComponent = React.createClass({
...
})
c("ns")(MyComponent)
4. Add classes to your components using c
and cRoot
c(...)
Example output:
'ns-MyComponent-a ns-MyComponent-b'
Generates a
className
string using the classnames module, but with all classes prefixed with the component's name and specified prefix.cRoot(initial, final)
Example output:
'ns-MyComponent ns-MyComponent-initial this-prop-className ns-MyComponent-final'
Returns the component name, followed by the result of passing
initial
andfinal
parameters throughc(...)
, with the value ofthis.props.className
(if any) sandwiched between.As browsers give the later classes higher priority, it is possible to give your classes higher or lower priority than those added from
this.props.className
.This function is generally used on the root component in your
render()
function, thus the name. You probably shouldn't use it more than once.
5. Write your LESS/SASS following the react-c guidelines
Your component's stylesheet should have exactly one top level selector: the one generated by
cRoot
Example:
/* Good */ .MyComponent { /* ... */ } /* Bad */ .OtherComponent { /* ... */ } /* Bad */ #some-id { /* ... */ }
All other selectors (and parts of selectors) should start with
&-
Example:
.MyComponent { /* good */ &-inner &-input { /* ... */ } /* bad */ &-inner input { /* ... */ } /* good */ &-other-component { /* ... */ } /* bad */ .OtherComponent { /* ... */ } }
These two rules have a number of flow-on effects:
- You cannot select elements based on tag names or ids. Instead, select child elements by adding a class to them with
c
. - You cannot directly apply styles to child components. Instead, pass in class names generated with
c
to child components, and style them instead.
The result of this is that it is incredibly easy to reason about what styles are applied, and where they come from. As a bonus, "inspect element" in your favourite web-browser will immediately show where styles originate.
In order to make these guidelines easier to follow, I recommend placing your LESS/SCSS files in the same directory as your jsx, with one file per component. For an example of a project organised this way, see numbat-ui.
FAQ
How do c
and cRoot
know what my class is called?
react-c uses component.prototype.displayName || component.name
to decide what your component is called. This can break down in the following cases:
- You're using React.createClass, but not using JSX. This is because
component.prototype.displayName
is set by the JSX compiler. SetdisplayName
manually in this case. - You're applying the ES7 decorator after another decorator which modifies
component.name
. This can happen if it returns aclass
which extends the original, for example.
Is react-c BEM compliant?
No.
BEM goes further than react-c, by distinguishing between classes for modifiers and elements.
For a BEM-based project, use something like react-bem.
Why should I use react-c over BEM-based modules like react-bem?
Given most React components are very small and have limited scope, BEM is overkill in this context. If you find your components are getting big enough that you think it might make sense to distinguish between elements and modifiers (like BEM), you probably instead should focus on factoring your components into smaller parts.
Related Projects
react-c is part of react-base - a collection of Higher-Order Components to make your life easier.
react-base (and react-c) were extracted from numbat-ui - a collection of UI components for React based on Google's Material Design.