Vishal Vijay
Vishal Vijay

Reputation: 2528

How to add ripple effect when clicking Card in Material UI

Is there a way I can add ripple effect to Material UI Card component on click.

And I would also like to know, is it possible to make ripple effect to come on top of the content of Card component, rather that it showing as background.

Upvotes: 30

Views: 28823

Answers (8)

Normal
Normal

Reputation: 3716

Using MUI V5 (2022)

You can get the benefit of the component prop, use the <ButtonBase> component to get the ripple effect.

Create a React HOC or simply copy this code into a new file:

import React, { forwardRef } from 'react'
import { ButtonBase } from '@mui/material'

export default function WithTouchRipple(OriginalComponent) {
  return (props) => {
    const Wrapper = !props.component
      ? ButtonBase
      : forwardRef((ButtonBaseProps, ref) => <ButtonBase component={props.component} {...ButtonBaseProps} ref={ref} />)
    return <OriginalComponent {...props} component={Wrapper} />
  }
}

Then use it as follows on any component you like:

import { Chip, Card, Stack } from '@mui/material'
import WithTouchRipple from '../WithTouchRipple'

const RippleChip = WithTouchRipple(Chip)
const RippleCard = WithTouchRipple(Card)
const RippleStack = WithTouchRipple(Stack)
<RippleChip component={Link} to={`/users/${id}`} {...chipProps} />
<RippleStack>...</RippleStack>
<RippleCard>...</RippleCard>

If you want the ripple effect to appear on the <Card> component, there is a built-in component for that called <CardActionArea>, and you can use it as follows:

<Card>
  <CardActionArea>
    <CardContent>
      {...}
    </CardContent>
  </CardActionArea>
</Card>

Upvotes: 3

Akshay K Nair
Akshay K Nair

Reputation: 1476

Using component attribute

Instead of wrapping, you can specify the component attribute as the desired component you want it to be. That is, for this use-case;
import ButtonBase from '@material-ui/core/ButtonBase';
...
<Card component = {ButtonBase}>
  <CardContent>
    ...
  </CardContent>
</Card>

If you have issues with height or width of the card, add the sx attribute;

<Card component={ButtonBase} sx={{height:'100%', width:'100%'}}>
   ...
</Card>

If ButtonBase messes up all other buttons on the page, it's better to use just the Button;

import Button from '@mui/material/Button';
...
<Card component = {Button}>
  <CardContent>
    ...
  </CardContent>
</Card>

Upvotes: 1

NearHuscarl
NearHuscarl

Reputation: 81520

2021 Update

The most idiomatic way to add the ripple effect when clicking the Card is using the CardActionArea. This component inherits the props of ButtonBase. It also changes the Card background color when hovered and focused (unlike ButtonBase):

<Card>
  <CardActionArea>
    <CardContent>
      {...}
    </CardContent>
  </CardActionArea>
</Card>

Codesandbox Demo

Upvotes: 8

debug
debug

Reputation: 383

Here is a Solution 2021 updated

  1. simple You need wrap your custom components with component from material ui .
  2. Then add style padding: 0 that solve.
  3. Here I want my Image should react with ripple effect.

You can customize by wrapping with Grid and props container


import { Button } from "@material-ui/core";

function ImageCard(props){

return (
            <Button style={{ padding: 0, borderRadius: "16px" }}>
              {/*my custom component you can use any component even material ui component also*/}
                <img
                  src={yourImageUrl}
                  alt="img"
                  style={{
                    height: 200,
                    width: 400,
                    borderRadius: "16px",//optional
                  }}
                />
              </Button>
      );
}

Upvotes: 1

Denialos
Denialos

Reputation: 1006

I can see this question was not answered, so I'll provide an up-to-date solution (writing this as material-ui is v. 0.18.7 (stable):

You need to import the ripple higher-order comp. (HOC) as:

import TouchRipple from '@material-ui/core/ButtonBase/TouchRipple';

Then you can wrap any component of you choice with TouchRipple, like:

<TouchRipple>
   <div>
     MY RIPPLING DIV
   </div>
</TouchRipple>

Or, if you need a CSS class-based apporach, you can use materialize lib -> https://react-materialize.github.io/#/

In that case, it's as simple as adding a value to waves prop on a material-ui Button, like:

<Button waves='light'>EDIT ME<Icon left>save</Icon></Button>

Upvotes: 14

Gryk
Gryk

Reputation: 360

I noticed that TouchRipple has been moved out of the internal directory. It's now available in the ButtonBase folder.

Here is how I was able to add ripple effect by using the ButtonBase component -

Basically, you wrap your component, let's say <Card> inside the <ButtonBase> like so, and the ButtonBase takes care of the TouchRipple setting up for you -

<ButtonBase>
     <Card>
         ....
     </Card>
</ButtonBase>

Here is a Codesandbox link to working demo. I know this is not the best way. You could directly use the TouchRipple/Ripple component, but I found this way to be very easy to use.

Hope this helps.

Upvotes: 26

Oscar Franco
Oscar Franco

Reputation: 6260

The approach taken in @xiaofan2406 never worked for me, not to mention passing height, width and position seems easily breakable and might not be possible when using flexbox.

However I managed to make it work like:

<YourComponent>
    <TouchRipple>
        {children}
    </TouchRipple>
</YourComponent>

Upvotes: 1

xiaofan2406
xiaofan2406

Reputation: 3310

The official api doesn't seem to support it. But this is what I do, when I want to use material-ui ripple affect:

Use material-ui/internal/TouchRipple, have a look at its source code

Usage example:

<YourComponent>
    <TouchRipple style={style}/>
    {children}
</YourComponent>

You need to pass the inline style to specify its height, width and position that matches YourComponent's height, width and postion

Upvotes: 0

Related Questions