├── .gitignore
├── README.md
├── example
├── Button.js
├── app.js
├── index.html
└── package.json
├── index.js
├── package.json
└── prod.js
/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules
2 | bundle.js
3 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Keep your CSS with your React component definitions
2 |
3 | I've recently been creating a large client side JavaScript application with React and Flux. As of right now the app has 35 basic React components, about 10 of which have their own custom CSS. I was in the bad habit of simply appending CSS for new components to a global stylesheet as I built them, but I knew this approach wouldn't be maintainable in the longer term.
4 |
5 | What I really wanted was to keep my CSS in the same file as my component definition so I wouldn't need to go fishing around in my global stylesheet every time I wanted to make a change. This would also mean that CSS would only be included if the component was require'd in the project somewhere. Removing a component from a project would remove its corresponding CSS automatically - no need to remember to remove it from the global stylesheet.
6 |
7 | Enough background - here's what it looks like:
8 |
9 | var React = require('react');
10 | var Button = React.createClass({
11 | render: function() {
12 | return (
13 |
My Button
14 | )
15 | }
16 | });
17 |
18 | require('react-styl')(`
19 | .btn {
20 | display: inline-block;
21 | background: blue;
22 | padding: 5px;
23 | }
24 | .btn:hover {
25 | background: red;
26 | }
27 | `)
28 |
29 | module.exports = Button;
30 |
31 | You'll notice we use the convenience of ES6 multiline strings (`) so we can write css directly in our component JS files without any funky quoting. You'll need to run this through an ES6->ES5 converter (such as es6ify) for your resulting code to be cross-browser compatible.
32 |
33 | Now, to render the CSS on the client, simply add a line to your bootstrap file. Something like:
34 |
35 | React.render(, document.getElementById('react'));
36 | require('react-styl').addStylesheet();
37 |
38 | That's it! But how does it work? Here's the (slimmed down) code for the react-styl module:
39 |
40 | var _styles = "";
41 |
42 | module.exports = function(styles) {
43 | _styles += styles;
44 | }
45 |
46 | module.exports.addStylesheet = function() {
47 | var style = document.createElement('style');
48 | style.type = 'text/css';
49 | style.appendChild(document.createTextNode(_styles));
50 | document.head.appendChild(style);
51 | }
52 |
53 | Every call to require('react-styl')('css string') appends the given css to the _styles variable. Since each component is cached after being require'd somewhere in your project, component CSS is only appended to the _styles variable once, even though your component may be require'd many times throughout your project. Then it's simply a case of appending the resulting CSS to a style tag and you're done.
54 |
55 | If you want to use a CSS preprocessor, like styl, simply edit your addStylesheet function to process the css before it gets added to the style tag. Something like this:
56 |
57 | var styl = require('styl');
58 | module.exports.addStylesheet = function() {
59 | var css = styl(_styles).toString(),
60 | style = document.createElement('style');
61 |
62 | style.type = 'text/css';
63 | style.appendChild(document.createTextNode(css));
64 |
65 | document.head.appendChild(style);
66 | }
67 |
68 | And that's the crux of it! Now you can keep your component CSS and JS in the same file, easing development and maintainability.
69 |
70 | By wrapping your CSS code with annotations, you can strip them out when building for production, instead serving your CSS from a static file.
71 |
72 | To try the example, clone this repo, change to the example directory, run npm install then npm build.
73 |
--------------------------------------------------------------------------------
/example/Button.js:
--------------------------------------------------------------------------------
1 | var React = require('react');
2 |
3 | var Button = React.createClass({
4 | render: function() {
5 | return (
6 |