Styling React Components with Radium

Anyone who is a long time reader of my blog knows I hate CSS. That’s why I am always on the lookout for something that makes it easy for me. I’ll add another wrinkle to the puzzle – I just started using Material-UI for some React components – it allows me to expend the effort on the truly important pieces of my application without worrying about a design language. I just use Googles Material Design language.

The question always on my mind is “am I doing this the right way?” Or am I merely doing it some way that works and I’ll find out this is the wrong way later on. I’ve got a pretty good stylesheet system at this point. Why would I change?

Well, for that library of components that someone else produced is one great reason. They require a style property to be added to add custom styling. Alternatively, I can add the !important tag all over the place – something that is ugly and limits the choices I make for styling. I don’t like !important – it is the left refuge in CSS.

Enter Radium – a library that still forces me to use CSS, but allows me to style components with JavaScript instead of SCSS. Here is how I converted my project to use Radium.

Step 1: Remove the style loaders from Webpack

I’ve got the following code in my webpack.config.js for handling stylesheets:

    module: {
        loaders: [
            // JavaScript and React JSX Files
            { test: /\.jsx?$/, loader: 'babel', exclude: /node_modules/ },
            { test: /\.jsx?$/, loader: 'eslint', exclude: /node_modules/ },

            // Stylesheets
            { test: /\.css$/, loader: 'style!css?sourceMap|postcss' },
            { test: /\.scss$/, loader: 'style!css?sourceMap!postcss!sass?sourceMap' },
            { test: /\.scss$/, loader: 'stylelint' }

I don’t need these any more as I am converting things over to JavaScript. I can delete the highlighted lines. In addition, there are a whole bunch of configuration elements within the webpack.config.js that I no longer need because I am not processing SASS files – those can go as well. This makes my config much leaner.

Incidentally, I also removed the externals for React and ReactDOM. This is because of a bug in Material-UI that causes errors (and malfunctioning button animations) if you include the externals. If you want to watch the bug, it’s in GitHub Issues. Unfortunately, that increases the size of my JavaScript significantly. I’m taking that temporary hit to speed development.

Step 2: Move imports to the HTML file

I have the Roboto font (and potentially other fonts) included as a @import statement in my CSS. I need to convert them to links instead. So, this:

// Roboto Font
@import url(',400,500,700');

Becomes this in the index.html:

    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <title>Grumpy Wizards</title>
    <link rel="stylesheet" href=",400,500,700">

Fortunately, I only have a couple of these, but it’s an important factor. Similarly, if you have any font definitions using @font-face, then they need to be converted to regular CSS files and loaded manually within your HTML file.

Step 3: Convert your mixins to JavaScript

I have a couple of files that have variables to hold the colors and fonts. I want to continue to use those variables, so I need to convert them to Javascript. Here is the old _colors.scss file:

$color-1: #009688;
$color-2: #A7FFEB;
$color-3: #FF5722;
$color-4: #311B92;
$color-5: #004D40;

$color-trans-1: rgba(255, 255, 255, .1);
$color-trans-2: rgba(255, 255, 255, .2);
$color-trans-3: rgba(255, 255, 255, .3);
$color-trans-4: rgba(255, 255, 255, .4);
$color-trans-5: rgba(255, 255, 255, .5);
$color-trans-6: rgba(255, 255, 255, .6);
$color-trans-7: rgba(255, 255, 255, .7);
$color-trans-8: rgba(255, 255, 255, .8);
$color-trans-9: rgba(255, 255, 255, .9);

And here is the new appStyle.js file:

let appSettings = {
    color1: '#009688',
    color2: '#A7FFEB',
    color3: '#FF5722',
    color4: '#311B92',
    color5: '#004D40',
    trans1: 'rgba(255, 255, 255, .1)',
    trans2: 'rgba(255, 255, 255, .2)',
    trans3: 'rgba(255, 255, 255, .3)',
    trans4: 'rgba(255, 255, 255, .4)',
    trans5: 'rgba(255, 255, 255, .5)',
    trans6: 'rgba(255, 255, 255, .6)',
    trans7: 'rgba(255, 255, 255, .7)',
    trans8: 'rgba(255, 255, 255, .8)',
    trans9: 'rgba(255, 255, 255, .9)',

    fonts: {
        sans: "'Roboto','Segoe UI',Frutiger,'Helvetica Neue',Arial,sans-serif"

export default appSettings;

This has all my variables in one place now and in JavaScript. There isn’t much actual difference between the two files.

Step 4: Style your initial application

Normally, you would attach Radium to your components. Unfortunately, you can’t do that initially – there is no component to which you can attach. You are rendering existing components. For those cases, you can use the following:

import { StyleRoot } from 'radium';
// ... and the rest of your includes ...

let pageStyle = {
    bottom: 0,
    left: 0,
    margin: 0,
    padding: 0,
    position: 'fixed',
    right: 0,
    top: 0

// render the page
    <StyleRoot style={pageStyle}>
        <Router history={browserHistory}>
            <Route path="/" component={Chrome}>

Note that my old code just had the Router component in it. The new code wraps the old code within a StyleRoot. That has a style attribute to set the style on it. Inevitably, this is a minimal stylesheet because you have your chrome component all set up to do the work of rendering the UI.

Step 5: Update your components for Radium support

Let’s take a look at my Chrome.jsx before adjustment – at least the important pieces of the top of the file:

import React from 'react';
import AppBar from 'material-ui/lib/app-bar';
import LeftNav from 'material-ui/lib/left-nav';


 * Provides all the chrome around the application
 * @extends React.Component
export default class Chrome extends React.Component {

And now the new code:

import Radium from 'radium';
import React from 'react';
import AppBar from 'material-ui/lib/app-bar';
import LeftNav from 'material-ui/lib/left-nav';

 * Provides all the chrome around the application
 * @extends React.Component
export default class Chrome extends React.Component {

This is something new for me – ES7 decorators. Decorators can do all sorts of wonderful things. At their core, the change the value of the class at design time – before instantiation. This means you can wrap the class in something else – in this case, the style processor that Radium brings to the table.

You will quickly discover that this won’t work on its own. Babel with the ES2015 and React plugins does not support ES7 decorators. Fortunately, there is a plugin for that:

npm install --save-dev babel-plugin-syntax-decorators

If you haven’t already done so, this is a great time to install radium as well. Don’t forget to also add syntax-decorators to your .babelrc file:

    "presets": [ "es2015", "react" ],
    "plugins": [

You should be able to build the project now – for the first time in a while.

Step 6: Add Style to your components

I was creating an SCSS file for each component in my prior method. Now I need to convert the stylesheet to JavaScript. Here is the Chrome.scss file that I am going to convert:

@import 'colors';
@import 'fonts';

.chrome {
    display: flex;
    flex-flow: column nowrap;
    height: 100%;
    width: 100%;

    &--content {
        flex-grow: 1;

    > footer {
        background-color: $color-5;
        display: block;
        text-align: center;

        > h6 {
            color: $color-trans-8;
            font: 0.8rem $sans-fontstack;
            margin: 0.5rem 0;

It wasn’t that big. In addition, I want to take care of the styling for my app bar, so I’ll do that at the same time. With apologies for the long listing, I’ve included the new render() method:

    render() {

        // Define Event Handlers
        let onMenuIconTap = (event) => { return this.onLeftNavDisplay(event, !this.state.leftNavIsOpen); };
        let onRequestChange = (open) => { return this.onLeftNavDisplay(null, open); };

        // Components
        let leftNav = (
            <LeftNav docked={false} onRequestChange={onRequestChange} open={this.state.leftNavIsOpen}>

        // Style
        let styles = {
            chrome: {
                display: 'flex',
                flexFlow: 'column nowrap',
                height: '100%',
                width: '100%'
            appbar: {
                backgroundColor: appStyle.color1
            footer: {
                backgroundColor: appStyle.color5,
                display: 'block',
                textAlign: 'center'
            footertext: {
                color: appStyle.trans8,
                font: `0.8rem ${appStyle.fonts.sans}`,
                margin: '0.5rem 0'

        let jsx = (
            <div style={}>
                    <AppBar style={styles.appbar} onLeftIconButtonTouchTap={onMenuIconTap} title={'Grumpy Wizards'}/>
                <section style={{ flexGrow: 1 }}>
                <footer style={styles.footer}>
                    <h6 style={styles.footertext}>{'Copyright \u00a9 2016 Adrian Hall'}</h6>


        return logger.exit('render', jsx);

The first block is my stylesheet – converted into a JavaScript object. This means I can represent that object any way I want – as long as it resolves to an object. For example, I might use Object.assign to merge styles together, store it in a library and import the styles, do calculations, call functions, or anything else I want to do. The style properties need to be converted to camelCase – instead of flex-flow, use flexFlow.

The second part is in the JSX. I attach a style attribute where I need to add style. Since I’ve created a stylesheet as a set of nested objects, they can get referenced using the standard Javascript object dot notation. Note that I don’t have to use the object notation – simple things, like the flex-grow style property at line 106, can just be included.

Wrap Up

There are some things that are different than just using the style attribute in your HTML code though. Normally, attributes like ‘:hover’ and media queries are not available within the style attribute – that is reserved for the CSS stylesheet. You can specify both browser states like :hover and media queries using Radium, so that limitation of the style attribute does not exist.

There is a lot to recommend this style mechanism. My components are now self-contained – no extra files. I’m just using pure JavaScript. That means, for example, I can distribute components with styling already built in. I don’t need to wonder if they are using webpack or browserify and what format I need to present the stylesheet. Sure, the designers in your life are likely to hate it, but I find the code cleaner. I’m really enjoying the discovery of Radium.

Oh – and don’t forget to remove all the loaders and linters dealing with style from your package.json! My code, as always, is in my GitHub Repository.