Sample component

Here is a sample component built with Styletron Themer. It creates a small data-visualization object, with a number and a label. It will have some dynamic styles; for example, the user will be able to choose the color of both the label and value.

Here's how we will use it:

<Value label="Threats" color="#e94c43">
  37
</Value>

Component code

The component code in this case is quite simple. Significantly, there is no style information or logic here (that comes next). Note the use of the <Styled> component and its render callback function.

import React from 'react';
import PropTypes from 'prop-types';
import {Styled} from 'styletron-themer';

// each component typically has a "styles.js" file (ours is shown below)
// if you prefer, you can embed it in the component file instead
import staticStyle, {dynamicStyle} from './styles';

// a separate component is used to draw the label ("Threats"). this
// isn't strictly necessary, but it keeps everything clean and reusable
import ValueLabel from './label/label';

export default class Value extends React.Component {

  static propTypes = {
    label:      PropTypes.node,
    color:      PropTypes.string,
    labelColor: PropTypes.string
  };

  render() {
    // the Styled component does all the work. we pass it a callback as a child
    return (
      <Styled
        themeName    = 'Value'
        staticStyle  = {staticStyle}
        dynamicStyle = {dynamicStyle}
        {...this.props}
      >
        {(className, props) => {
          // see below for more details on the use of the "props" parameter
          //
          let {label, color, labelColor, ...otherProps} = props;
          return (
            <div {...otherProps} className = {className}>
              {this.props.children}
              {label && <ValueLabel color={labelColor}>{label}</ValueLabel>}
            </div>
          );
        }}
      </Styled>
    );
  }
}

By the time the render callback is invoked, className parameter has been set up with all of the appropriate styles based on the theme cascade. All the component needs to do is apply the classes to the appropriate HTML element.

About the Styled component

The <Styled> component takes several props, all of which are optional:

  • staticStyle: The base style object for your component. This is a Styletron object, which means it can contain :hover, :focus, or media queries.
  • dynamicStyle: If your component needs to change style based on props, pass a function here. Details about the function signature are in the section on the API.
  • themeName: If you want to share your component, if you want it to have an overridable theme, you must give it a unique name for the theme. But if your component is single-use or private, you can omit this prop.
  • {...this.props}: Behind the scenes, the <Styled> component needs to invoke your dynamic styling function, to which it passes the instance's props. This means it needs access to those props.

Additionally, by passing the props up to <Styled>, we give our users the ability to apply inline styles. For example, if the user rendered <Value style={{background:'#eee'}} ... />, the style prop would be scooped up and passed to <Styled> as part of the props spread. These inline styles will be merged and included in the final list of Styletron classes passed to your render callback.

More details in the API section.

About the props parameter

Your render callback is invoked with a props parameter. It contains all of the props you passed into Styled, minus the props that it consumes (e.g., themeName, style, className). This turns out to be a really important feature that allows component users to pass down neutral props (e.g., data- or aria-) to your underlying HTML element. See prop flow for more details.

Style code

In this example, we've extracted the styling code into a separate file. This isn't required. Feel free to include this code in your component file.

Also, we export the static styles as the default export, and the dynamic styling function as a named export. That's just our convention; you can do whatever you like here, as long as you pass the correct props to <Styled>.

// styles.js
//
// the base style is applied to all instances of the component.
// we never name this variable. the reasoning is important, and
// is explained in Best Practices.
//
export default {
  textAlign:  'center',
  fontSize:   '20px',
  fontWeight: 'bold',
  color:      '#999'
};

// dynamic style as a function of props. the function is also given
// a copy of the base style, now called "componentTheme", because it
// integrates the user's overrides.
//
export function dynamicStyle({props, componentTheme}) {
  return Object.assign(

    // we create a fresh, empty object...
    {},

    // add in the base style...
    componentTheme,

    // then override the color if requested
    props.color && {color: props.color}
  );
}

The dynamicStyle function (you can name it whatever you like) takes the base component theme and applies changes based on props. In this example, only the text color is changed.

More details and specs on the dynamic styling function are in the API section.

Using the components

Styled components give users the ability to override the theme globally (discussed elsewhere). It also allows users to override styles on each component:

<Value label = "Threats"
       color = "#e94c43"
       id    = "threat-indicator"
       style = {{border: '2px solid blue'}}
       className = 'shadowed'
  37
</Value>

The style prop is a Styletron object. That means it looks similar to React's own style prop, except that these styles are run through Styletron and converted into classes, and they can contain options (such as :hover and media queries). (Details in theme cascade.) The className prop allows you to apply non-Styletron classes, such as from a legacy CSS framework. If you do not have legacy classes, you should use style instead.

The id prop is passed through to the DOM node, along with any data- attributes or other props that your component does not intercept and process. See the use of the otherProps value in the component's render code above.

results matching ""

    No results matching ""