Simon Long
Simon Long

Reputation: 1450

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.

Upvotes: 15

Views: 19071

Answers (5)

chygo
chygo

Reputation: 476

Now, you can style the icon prop directly with sx:

<EleIcon sx={{ height: '2.5vh', width: '2.5vw' }} />

EleIcon is the icon passed to my component

Upvotes: 1

Lasitha Lakmal
Lasitha Lakmal

Reputation: 880

Try this solution. Worked for me perfectly

Component

import MyLocationIcon from '@mui/icons-material/MyLocation';

<TextInputComp Icon={MyLocationIcon} />

Component code

function TextInputComp(p: any) {
    const {Icon } = p;
    return (
        <Icon fontSize={'large'} />
    )
}

Upvotes: 0

Ryan Cogswell
Ryan Cogswell

Reputation: 81166

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

Upvotes: 23

Fraction
Fraction

Reputation: 12993

Pass the icon like this:

<MyComponentWithIconProps statusImage={Done} />

then use it as follows:

return <div><props.statusImage className={styles.iconStyle} /></div>;

Upvotes: 3

Vicente
Vicente

Reputation: 2472

I would do like this:

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

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

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

  return <div className={styles.iconStyle}>{props.statusImage}</div>;
}

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

export default MyComponentWithIconProps;

Upvotes: 0

Related Questions