(inline)Styling React

Contents

 

React inline style

MSS and Virtual CSS

Radium & others

React inline styles

 

var divStyle = {
  color: 'magenta',
  height: 200,
  width: 300,
  textAlign: 'center',
  display: 'table-cell',
  backgroundColor: 'pink',
  verticalAlign: 'middle',
  WebkitTransition: 'all', // note the capital 'W' here
  msTransition: 'all' // 'ms' is the only lowercase vendor prefix
};

ReactDOM.render(<div style={divStyle}>React inline styles</div>, 
    document.getElementById('container'));

React inline styles

 

class MyNotification extends React.Component {
  render() {
    // Clone the CSS styles and set the border-color CSS property.
    var styles = _.cloneDeep(this.constructor.styles);
    styles.notification.borderColor = this.props.color;
    return (
      <div style={styles.notification}>
        {this.props.prompt}
        <span style={styles.notificationHint}>{this.props.hint} />
      </div>);
  }
}

// Define the inline CSS styles for the notification here.
MyNotification.styles = {
  notification: {
    border: "5px solid green",
    padding: 10,  // Becomes "10px" when rendered.
    color: "#333"
  },
  notificationHint: {
    fontStyle: "italic"
  }
};

React.render(
  <MyNotification prompt="I ♥ modular CSS.", hint="And so should you!" color="green"/>,
  document.querySelector('#app-root'));

React inline styles

 

Problems:

CSS pseudo classes and media queries are not supported

Break existing developer tools

Creating CSS files for deployment is not that easy

React inline styles

 

class MyNotification extends React.Component {
  render() {
    return (
      <div className="notification">
        <style>    
          @media (min-width: 600px) {
            .notification {
              padding: 15px;
            }
          }
          .notification {
            border: 1px solid ${this.props.color};
            padding: 10px;
            color: #333;
          }
          /* Use nested CSS selectors - because we can! */
          .notification span {
            font-style: italic;
          }
        </style>
        {this.props.prompt}
        <span>{this.props.hint}</span>
      </div>);
  }
}

Does not work because in JSX everything between {...} is interpreted as JavaScript

React inline styles

 

Problems:

The selectors are not modular

Global CSS namespace

MSS and VirtualCSS

class MyNotification extends React.CSSComponent {
  render() {
    var styleMap = this.mountStyles`
      @media (min-width: 600px) {
        .notification {
          padding: 15px;
        }
      }
      .notification {
        border: 10px solid ${this.props.color};
        padding: 10px;
        color: #333;
      }
      /* ".notification span" is rejected by ModularCSS as it
       * contains a nested CSS selectors. Therefore, need to
       * use a new class name instead. */  
      .notification-hint {
        font-style: italic;
      }`;
    return (
      <div className={styleMap.notification}>
        {this.props.prompt}
        <span className={styleMap.notificationHint}>
          {this.props.hint}
        </span>
      </div>);
  }
}

MSS and VirtualCSS

<style>
  @media (min-width: 600px) {
    .notification_12 {
      padding: 15px;
    }
  }
  .notification_12 {
    border: 1px solid green;
    padding: 10px;
    color: #333;
  }
  .notification-hint_12 {
    font-style: italic;
  }
</style>
var styleMap = {
  notification: 'notification_12',
  notificationHint: 'notification-hint_12'
}

Resulting CSS

Resulting style object (mapp classes)

MSS and VirtualCSS

 <style> 
  /* Result from mountCSS with this.props.colour="green" */
  @media (min-width: 600px) {
    .notification_12 {
      padding: 15px;
    }
  }
  .notification_12 {
    border: 1px solid green;
    padding: 10px;
    color: #333;
  }
  .notification-hint_12 {
    font-style: italic;
  }

  /* Result from mountCSS with this.props.colour="red" */
  @media (min-width: 600px) {
    .notification_42 {
      padding: 15px;
    }
  }
  .notification_42 {
    border: 1px solid red;
    padding: 10px;
    color: #333;
  }
  .notification-hint_42 {
    font-style: italic;
  }
</style>

MSS and VirtualCSS

<style>
  /* Common styles for the colour="green" and colour="red"
   * MyNotification container */
  @media (min-width: 600px) {
    .notification_12_42_common {
      padding: 15px;
    }
  }
  .notification_12_42_common {
    border: 1px solid auto;
    padding: 10px;
    color: #333;
  }
  .notification-hint_12_42_common {
    font-style: italic;
  }
  /* Specialised styles for the MyNotification container */
  .notification_12 { border-color: green; }
  .notification_42 { border-color: red; }
</style>

MSS and VirtualCSS

