Tyler
Tyler

Reputation: 1283

Applying conditional styles to a component in React - Inline CSS

I am trying to style some buttons based on whether they are 'active' or not, and also whether or not the use is hovering the mouse over them.

It works to some extent, however, it's behaving in a way that I don't fully understand.

How do I apply a conditional style to a component, based on its state, as well as based on user behavior?

I have an example in this SANDBOX

And the main JS file copied here:

demo.js

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

const useStyles = theme => ({
  root: {
    backgroundColor: theme.palette.secondary.paper,
    width: 500
  },
  pageButton: {
    backgroundColor: "black",
    color: "blue",
    width: 30,
    minWidth: 20,
    "&:hover": {
      backgroundColor: "green"
    }
  },
  normalButton: {
    width: 30,
    minWidth: 20,
    backgroundColour: "red"
  }
});

class Feature extends React.Component {
  constructor(props) {
    super(props);
    this.state = { currentPage: 0 };
  }
  handleClick(page) {
    this.setState({ currentPage: page });
  }

  fetchPageNumbers() {
    return [1, 2, 3];
  }
  render() {
    const classes = this.props.classes;
    return (
      <div className={classes.root}>
        {this.fetchPageNumbers().map((page, index) => {
          return (
            <div>
              <Button
                onClick={() => this.handleClick(page)}
                key={page}
                className={
                  this.state.currentPage === page
                    ? classes.pageButton
                    : classes.normalbutton
                }
              >
                {page}
              </Button>

              <Button
                onClick={() => {}}
                key={page * 20}
                className={classes.normalButton}
              >
                {page * 20}
              </Button>
            </div>
          );
        })}
      </div>
    );
  }
}

Feature.propTypes = {
  classes: PropTypes.object.isRequired
};

export default withStyles(useStyles)(Feature);

There are two rows. The second row picks up the styles just fine. The first row will only adhere when the button is clicked. I want to be able to set the state based on whether the current button is active (ie. state == buttonNumber), and also whether or not the user is hovering over any of the buttons.

Upvotes: 2

Views: 6491

Answers (2)

Reuben Porter
Reuben Porter

Reputation: 1

In response to @keikai you can also pass in an object into the styles() hook (I was getting an error by just passing in props).

import { makeStyles } from "@material-ui/core/styles";
const useStyles = makeStyles(theme => ({
  root: {
    width: ({ size }) => (size === "big" ? "100px" : "20px")
  }
}));

const classes = useStyles({ size });

Upvotes: 0

keikai
keikai

Reputation: 15146

How do I apply a conditional style to a component, based on its state, as well as based on user behavior?


For conditional style based on user behavior

I guess your current demand is when it's hovering.

"&:hover": {
  // Hover styles
}

For conditional style based on params(props)

withStyles doesn't have access to the properties.


But there are multiple work-around solutions

1.use injectSheet HOC

notice that the useStyles in your code is actually not a hook

const styles = props => ({
  root: {
    width: props.size === 'big' ? '100px' : '20px'
  }
})

or

const styles = {
  root: {
    width: props => props.size === 'big' ? '100px' : '20px'
  }
}

with

const CustomFeature = ({size, classes}) => <Feature className={classes.root} />;

export default withStyles(styles)(CustomFeature);

2.use style hooks with params (for functional components)

import { makeStyles } from "@material-ui/core/styles";
const useStyles = makeStyles(theme => ({
  root: {
    width: props => props .size === "big" ? "100px" : "20px"
  }
}));

const classes = useStyles();

or

import { makeStyles } from "@material-ui/core/styles";
const useStyles = params =>
  makeStyles(theme => ({
    root: {
      width: params.size === "big" ? "100px" : "20px"
    }
  }));

const classes = useStyles(whateverParamsYouWant)();

Upvotes: 5

Related Questions