Skip to content

Reusable and adaptable components without external css dependency.

Notifications You must be signed in to change notification settings

realvalkyrie/react-inline-style

 
 

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

4 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

React Inline Style

npm version

About

Inline styles are great for distributed react components via npm or just reusable components in general. Having everything you need to run the component requirable within javascript improves its usability greatly. Having to look for an external css file in the node_modules folder sucks.

However using inline styles, we quickly run into multiple problems. The main one being the missing possibility to adjust styles from outside the component but also the missing pseudo classes (mainly :hover) and media queries can sometimes be really handy and are duly missed. And while these last two can be substituted with javascript, there are situations where global css is needed (think: HTML API responses, 3rd party plugins etc).

There is a lot of discussion going on about these problems and the missing modularity of css in general.
Check out @Vjeux on CSS in JS as a good starting point.

React Inline Style focuses on reusable, self contained components, that dont require any external css file but are still adaptable and styleable by their owner / end user / developer.

Features

React Inline Style provides a practical solution for the following problems:

  1. Define ALL styles in JavaScript within the component/module.
  2. Owner component can influence/override its child components styles.
  3. Define global css rules and media-queries also from within a component.
  4. Easy substitution for conditional class definitions like :hover and :pressed.

What React Inline Style does not provide:

  1. Export styles into global stylesheet.

Basic Usage

React Inline Style is used as react mixin.
Styles can be defined with the define() methods and are applied through the style property with the this.style() method.

var React = require("react");
var Style = require("react-inline-style");

Style = Style.define({  //                           <-- make sure to redefine Style with the output of Style.define()
  textComponent : {
    fontWeight:"bold",
    fontStyle:"italic"
  }
});
 
var TextComponent = React.createClass({
  
  mixins : [Style()],  //                           <-- make sure to include the mixin              

  click : function(){
    this.style.define({
      textComponent : {
        fontStyle:"normal",
        letterSpacing:"2px"
      }
    });
    this.forceUpdate();
  },

  render : function (){
    return (
      <p 
        style={this.style("textComponent")} 
        onClick = {this.click}>
          textComponent
      </p>
    );
  }

});

React.render(<TextComponent />, document.body);

Demo: jsFiddle

Style Definition

Styles can be defined on a module-level or the instance-level of the component.

var React = require("react");
var Style = require("react-inline-style");

Style = Style.define({...}); //             <-- module-level
 
React.createClass({
  mixins : [Style()],
  render : function (){
    
    this.style.define({...}); //            <-- instance-level
  
    [...]
  }
});

Styles defined on module-level will apply to all instances of the component (Think: Static styles) while instance-level styles only apply to the current instance/placement (Think: Dynamic styles).

Both define() methods take the same parameters. See API: Style.define(); for more info.

Style Application

Styles are applied through the style property with the this.style() method.

this.style() takes either "class names" whos definitions can be modified and overridden by parent/owner components, or style definitions as object literals. The later cant be overridden from the outside.

Styles passed to this.style() are applied/override each other in the order they were passed in.

var React = require("react");
var Style = require("react-inline-style");

Style = Style.define({
  myStyle : {
    fontWeight:"bold",
    color:"blue"
  }
});
 
React.createClass({
  mixins : [Style()],
  render : function (){
    return (<p style={this.style("myStyle", {color:"red"})}>textComponent</p>); 
  }
});

Demo: jsFiddle

Inheritance

Defined styles are passed down the component tree and override its child components style definitions. This makes it possible to adjust and influence components without changing their code.

The inheritance also works through RandomComponents that do neither use nor include the react-inline-style mixin.

var React = require("react");
var Style = require("react-inline-style");

var TextComponent = require("./TextComponent"); // See definition in "Basic Usage".
var RandomComponent = require("RandomComponent"); // This can be any component.

Style = Style.define({
  textComponent : {
    color : "red"
  }
});
 
var RootComponent = React.createClass({
  
  mixins : [Style()],

  render : function (){
    return (
      <RandomComponent> 
       <TextComponent \>
      </RandomComponent>
    );
  }

});

React.render(<RootComponent />, document.body);

Demo: jsFiddle

Namespaces / Nesting Styles

Namespacing is super useful and even necessary when using modular css.

There are two ways of namespacing a component with React Inline Style:

Namespaceing from inside a component

Within your component you can nest your style definitions in order to create namespaces:

Style.define({

  myNamespace : {
    textComponent : {
      color :"red"
    }
  }
});

// available through

this.style("myNamespace.textComponent")

And namespaces can also be passed in as the first parameter:

Style.define("myNamespace.textComponent", {
    color :"red"
});

// also available through

this.style("myNamespace.textComponent")

styleNamespace Property (Namespacing from outside a component)

When using multiple components within one parent component, namespace collisions can happen and styles can't be defined for a particular component alone.

To prevent this you can use the property styleNamespace to define a namespace for this component instance from the ouside:

var React = require("react");
var Style = require("react-inline-style");

var TextComponent = require("./TextComponent"); // See definition in "Basic Usage".

Style = Style.define({
  first : {
    textComponent : {
      color : "red"
    }
  },
  second : {
    textComponent : {
      color : "blue"
    }
  }
});
 
var RootComponent = React.createClass({
  
  mixins : [Style()],

  render : function (){
    return (
     <TextComponent styleNamespace = "first" \>
     <TextComponent styleNamespace = "second" \>
    );
  }

});