// For the case of <MyNotification ... color="green">:
var styleMap = {
  notification: 'notification_12_42_common notification_12',
  notificationHint: '.notification-hint_12_42_common'
}
  // For <MyNotification ... color="green" />
  .notification_12 { border-color: green; } 
  // For <MyNotification ... color="red" /> 
  .notification_42 { border-color: red; }
  // For <MyNotification ... color="xyz" />
  [A lot of other classes to cover all possible colors go here.]

MSS and VirtualCSS

var styleMap = {
  // NOTE: The .notification_12 class name is gone. Instead the
  // border color as defined in .notification_12 is now inlined 
  // on the style object.
  notification: {
    style: { borderColor: 'green' },       // For inline styles
    className: 'notification_12_42_common' // For class names
  },
  notificationHint: {
    style: { },
    className: 'notification-hint_12_42_common'
  }
}
var StyleSheet = require('react-style')

var styles = StyleSheet.create({
    foo: {
      color: 'red',
      backgroundColor: 'white'
    }
})

React style

var React = require('react')

class HelloWorld extends React.Component{

  render() {
    var dynamicStyles = {color: this.props.color}
    return <div styles={[styles.foo, dynamicStyles]}>Hello, world!</div>
  }

}

same syntax as React Native StyleSheet

Notice that the property is styles, not style

var styles = StyleSheet.create`
  .foo {
    color: red;
    background-color: white;
  }
`

React style

var styles = StyleSheet.create({
  foo: {
    color: 'red',
    backgroundColor: 'white'
  }
})

which translates to:

React style

Problems:

No CSS selectors, pseudo-classes and CSS animation

Does not support React 0.14 :(

inline styles...

import StyleSheet from 'react-style';

const styles = StyleSheet.create({
  primary: {
    background: 'green'
  },
  warning: {
    background: 'yellow'
  },
  button: {
    padding: '1em'
  },
  // media queries
  '@media (max-width: 200px)': {
    button: {
      width: '100%'
    }
  }
});

...

<button styles={[styles.button, styles.primary]}>Confirm</button>

React Inline

class ConfirmButton extends React.Component {
  render() {
    const {className} = this.props;
    const classes = cx(styles.button, styles.primary, className);

    return <button className={classes}>Confirm</button>;
  }
}

React Inline

var {Block, Flex, InlineBlock, rgb} = require('jsxstyle');
var Theme = require('./MyTheme');

var hovered = false; // This could be dynamic

var avatar = (
  <Flex
    width={Theme.GRID_UNIT * 10}
    marginLeft="auto"
    marginRight="auto"
    alignItems="center">
    <img src="..." />
    <Block marginLeft={Theme.GRID_UNIT} 
        color={Theme.primaryColor}
        background={hovered && rgb(255, 0, 0)}>
      <InlineBlock fontWeight="bold">Username here</InlineBlock>
      subtitle here
    </Block>
  </Flex>
);

jsxstyle

Problems:

No CSS selectors, pseudo-classes and CSS animation, etc.

jsxstyle

.Avatar_1 {
    /* display flex + style properties defined 8?
}

.Avatar_2 {
    /* display block + style properties defined 8?
}

.Avatar_3 {
    /* display inline-block + style properties defined 8?
}    

External CSS - webpack loader

Radium

var Radium = require('radium');
var React = require('react');
var color = require('color');

@Radium
class Button extends React.Component {
  static propTypes = {
    kind: React.PropTypes.oneOf(['primary', 'warning']).isRequired
  };

  render() {
    return (
      <button
        style={[
          styles.base,
          styles[this.props.kind]
        ]}>
        {this.props.children}
      </button>
    );
  }
}

@Radium decorator

Radium

// You can create your style objects dynamically or share them for
// every instance of the component.
var styles = {
  base: {
    color: '#fff',

    // Adding interactive state couldn't be easier! Add a special key to your
    // style object (:hover, :focus, :active, or @media) with the additional rules.
    ':hover': {
      background: color('#0074d9').lighten(0.2).hexString()
    }
  },

  primary: {
    background: '#0074D9'
  },

  warning: {
    background: '#FF4136'
  }
};

Radium

<Button size="large" block={true}>
  Cool Button!
</Button>
var styles = {
  base: {
    background: 'blue',
    border: 0,
    borderRadius: 4,
    color: 'white',
    padding: '1.5em'
  },

  block: {
    display: 'block'
  }
};

Modifiers

// Inside render
return (
  <button
    style={[
      styles.base,
      this.props.block && styles.block
    ]}>
    {this.props.children}
  </button>
);

Radium

Other stuff:

Comparison:

(inline) styling React

By Andrei Antal

(inline) styling React

  • 1,644