Utilizing props to define the background-color of the '&:hover' state

I'm adapting Material UI's Chip component to accept custom values for the colors prop, rather than being limited to "primary" and "secondary". Additionally, I want the chip to exhibit a hover effect when clicked, transitioning to a different color upon cursor interaction. With colors passed in as props, adjusting the backgroundColor and color is straightforward:

<Chip
  style={{
    backgroundColor: props.backgroundColor,
    color: props.color
  }}
/> 

However, incorporating a hover color as a prop requires a slightly different approach:

<Chip
  style={{
    backgroundColor: props.backgroundColor,
    color: props.color,
    '&:hover': {
      backgroundColor: props.hoverBackgroundColor,
      color: props.hoverColor
    }
  }}
/> 

Unfortunately, it seems that using &:hover within the style prop is not supported. Normally, &:hover would be included in a styles object passed into withStyles, but accessing props from there presents a challenge. Any suggestions on how to proceed?

Answer №1

To create a custom chip component with controlled styling, you can use the makeStyles function to define your styles. This allows you to pass variables as props to customize the appearance of the chip.

Below is an example implementation of a CustomChip component:

import React from "react";
import Chip from "@material-ui/core/Chip";
import { makeStyles } from "@material-ui/core/styles";
import { emphasize } from "@material-ui/core/styles/colorManipulator";

const useChipStyles = makeStyles({
  chip: {
    color: ({ color }) => color,
    backgroundColor: ({ backgroundColor }) => backgroundColor,
    "&:hover, &:focus": {
      backgroundColor: ({ hoverBackgroundColor, backgroundColor }) =>
        hoverBackgroundColor
          ? hoverBackgroundColor
          : emphasize(backgroundColor, 0.08)
    },
    "&:active": {
      backgroundColor: ({ hoverBackgroundColor, backgroundColor }) =>
        emphasize(
          hoverBackgroundColor ? hoverBackgroundColor : backgroundColor,
          0.12
        )
    }
  }
});

const CustomChip = ({
  color,
  backgroundColor,
  hoverBackgroundColor,
  ...rest
}) => {
  const classes = useChipStyles({
    color,
    backgroundColor,
    hoverBackgroundColor
  });

  return <Chip className={classes.chip} {...rest} />;
};

export default CustomChip;

The styling logic in this component, including the use of the emphasize function for hover and active colors, is inspired by the internal implementation of Material-UI's Chip.

You can use the CustomChip component like this:

<CustomChip
  label="Custom Chip 1"
  color="green"
  backgroundColor="#ccf"
  onClick={() => {
    console.log("clicked 1");
  }}
/>

<CustomChip
  label="Custom Chip 2"
  color="#f0f"
  backgroundColor="#fcc"
  hoverBackgroundColor="#afa"
  onClick={() => {
    console.log("clicked 2");
  }}
/>

Check out this CodeSandbox demo for a live example:

https://codesandbox.io/s/chip-color-forked-tb0vc?fontsize=14&hidenavigation=1&theme=dark


For a Material-UI v5 version, here is how you can define the CustomChip component:

import Chip from "@material-ui/core/Chip";
import { styled } from "@material-ui/core/styles";
import { emphasize } from "@material-ui/core/styles";
import { shouldForwardProp } from "@material-ui/system";

function customShouldForwardProp(prop) {
  return (
    prop !== "color" &&
    prop !== "backgroundColor" &&
    prop !== "hoverBackgroundColor" &&
    shouldForwardProp(prop)
  );
}

const CustomChip = styled(Chip, { shouldForwardProp: customShouldForwardProp })(
  ({ color, backgroundColor, hoverBackgroundColor }) => ({
    color: color,
    backgroundColor: backgroundColor,
    "&:hover, &:focus": {
      backgroundColor: hoverBackgroundColor
        ? hoverBackgroundColor
        : emphasize(backgroundColor, 0.08)
    },
    "&:active": {
      backgroundColor: emphasize(
        hoverBackgroundColor ? hoverBackgroundColor : backgroundColor,
        0.12
      )
    }
  })
);

export default CustomChip;

Here is a CodeSandbox link to see the Material-UI v5 CustomChip in action:

https://codesandbox.io/s/chip-color-0fyh2?fontsize=14&hidenavigation=1&theme=dark

Answer №2

With the latest version of Material UI, known as Material UI v5, you have the ability to style pseudo-classes like :hover using the sx prop:

<Chip
  label="Chip"
  onClick={() => {}}
  sx={{
    ':hover': {
      bgcolor: 'red',
    },
  }}
/>

An alternative approach is to utilize styled() in order to create a reusable styled component:

const options = {
  shouldForwardProp: (prop) => prop !== 'hoverBgColor',
};
const StyledChip = styled(
  Chip,
  options,
)(({ hoverBgColor }) => ({
  ':hover': {
    backgroundColor: hoverBgColor,
  },
}));
<StyledChip label="Chip" onClick={() => {}} hoverBgColor="red" />

You can explore further by visiting this link.

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Aligning elements next to each other in html / css without using any top margins

