Developing on Staxmanade

Reusable React Component with Overridable Inline CSS Styles

(Comments)

React's Component model is great at allowing the component creator to define the interface that consumers of the component interact with. (What is exposed vs what is abstracted away).

If you're building a component and using any in-line styles and you're not careful you can lock the consumer of you're component out of potential customizations they may require for their specific use-case (that you can't think of or foresee). Trying to build components to be reusable and a little more OCP can be challenging especially with how difficult it can be to get css layouts the way you (or the consumer of you're component) may want...

As an example, let's create simple img component to illustrate the point.

Let's say we have the following image component.

import React from 'react';

export default class Image extends React.Component {

  render() {
    return (
      <div>
        <img src={this.props.src} />
      </div>
    );
  }

}

The above component is very simple and very specific.

Now let's say we allow our consumers to customize the height or width of the image. You may think, ok, simple we'll just allow the consumer to specify height and width as props to the component.

So the consumer could just go <Image height="20" width="20" src="someimage.png" />.

And you end up with something that could look like this.

import React from 'react';

export default class Image extends React.Component {

  render() {
    let imageStyle = {
      height: this.props.height,
      width: this.props.width
    };
    return (
      <div>
        <img src={this.props.src} style={imageStyle} />
      </div>
    );
  }
}

Now this works for a while, the consumers of you're component are happy they can control the height and width and everyone's humming along merrily.

Then someone comes to you and says they are having some layout issues and need to control something like float, or margin, or padding... This idea of extending the component with more props could become cumbersome if we have to do this for each and every potential layout option available.

How could we extend this generic pattern into something that allows the component to define a general set of happy defaults, while still giving the consumer complete control over layout?

One Possible Solution

We can use something like Object.assign() to easily accomplish this.

We can allow the consumers to pass in their own style={...} property and provide a set of sensible defaults for the component, but allow the consumer of our component to completely override a style if necessaryl

We can update our:

    let imageStyle = {
      height: this.props.height,
      width: this.props.width
    };

to the following pattern:

    let imageStyle = Object.assign(
      {},                               // target (starting with)
      { ...sensible defaults... },  // some pre-defined default React inline-style for the component
      this.props.style              // allow consumers to override properties
    );

Now if the consumer calls the component with <Image style={{height: "21px", width: "21px"}} src="someImage.png" /> the component's consumers' values will override any defaults provided. And they can extend the style with anything else they may need.

Happy Componentization!

Comments