1

I'm writing some simple reusable component for our React(with MaterialUI) application.

The problem is, that i want to allow different styles of this same reusable component, to be customized via props, by the consuming component.

This is some of the code:

import { withStyles } from '@material-ui/core';

const styles = theme => ({
image: {
    maxHeight: '200px'
}
});

render() {
        const classes = this.props.classes
        return (
            <div>
                 ...
                 <img className={classes.image} src={this.state.filePreviewSrc} alt="" />
                 ...
            </div>
        );
    }

Let's say, i want to allow the programmer to customize the appearance of classes.image. Can the hard-coded image class be overwritten somehow?

Is using withStyles api is even the correct approach, for creating components whose appearance can be customized by the consuming component/programmer?

i.brod
  • 3,993
  • 11
  • 38
  • 74
  • 1
    Take a look at styles interpolation https://material-ui.com/styles/basics/#adapting-based-on-props – Dupocas Nov 06 '19 at 14:42
  • I see that it uses the makeStyles api. Can it be used, in the same fashion, with the withStyles api? – i.brod Nov 06 '19 at 14:44
  • Sadly still no: https://github.com/mui-org/material-ui/issues/8726 You can always use inline styles for dynamic styles: `style={{color : props.color}}` – Dupocas Nov 06 '19 at 14:47
  • `withStyles` supports props in the same manner as `makeStyles`. In v4, `withStyles` is just a wrapper around `makeStyles`. https://github.com/mui-org/material-ui/blob/v4.6.0/packages/material-ui-styles/src/withStyles/withStyles.js#L38 – Ryan Cogswell Nov 06 '19 at 15:57

1 Answers1

2

There are three main approaches available for how to support customization of styles:

  1. Leverage props within your styles
  2. Leverage props to determine whether or not certain classes should be applied
  3. Do customization via withStyles

For option 3, the styles of the wrapping component will be merged with the original, but the CSS classes of the wrapping component will occur later in the <head> and will win over the original.

Below is an example showing all three approaches:

ReusableComponent.js

import React from "react";
import { withStyles } from "@material-ui/core/styles";

const styles = {
  root: props => ({
    backgroundColor: props.rootBackgroundColor
      ? props.rootBackgroundColor
      : "green"
  }),
  inner: props => ({
    backgroundColor: props.innerBackgroundColor
      ? props.innerBackgroundColor
      : "red"
  })
};

const ReusableComponent = ({ classes, children, suppressInnerDiv = false }) => {
  return (
    <div className={classes.root}>
      Outer div
      {suppressInnerDiv && <div>{children}</div>}
      {!suppressInnerDiv && (
        <div className={classes.inner}>
          Inner div
          <div>{children}</div>
        </div>
      )}
    </div>
  );
};
export default withStyles(styles)(ReusableComponent);

index.js

import React from "react";
import ReactDOM from "react-dom";
import { withStyles } from "@material-ui/core/styles";

import ReusableComponent from "./ReusableComponent";

const styles1 = theme => ({
  root: {
    backgroundColor: "lightblue",
    margin: theme.spacing(2)
  },
  inner: {
    minHeight: 100,
    backgroundColor: "yellow"
  }
});
const Customization1 = withStyles(styles1)(ReusableComponent);

const styles2 = {
  inner: {
    backgroundColor: "purple",
    color: "white"
  }
};
const Customization2 = withStyles(styles2)(ReusableComponent);

function App() {
  return (
    <div className="App">
      <ReusableComponent>Not customized</ReusableComponent>
      <Customization1>Customization 1 via withStyles</Customization1>
      <Customization2>Customization 2 via withStyles</Customization2>
      <ReusableComponent rootBackgroundColor="lightgrey" suppressInnerDiv>
        Customization via props
      </ReusableComponent>
    </div>
  );
}

const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);

Edit styling reusable component

Ryan Cogswell
  • 75,046
  • 9
  • 218
  • 198