How to add ripple effect when clicking Card in MUI - javascript

Is there a way I can add ripple effect to MUI 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.

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.

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>

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>

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>

Here is a Solution 2021 updated
simple You need wrap your custom components with component from material ui .
Then add style padding: 0 that solve.
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>
);
}

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>

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>

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

Related

Materialiui Paper api with close button

I am implementing Paper from Material UI: https://mui.com/components/paper/
And here is the code I have written so far:
<Paper className="modal" elevation={3}>
{..Content..}
</Paper>
The current UI makes it open a special pane which closes only when I click on area outside of it. I want to add a close button to close the Paper. Is it possible to add a custom onClose action on it?
Edit: Here is a codesandbox that I have replicated: https://codesandbox.io/s/black-surf-r1yz87?file=/src/App.js
Paper is just a surface to render components on, it does not support any functionality. For this use case, a state variable can be used to hide and unhide the Paper component. You may make it a reusable component.
const [shouldShowPaper, setShouldShowPaper] = useState(true);
...
{
shouldShowPaper &&
<Paper elevation={props.elevation} style={{position: "relative"}}>
<button
style={{position:"absolute", top: "10px", right: "10px"}}
onClick={() => setShouldShowPaper(false)}
>
X
</button>
{props.children}
</Paper>
}
You may toggle classes to show transitions instead of abrupt removal of the paper component.

ScrollView not working (only on android) reactnative

