react-c

0.2.0 • Public • Published

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 and final parameters through c(...), with the value of this.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

  1. Your component's stylesheet should have exactly one top level selector: the one generated by cRoot

    Example:

    /* Good */
    .MyComponent {
      /* ... */
    }
     
    /* Bad */
    .OtherComponent {
      /* ... */
    }
     
    /* Bad */
    #some-id {
      /* ... */
    }
  2. 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. Set displayName manually in this case.
  • You're applying the ES7 decorator after another decorator which modifies component.name. This can happen if it returns a class 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.

Package Sidebar

Install

npm i react-c

Weekly Downloads

31

Version

0.2.0

License

MIT

Last publish

Collaborators

  • jamesknelson