React.render(<RootComponent />, document.body);

Demo: jsFiddle

Global Styles

In some situations global styles are necessary (3rd party html) in others they are useful or improve performance (media queries).

React inline style provides the possibility to define global styles from within a component through Style.global(). Style definitions passed to Style.global() are transformed to normal css definitions and are added to the document <head>.

Style.global({
  ".example" : {
    color : "red",
  
    "p, a" : {
      fontWeight:"bold"
    }
  },
  
  "@media (max-width: 600px)":{
    ".example" : {
      color:"blue"
    }
  }
});


// Becomes in <head /> 

<style id="mgy3joepeffuhaor" class="react-inline-style global-css">
  
  .example {
    color:"red";
  }
  
  .example p {
    font-weight:bold;
  }
    
  .example a {
    font-weight:bold;
  }
  
  @media (max-width: 600px) {
    .example {
      color:"blue";
    }
  }

</style>

Style.global() only exists on module-level. Although it can be updated at any time on instance-level. these styles are global and affect all instances.

Conditionals / :pseudo classes

Using inline styles, :pseudo classes are not available. However they can be substitued easily with react's this.state.

Doing so, often requires tests like this.state.hover && "hoverStyle" to apply hoverStyle only if this.state.hover is actually true.

React Inline Style makes this easier by reintroducing :pseudo classes. When applying a style class through this.style(), you can add any pseudo :variableName to it. Doing so results in a check for this.state.variableName and the styles are only applied if it returned true:

"hoverStyle:hover"    ===  this.state.hover && "hoverStyle"

"hoverStyle:myState"  ===  this.state.myState && "hoverStyle"

Also the two most common :pseudo classes :hover and :pressed are already implemented for you. Just use them and all the required event handlers will be attached once their needed and removed when their not. (Still no solution for :focus though)

Demo: jsFiddle

Extend Style Classes

Style definitions can _extend other styles.

Style.define({
  defaults : {
    myStyle : {
      color:"blue",
      fontWeight: "bold" 
    }
  },
  myStyle : {
    
    _extend:"defaults.myStyle",
    
    color:"red"
  }
});

this.style("myStyle") now results in:

{ color:"red", fontWeight:"bold" }; 

API

React Inline Style is a React mixin. Make sure to include it into your component:

  Style = require("react-inline-style");

  React.createClass({
    mixins : [Style()],
    ...
  });
  

Style.define( [ namespace, ] styles);

RETURNS function: New Style instance.
Defines styles on module-level

namespace optional

TYPE string / array

Onle or multiple namespaces to encapsulate this definition

["namespace", "another.namespace"]

or 

"namespace, another.namespace"

styles required

TYPE object

Style definitions

{
  styleClass : {
    color: "red",
    backgroundColor:"red",
   
    nestedStyle : {
      fontWeight: "bold"    
    }
  },
  anotherStyle: {
    _extend : "styleClass.nestedStyle",
    color: "purple"
  }
}

See Style Definition for more info.


Style.global( [ namespace, ] styles);

RETURNS function: New Style instance.
Defines global styles that will be placed in <head>

namespace optional

TYPE string / array

Onle or multiple namespaces to encapsulate this definition

[".namespace", ".another .namespace"]

or 

".namespace, .another .namespace"

styles required

TYPE object

Style definitions:

{
  ".styleClass" : {
    color: "red",
    backgroundColor:"red",
    ...
    ".nestedStyle" : {
      fontWeight: "bold"    
    }
  },
  ".anotherStyle": {
    color: "purple"
  }
}

See Global Styles for more info.


this.style([ styleClass, ][ styleDefinition, ][ styleGroup, ]);

RETURNS object: Style definition.
Takes any number of parameters/styles and combines them to one valid style definition that can be passed to the style property.
Style definitions override each other in the order they were passed into the function.

styleClass optional

TYPE string

StyleClass string.

"myStyle"
"namespace.myStyle"
"namespace.myStyle:hover"
"myStyle:conditional"

styleDefinition optional

TYPE object

Style definitions

{
  color: "red",
  backgroundColor: "white",
  fontWeight: "bold",
  fontStyle: "italic",
}

styleGroup optional

TYPE array

A collection of styleClasses, styleDefinitions and styleGroups

[ "myStyle", "namespace.myStyle:hover", {color:"red"} ]

See Style Application for more info.


this.style.define( [ namespace, ] styles);

RETURNS null
Defines styles on instance-level

namespace optional

TYPE string / array

Onle or multiple namespaces to encapsulate this definition

["namespace", "another.namespace"]

or 

"namespace, another.namespace"

styles required

TYPE object

Style definitions

{
  styleClass : {
    color: "red",
    backgroundColor:"red",
    
    nestedStyle : {
      fontWeight: "bold"    
    }
  },
  anotherStyle: {
    _extend : "styleClass.nestedStyle",
    color: "purple"
  }
}

See Style Definition for more info.


this.style.log();

RETURNS null
Logs the current "virtual stylesheet" and namespace into the console

License

License: MIT


Released in 2015 by Philipp Adrian @ Dow Jones

About

Reusable and adaptable components without external css dependency.

Resources

Stars

Watchers

Forks

Packages

No packages published

Languages

  • JavaScript 100.0%