How can I arrange four blocks of text side-by-side, center them over a background image, and ensure they respond well on different screen sizes without using tables? I typically use tables for this layout, but I've heard that CSS/HTML5 can achieve th ...

Alert: The prop type validation has encountered an issue. The prop `options` is specified as mandatory in `ForwardRef(Autocomplete)`, however, it is currently set as `undefined

Alert: The prop options is required for ForwardRef(Autocomplete), but it is currently set to undefined. at Autocomplete (http://localhost:3000/static/js/bundle.js:93934:83) Please help me fix this warning. Thank you in advance for your assistance. ...

How can TypeScript rules be incorporated into a Next.js project without compromising next/core-web-vitals?

In my current NextJS project which is in typescript, I have the following configuration in my .eslintrc.json: { "extends": "next/core-web-vitals" } Now, I want to include additional typescript rules, such as enforcing the rule of n ...

Changing the position from fixed to static

It's strange, but for some reason when I attempt to apply position:fixed using jQuery: $('#footer').css('cssText', 'position:fixed !important;'); to my footer, the result on the page is different: <div id="footer" ...

The collapsible toggle menu fails to collapse on mobile-sized screens

I've experimented with basic Bootstrap in order to create a toggle menu, but I'm encountering issues. The menu collapses instead of expanding when the screen size is maximized ('m'). Furthermore, clicking on the toggle icon does not cau ...

Retrieve an array of 16 elements using React in a TypeScript environment

Exploring the new React 16 feature to return array elements within the render method is throwing a TypeScript error stating "Property 'type' is missing in type 'Element[]'" const Elements: StatelessComponent<{}> = () => ([ & ...

Combining the value of $(this) to create an identifier name

I am attempting to create a hover effect on an h1 element that triggers the glowing effect on a span element with an id that corresponds to the value of the h1. While I have successfully set up a glowing effect for a sentence, I am struggling to replicate ...

Countless callbacks are triggered by useEffect as the state changes for the initial time

My parent component is passing a callback function to the child component. The purpose of this callback is to be called whenever the state of an array changes in the child component. However, I am facing an issue where upon changing the state for the first ...

Steps to modify the CSS of a custom component in Angular 8

I have been attempting to override the css of a custom component selector, however, my attempts have been unsuccessful. I have tried using ":ng-deep" but it hasn't worked. How can I go about finding a solution for this issue? app.component.html: < ...

The div smoothly descended from the top of the page to the center under the control of jQuery

I am trying to implement a feature where a div slides down from the top of the page to the center when a button is clicked. However, my current code seems to be causing the div to slide from the bottom instead of the top. Ideally, I want the div to slide ...

Ways to conceal CSS on the page when triggering a different element

I am trying to achieve the functionality of hiding the black arrow when clicking on the green arrow, all without using jQuery. Here is my fiddle: http://jsfiddle.net/t5Nf8/195/ html: <div class="arrow-down"></div> <div class="arrow-up"> ...

Custom options titled MUI Palette - The property 'primary' is not found in the 'TypeBackground' type

I am currently working on expanding the MUI palette to include my own custom properties. Here is the code I have been using: declare module '@mui/material/styles' { interface Palette { border: Palette['primary'] background: Pa ...

Problem with loading images on an HTML webpage

After refreshing the page, I'm encountering an issue where the image is not loading. However, if I switch tabs from MEN to WOMEN and back again, the image will display without any problem. Even making changes in the CSS doesn't seem to affect thi ...

Incorporate the total cost of items in the shopping cart through Google Pay using React JS

Hey there, I'm facing a challenge and need some help. How can I integrate the shopping cart value into my Google Pay when I click the pay with Google button? I want the selected amount to be displayed. Any suggestions on how to achieve this? In my se ...

What is the best way to pass an event to a JavaScript function using React?

const [location, setLocation] = useState(default); const handleChangesFunction = (event, data, setLocationFunction) => { const storedLocation = [...data]; storedLocation[event.target.dataset.id][event.target.name] = event.target.value; ...

What is the best way to modify a reducer's state using an action?

My goal is to send an action payload to the reducer and have it update the appropriate data before returning the entire state. The Reducer: const initialState = { fname: 'FNAME', lname: 'LNAME', data: [] } const DATA1 = [ ...

What steps can be taken to resolve the issue "AG Grid: Grid creation unsuccessful"?

For my project, I decided to use the modular import approach for AG-Grid. This means importing only the necessary modules instead of the entire package: "@ag-grid-community/core": "31.3.2", "@ag-grid-community/react": ...

iterative outcomes with ajax and jquery scripting in javascript

Hey there! I'm trying to create a JavaScript script using AJAX that will extract the id and value of a button when hovered over. The extracted value will then be sent to a PHP script on the same page, where it will be used as a variable for searching ...

Text overlay effect on hovering an image

I am struggling to add text to a photo and make the entire photo clickable with a link. I have already applied a darkening effect that I want to keep, but now I need to insert text on top of it. It is important for me to maintain the current dimensions and ...

undefined event typescript this reactjs

I have come across the following TypeScript-written component. The type definitions are from definitelytyped.org. I have bound the onWheel event to a function, but every time it is triggered, this becomes undefined. So, how can I access the referenced el ...