Send Variable to withStyles in Material UI?
Asked Answered
H

2

5

I have the following:

class StyledInput extends React.Component{


  styles = (color, theme) => ({
    underline: {
      borderBottom: `2px solid ${color}`,
      '&:after': {
        borderBottom: `2px solid ${color}`,
      }
    }
  })
  
  div = props => (
    <TextField
    placeholder="temp input"
    InputProps={{
      classes:{
        root: props.classes.underline
      },
      style:{
        height: '1.5rem',
        fontSize:'1rem',
        marginTop: '-1rem',
      }
    }}
    >
      <div>
        {props.children}
      </div>
    </TextField>
  )
  
  Styled = withStyles(this.styles('white'))(this.div)

  render(){
    return(
      <div>
        <this.Styled>{this.props.children}</this.Styled>
      </div>
    );
  }
}

export default StyledInput;

So what this does is it successfully takes a material UI text field and changes the bottom bar to be white, as opposed to blue, when the user clicks the field. Great!

...however...

What I would really like to do is something like

<this.Styled color={someDefinedColor}>{this.props.children}</this.Styled>

where Styled would then look like this:

Styled = (color) => withStyles(this.styles(color))(this.div)

so that I can dynamically pass colors to the Styled attribute. Clearly this is pseudo-code - I've been playing with it, but can't get it to fall through. As a general statement, material-ui is a bit of a bummer to dynamically change colors, so I was wondering if anyone knew how to get this to work.

Thanks!

Homoeo answered 22/2, 2019 at 18:3 Comment(3)
you may want to dig into the withStyles code and see how it creates the component that wraps it: github.com/mui-org/material-ui/blob/…Lauricelaurie
Thanks, I'll take a look.Homoeo
Answers in answer section only, please.Gird
H
4

Here is an example of how to do this using the new hook syntax:

index.js

import React from "react";
import ReactDOM from "react-dom";
import StyledComponent from "./StyledComponent";
const CustomComponent = ({ children, className }) => {
  return (
    <p className={className}>
      Just showing passing in the component to use rather than automatically
      using a div.
      <br />
      {children}
    </p>
  );
};
function App() {
  return (
    <div className="App">
      <StyledComponent color="green">
        Here's my content with green underline
      </StyledComponent>
      <StyledComponent
        component={CustomComponent}
        color="blue"
        hoverColor="orange"
      >
        Here's my content with blue underline that changes to orange on hover.
      </StyledComponent>
    </div>
  );
}

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

StyledComponent.js

import React from "react";
import { makeStyles } from "@material-ui/styles";
const useStyles = makeStyles({
  root: {
    borderBottom: ({ color }) => `2px solid ${color}`,
    "&:hover": {
      borderBottom: ({ color, hoverColor }) => {
        const borderColor = hoverColor ? hoverColor : color;
        return `2px solid ${borderColor}`;
      }
    }
  }
});

const StyledComponent = ({
  component: ComponentProp = "div",
  children,
  color,
  hoverColor
}) => {
  const classes = useStyles({ color, hoverColor });
  return <ComponentProp className={classes.root}>{children}</ComponentProp>;
};

export default StyledComponent;

Edit useStyles with variable

If you wanted, you could put this useStyles method in its own file and re-use it as a custom hook to make the classes it generates (still with variable support) available to multiple components (rather than just StyledComponent).

Huberty answered 22/2, 2019 at 18:45 Comment(4)
Thanks! I think the key for me is that you basically have to wrap the thing in another component (in your case StyleDiv and useStyles). I have something similar with classes, but your way definitely appears more parsimonious. Thanks for the help!Homoeo
Sorry - stupid question. Is there a way to add pseudo-elements to the makeStyles constructor? It appears that it may not be possible.Homoeo
I've added an example using ":hover". Here's the relevant documentation: cssinjs.org/jss-plugin-nested/…Huberty
Ahh...wunderbar!Homoeo
P
0

Here is an example of how you can use only props or props and theme both with makeStyles() just like styled-components

component.js

import { tableCellStyling } from './component.styled.js';

const RenderRow = (props) => {
    const { noPaddingTopBottom } = tableCellStyling(props);
    return(
        <StyledTableRow>
            {data.map( (row,i) => (
                <StyledTableCell className={noPaddingTopBottom}>
                    {row.data}
                </StyledTableCell>
            )}
        </StyledTableRow>
    )
};

Assuming my props object which is being passed by RenderRow Component to tableCellStyling has { color: 'grey', thinRow: true } in it

component.styled.js

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

export const tableCellStyling = makeStyles(theme => ({
    noPaddingTopBottom: {
        borderBottom: ({ color }) => color ? `2px solid ${color}` : '2px solid red',
        paddingBottom: props => props.hasActions && 0,
        paddingTop: props => props.hasActions && 0,
        backgroundColor: theme.palette.common.white,
    },
}));
Passage answered 12/1, 2021 at 10:50 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.