Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I style a material-ui Icon which was passed as prop

I'm writing a custom Material UI React component which I want to pass an Icon into as a prop. However I want to style the icon when I get it and make it a minimum width and height.

Here's a simplified version of what I'm trying to do. I want to apply the iconStyle to the icon passed in as props.statusImage but can't figure out how.

import PropTypes from "prop-types";
import { makeStyles } from "@material-ui/styles";

const useStyles = makeStyles({
  iconStyle: {
    minWidth: 100,
    minHeight: 100
  }
});

function MyComponentWithIconProps(props) {
  const styles = useStyles();

  return <div>{props.statusImage}</div>;
}

MyComponentWithIconProps.propTypes = {
  statusImage: PropTypes.element
};

export default MyComponentWithIconProps;

I use the component like this

import {Done} from "@material-ui/icons";
<MyComponentWithIconProps statusImage={<Done/>}

Code Sandbox : https://codesandbox.io/s/jovial-fermi-dmb0p

I've also tried wrapping the supplied Icon in another Icon element and attempting to style that. However that didn't work and seems sort of 'hacky' anyway.

like image 636
Simon Long Avatar asked Nov 15 '19 14:11

Simon Long


2 Answers

There are three main alternatives:

  1. Pass in the element type of the icon rather than an element (e.g. Done instead of <Done/>) and then add the className as you render the element (this is the approach in Fraction's answer).
  2. Clone the element in order to add the className prop to it.
  3. Put a class on the parent element and target the appropriate child type (e.g. svg).

Approach 1:

index.js

import React from "react";
import ReactDOM from "react-dom";
import { Done } from "@material-ui/icons";
import MyComponentWithIconProps from "./MyComponentWithIconProps";

function App() {
  return (
    <div className="App">
      <MyComponentWithIconProps statusImage={Done} />
    </div>
  );
}

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

MyComponentWithIconProps.js

import React from "react";
import PropTypes from "prop-types";
import { makeStyles } from "@material-ui/styles";

const useStyles = makeStyles({
  iconStyle: {
    minWidth: 100,
    minHeight: 100
  }
});

function MyComponentWithIconProps(props) {
  const styles = useStyles();
  const StatusImage = props.statusImage;
  return (
    <div>
      <StatusImage className={styles.iconStyle} />
    </div>
  );
}

MyComponentWithIconProps.propTypes = {
  statusImage: PropTypes.element
};

export default MyComponentWithIconProps;

Edit add class to icon prop


Approach 2:

index.js

import React from "react";
import ReactDOM from "react-dom";
import { Done } from "@material-ui/icons";
import MyComponentWithIconProps from "./MyComponentWithIconProps";

function App() {
  return (
    <div className="App">
      <MyComponentWithIconProps statusImage={<Done />} />
    </div>
  );
}

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

MyComponentWithIconProps.js

import React from "react";
import PropTypes from "prop-types";
import { makeStyles } from "@material-ui/styles";
import clsx from "clsx";

const useStyles = makeStyles({
  iconStyle: {
    minWidth: 100,
    minHeight: 100
  }
});

function MyComponentWithIconProps(props) {
  const styles = useStyles();
  const styledImage = React.cloneElement(props.statusImage, {
    // Using clsx to combine the new class name with any existing ones that may already be on the element
    className: clsx(styles.iconStyle, props.statusImage.className)
  });
  return <div>{styledImage}</div>;
}

MyComponentWithIconProps.propTypes = {
  statusImage: PropTypes.element
};

export default MyComponentWithIconProps;

Edit add class to icon prop


Approach 3:

index.js

import React from "react";
import ReactDOM from "react-dom";
import { Done } from "@material-ui/icons";
import MyComponentWithIconProps from "./MyComponentWithIconProps";

function App() {
  return (
    <div className="App">
      <MyComponentWithIconProps statusImage={<Done />} />
    </div>
  );
}

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

MyComponentWithIconProps.js

import React from "react";
import PropTypes from "prop-types";
import { makeStyles } from "@material-ui/styles";

const useStyles = makeStyles({
  iconStyle: {
    "& > svg": {
      minWidth: 100,
      minHeight: 100
    }
  }
});

function MyComponentWithIconProps(props) {
  const styles = useStyles();
  return <div className={styles.iconStyle}>{props.statusImage}</div>;
}

MyComponentWithIconProps.propTypes = {
  statusImage: PropTypes.element
};

export default MyComponentWithIconProps;

Edit add class to icon prop

like image 168
Ryan Cogswell Avatar answered Nov 15 '22 23:11

Ryan Cogswell


Pass the icon like this:

<MyComponentWithIconProps statusImage={Done} />

then use it as follows:

return <div><props.statusImage className={styles.iconStyle} /></div>;
like image 3
Fraction Avatar answered Nov 15 '22 21:11

Fraction