This is only happening for one of the custom components that I have created. This use to work but it randomly stopped. I have tried to move ScrollView in different parts of the function (before View, around Card ...) but I've had no success. The little scrollbar on the right hand side shows...you just can't scroll. But it works without any issues on iOS
I also tried to give View that wraps ScrollView flex: 1 but no success.
I'm running expo v42
using native base ^2.15.2
The component:
import React from 'react';
import { View, StyleSheet, Image, ScrollView } from 'react-native';
import propTypes from 'prop-types';
import { Card, CardItem } from 'native-base';
export default function ExerciseCard(props) {
const { iconSource, iconType, customStyle, SVG } = props;
return (
<Card style={styles.Card}> // this is from native base
<CardItem style={[styles.ExerciseCard, customStyle]}> // also native base
//icon stuff
// dynamic svg
<View style={styles.TopToBottom}>
<ScrollView>
{props.children} // this can have bunch of text hence why I need to scroll through them
</ScrollView>
</View>
</CardItem>
</Card >
I don't know if it can bring you a solution but I've already encountered this kind of issue, and I had to wrap the content in a touch component like touchableOpacity.
I think the issue depends on the layering / wrapping around the scrollview.

How to use a component to act as clickable alternative?

hey I have designed a rectangle using css and it displays a text inside of it , How can I convert this whole component as a means to navigate to some other url (i have tried using the Link from reactrouterDOM but it changed the shape and also an underline appeared just below the text, which defeated the whole point of it not looking like a link text ).
Any Approach Would be helpful as I am quite new to React.Thanks!
If you want to use Link from react-router:
<Link to="/url" style={{
textDecoration: 'none',
color: 'inherit',
display: 'inline-block',
}}>
<Rectangle/>
</Link>
If you just want to handle onClick in rectangle:
export const Rectangle = (props) => (
<div onClick={props.onClick}>whatever</div>
);
and then use it as:
<Rectangle onClick={() => console.log('whatever')}/>
PS: https://reactjs.org/docs/handling-events.html

How do I get typography theme defaults to apply to regular tags with Material-UI?

So, I've read https://material-ui.com/style/typography/ and I'm loading the Roboto font. I would expect a simple component like:
const theme = createMuiTheme();
const App = () => {
return (
<MuiThemeProvider theme={theme}>
<CssBaseline />
<p>Hello world!</p>
</MuiThemeProvider>
);
};
would style the p tag using Roboto (the default font). But that doesn't happen. If I change the code to:
const theme = createMuiTheme();
const App = () => {
return (
<MuiThemeProvider theme={theme}>
<CssBaseline />
<Typography>Hello world!</Typography>
</MuiThemeProvider>
);
};
it works as expected. A p tag is inserted as well as the typography css. I'm confused by how the library is intended to be used:
Is the idea of Material-UI that I'm going to replace all regular html tags with custom React elements?
Is there any way to apply the styles from the theme typography to regular html tags like h1-6, p, etc easily?
Am I expected to style all the regular html elements myself using withStyles on some top level component?
Is the idea of Material-UI that I'm going to replace all regular html tags with custom React elements?
No. The idea of typography in Material UI (and Material Design in general) is to provide a consistent scale of variants accross you application theme : https://material.io/design/typography/the-type-system.html#
You may then use this typography styles in different ways, like explained in 2. and 3. below
Is there any way to apply the styles from the theme typography to regular html tags like h1-6, p, etc easily?
Like #Chimera.Zen answered, you may apply theme styles and font variants to any react component or html tags with the withStyles HOC. But here is another way of doing so that i find more useful, by reusing theme typography definitions in your JSS styles :
const styles = theme => ({
paragraph: {
...theme.typography.body1
}
});
const MyComponent = props => (
<p className={props.classes.paragraph}>
My styles text
</p>
);
Am I expected to style all the regular html elements myself using withStyles on some top level component?
You are not. You may style individual component if you like, but you will likely more use inheritance and use default styles of container components like Paper, Drawer, etc. or your own container components.
You can implement a global container component (eg "Root" or "App"...) applying default "body1" style to your whole application.
Another approach is to use the 'jss-global' plugin like explained here by MUI author https://github.com/mui-org/material-ui/issues/9988#issuecomment-426631645 :
import { withStyles } from '#material-ui/core/styles';
export default withStyles({
'#global': {
body: {
...theme.typography.body1
},
},
})(() => null);
Yes, but you don't have to.
Yes, using the withStyles component and styles being defined. See example at the end of the answer
Components like Paper, Drawer, etc will take the theme defaults which can also be altered in the component that initiated <MuiThemeProvider>. Normal HTML elements need to have a style defined in the component it's being used in, or a classname in a stylesheet.
If you have say style.root, you can apply that to a Material-UI component, a div, span, p, a, etc. If it's applied to a MUI component, the styles in style.root will override the defaults.
Using the Material-UI Paper component as an example and styles.paragraph as an additional example:
const styles = theme => ({
root: {
...theme.mixins.gutters(),
paddingTop: theme.spacing.unit * 2,
paddingBottom: theme.spacing.unit * 2,
},
paragraph: {
color: '#FFF',
textAlign: 'center',
paddingTop: theme.spacing.unit * 2,
paddingBottom: theme.spacing.unit * 2,
});
These styles can now be applied to any element
<div className={styles.root}>
<Paper className={styles.root}>
<Typography component="p" className={styles.paragraph}>
Paper can be used to build surface or other elements for your application.
</Typography>
</Paper>
</div>

Setting hovered style for material-ui IconButton

According to React Material-UI docs, I have a prop hoveredStyle to work with: http://www.material-ui.com/#/components/icon-button
I want to use IconButton for two purposes:
Utilize its tooltip prop for accessibility
I can wrap Material-UI svg icons directly
However, I don't want the cursor to change to a pointer when I hover (which is default behavior I believe), so I changed it like so.
import DeleteIcon from 'material-ui/svg-icons/action/delete
const hoveredStyle = {
cursor: 'initial'
}
render() {
return (
<IconButton tooltip="Description here" hoveredStyle={hoveredStyle}>
<DeleteIcon />
</IconButton>
)
}
This works fine, except that the split millisecond that I enter hover mode on the icon, I still see the default hand pointer before it gets set to the normal mouse pointer. How do I approach this?
I just tested adding a cursor: default to the style of both IconButton and DeleteIcon and it seems to have the functionality you want. (No pointer cursor on hover.)
const noPointer = {cursor: 'default'};
return (
<div>
<IconButton tooltip="Description here" style={noPointer}>
<DeleteIcon style={noPointer} />
</IconButton>
</div>
);
Some notes for people stumbling upon this thread. If you are having a problem with hover styles for an icon if you are using Material-ui you might have forgot something.
In my case I used a <KeyboardArrowLeft/> and wrapped it in a <Tooltip/>. I could not get hover styles in there at all including a simple hand "cursor". I had to wrap the icon with <IconButton>. It is in that element where you can pass styles.
While the example that was provided before as the "accepted answer" does solve the initial problem, it is not production level.
If you are using reactjs you will need to import the following into your component, switch with your respective icon
import Tooltip from '#material-ui/core/Tooltip';
import IconButton from '#material-ui/core/IconButton';
import KeyboardArrowLeft from '#material-ui/icons/KeyboardArrowLeft';
In the icon wrap as follows
<Tooltip title="">
<IconButton
aria-label=""
style={componentStyle.iconBack}
>
<KeyboardArrowLeft
style={componentStyle.eventHeadingBack}
onClick={}
/>
</IconButton>
</Tooltip>
In the Tooltip, give it a title of what the user should expect when clicking the button.
In the IconButton, add some description for aria (screen readers) like "back to home page". In the style, use a class. You will have a const that you can use for that component you are working on, then give the classname for the actual element a descriptive title. This is where you can control the cursor and hover actions.
In the actual icon, give it a class so you can do things like change color.
Now you will need to style the component, name it however you want but ideally according to the components purpose.
const componentStyle = {
container: {
display: 'flex',
width: '100%',
height: '100vh',
backgroundColor: '#212121',
},
iconBack: {
cursor: 'crosshair'
},
eventHeadingBack: {
color: '#fff',
marginRight: '16px'
}
}

Categories

Resources