How to remove MUI 5 Card Action Area Default Hover State - reactjs

This question has probably been answered but i cant seem to find a solution.
I want to remove the default hover state on the CardActionArea component from mui 5. When i hover over the action area, there is a light grey background that i want to remove. Any help is much appreciated.
<Grid container spacing={2}>
{todos.map((todo) => (
<Grid key={todo.db_id} item xs={12} md={4}>
<Card variant='outlined' sx={{ minWidth: 200 }}>
<CardActionArea onClick={() => handleRedirect(todo.db_id)}>
<CardContent>
<Typography variant='h4' color='text.secondary' gutterBottom>
{todo.title}
</Typography>
</CardContent>
</CardActionArea>
<CardActions>
<Button
onClick={() => deleteHandler(todo.db_id)}
variant='contained'
size='small'
>
Delete
</Button>
</CardActions>
</Card>
</Grid>
))}
</Grid>

I'm using the styled-components engine for MUI 5, so my answer will be based on that, but I was able to remove the grey hover by accessing the .MuiCardActionArea-focusHighlight, as described on this page:
https://mui.com/material-ui/api/card-action-area/
I was able to remove it with the following code:
const StyledCardActionArea = styled(CardActionArea)(({theme}) => `
.MuiCardActionArea-focusHighlight {
background: transparent;
}
`);
Then just put that component in place of CardActionArea within your code.

Related

How can I keep Link and IconButton on the same line?

I have a link with a long text and a "copy" icon after it. I don't want the icon to be aware rendered on a separate line alone.
So these should be ok:
But not this:
The basic code is:
<>
<Link>cat dog cow pig owl rabbit hare wolf fox</Link>
<IconButton><EditIcon/></IconButton>
</>
I can easily place the icon to the right with a flexbox, but not sure how I effectively insert a non-breaking space between a text and an icon.
I just ran into the same problem and I managed to solve it using MUI's Grid.
I had to do some string splitting in my case, so I included here as well. Hope this helps!
<Link onClick={() => { alert('test'); }}>
<Grid container direction="row" alignItems="center">
<Grid item>
<Typography variant="body1">
{linkText.split(' ').slice(0, -1).join(' ')}
</Typography>
</Grid>
<Grid item>
<Typography variant="body1" display="flex" alignItems="center">
{linkText.split(' ').slice(-1)}
<IconButton>
<EditIcon
onClick={(event) => {
event?.stopPropagation();
// do stuff
}}
/>
</IconButton>
</Typography>
</Grid>
</Grid>
</Link>

How to style and position Material UI Link component

I'm trying to style and change position of a Link component, I'm trying to have the Link (Forget Password?) at the right end, but now it's centered as shown in the image below
Also I want to change the color of it, I tried color="black" but didn't work
I'm using grids trying to have the texts apart from each other.
The Code
{/* Password */}
<Grid container mt={4}>
<Grid item xs={6} justify={"flex-start"}>
<Typography
variant="h9"
gutterBottom
component="div"
style={{ fontWeight: "bold", textAlign: "left"}}
>
Password
</Typography>
</Grid>
<Grid item xs={6} justify={"flex-end"}>
<Typography
variant="body2"
gutterBottom
component={Link}
// align="right"
to="/register"
>
{/* <Link to="/register">Forget Password?</Link> */}
Forget Password?
</Typography>
</Grid>
</Grid>
If "black" isn't defined in your theme, that won't work. color="primary" should work, but if you can also define black as a color in your theme.
Alternatively, if you want only this link to be black, you can add the attribute sx={{ color: 'black' }} to <Link> and that should work.
If it's not necessary to do so, I wouldn't wrap the link in a typography; just apply all the styles directly to link, as link already uses a typography element under the hood.
Try this to right-align your password link:
<Grid item xs={6}>
<Box display="flex" justifyContent="flex-end">
<Typography
variant="body2"
gutterBottom
component={Link}
// align="right"
to="/register"
>
{/* <Link to="/register">Forget Password?</Link> */}
Forget Password?
</Typography>
</Box>
</Grid>

Material-UI Responsive Cards

I'm in the process of testing out Material-UI. I've been using Bootstrap for a long time, but am interested in adapting some React projects to Material-UI. Something I've been trying to figure out is how to create responsive cards in Material-UI. I've leaned pretty heavily on Bootstraps responsive containers in the past, so I can't understand why my cards expand with the page but don't shrink as the window is condensed...If we're meant to write custom css for this I'm cool with that, just need to be pointed in the right direction.
Questions:
Are responsive cards in Material-UI out of the gate a thing?
Or are we meant to write the css to make the cards responsive?
If so, where can I learn to do that? (leaned on Bootstrap a lot in the past)
Thanks in advance for your help!
...
useStyles = () => makeStyles(theme => ({
root: {
flexGrow: 1,
},
paper: {
padding: theme.spacing.unit,
textAlign: "center",
color: theme.palette.text.secondary,
marginBottom: theme.spacing.unit
},
}));
render() {
const {baseData} = this.state;
const {hfcMetrics} = this.state;
const {stateMember} = this.state;
const {stateName} = this.state;
const {states} = this.state;
const {lineVizData} = this.state;
const classes = this.useStyles();
return (this.state.doneLoading === false ? (
<div className={classes.root}>
<Grid container>
<Grid item xs={12}>
<ReactLoading type={"spinningBubbles"} color={"black"} height={'10%'}
width={'10%'} id='spinner'/>
</Grid>
</Grid>
</div>
)
:
(stateMember === true ?
<div className={classes.root}>
<Grid container spacing={3}>
<Grid item xs={12}>
<Card>
<CardHeader
title="Options"
/>
<CardContent style={{ width: '100%', height: 300 }}>
<LineViz
data={lineVizData}
state={stateName}
source='compareTool'
states={states}
vizKey={this.state.vizKey}
/>
</CardContent>
<CardActions>
<Button size="small" color="primary">
Share
</Button>
<Button size="small" color="primary">
Learn More
</Button>
</CardActions>
</Card>
</Grid>
<Grid item xs={6}>
<Card ref={this.elRef}>
<CardHeader
title="Comparison Analysis"
action={
<ButtonGroup variant="text" color="primary" aria-label="text primary button group">
<YearDropDown2
year={this.state.year}
handleChange={this.toggleYear}
/>
<IconButton color='default' component="span"
onClick={() => this.resetStateToggle()}><AutorenewRoundedIcon/></IconButton>
</ButtonGroup>
}
/>
<CardContent style={{padding: 0}}>
<DataCompareTable
data={this.state.compareData}
metric={this.state.metric}
stateName={this.state.stateName}
compareCount={this.state.compareCount}
handleChange={this.toggleStateName}
toggleOne={this.state.toggleOne}
toggleTwo={this.state.toggleTwo}
toggleThree={this.state.toggleThree}
/>
</CardContent>
</Card>
</Grid>
<Grid item xs={6}>
<Paper className={classes.paper}>xs=6</Paper>
</Grid>
</Grid>
</div>
: ''
)
)
}
}
export default CompareTool
Thank you for your question
To answer your questions:
1) not that I know of
2) no you dont have to write alot of css, but yes some css in the usestyles
3) Below I explained in detail the css you have to write, in your code. You are using inline styles and useStyles at the same time, try putting all your styles in the usestyle hook API instead and make it responsive. Hope this helps let me know if I need to make it clearer. Thank you
as far as I know, you can use the "useMediaQuery" hook to make your design responsive.
Here is the component from the material UI Card component page, I only added the useTheme and useMediaQuery imports, and added a medium breakpoint inside useStyle under classes.root Here is a useful link
on "useMediaQuery"
https://material-ui.com/components/use-media-query/#usemediaquery
import { useTheme } from "#material-ui/styles";
import useMediaQuery from "#material-ui/core/useMediaQuery";
const useStyles = makeStyles(theme => ({
root: {
maxWidth: 345,
[theme.breakpoints.down("md")] : {
maxWidth: 200
}
},
media: {
height: 140
}
}));
const Card = () => {
const classes = useStyles();
const theme = useTheme();
const matches = useMediaQuery(theme.breakpoints.up("sm"));
return (
<Card className={classes.root}>
<CardActionArea>
<CardMedia
className={classes.media}
title="Contemplative Reptile"
/>
<CardContent>
<Typography gutterBottom variant="h5" component="h2">
Lizard
</Typography>
<Typography variant="body2" color="textSecondary" component="p">
Lizards are a widespread group of squamate reptiles, with over 6,000
species, ranging across all continents except Antarctica
</Typography>
</CardContent>
</CardActionArea>
<CardActions>
<Button size="small" color="primary">
Share
</Button>
<Button size="small" color="primary">
Learn More
</Button>
</CardActions>
</Card>
);
}
Hope this helps
You can wrap your card in a container with responsive options or use grids, which is very convenient.

How to dynamically create button for calling specific action using map array in react

I tried to map an array in react and tried to generate a button that will perform a specific action ,that is referencing another object generated by the same array using map() function.I'm using material-ui to speed up my development process.
I am very new to react (actually this is my first project with react), so maybe this is just simple question to implement 'state' in react, but i'm a little bit confusing to use this and bind syntax properly.
P.S -So excuse me for my stupidity :>
Follow this link to reproduce the code
and this is the code i got trouble with:
const products = [
{
id: 1,
img: "https://image.flaticon.com/icons/png/512/676/676434.png",
title: "Pineaple",
price: "Rp. 14.000",
desc: "Pineaple is one of nutritious food"
},
{
id: 2,
img: "https://image.flaticon.com/icons/png/512/676/676433.png",
title: "Banana",
price: "Rp. 14.000",
desc: "Banana is one of nutritious food"
},
{
id: 3,
img: "https://image.flaticon.com/icons/png/512/676/676441.png",
title: "Dragonfruit",
price: "Rp. 14.000",
desc: "Dragonfruit is one of nutritious food"
},
];
export default function Posts(props) {
const [open, setOpen] = React.useState(false);
function handleClickOpen() {
setOpen(true);
}
function handleClose() {
setOpen(false);
}
return (
<div>
<Grid container spacing={1} justify="center">
{products.map(product => (
<Grid item xs={6} sm={3} md={2} key={product.id}>
<Card>
<CardActionArea>
<CardMedia
component="img"
width="auto"
height="auto"
image={product.img}
/>
<CardContent>
<Typography component="h2"> {product.title} </Typography>
<Typography variant="body2" color="primary" component="p">
{" "}{product.price}{" "}
</Typography>
</CardContent>
</CardActionArea>
<CardActions>
<Button onClick={handleClickOpen}>
Buy
</Button>
</CardActions>
</Card>
</Grid>
))}
</Grid>
{products.map(product => (
<Dialog
key={product.id}
fullScreen
open={open}
onClose={handleClose}
>
<AppBar position="sticky">
<Toolbar>
<IconButton onClick={handleClose}>
<CloseIcon />
</IconButton>
<Typography> {product.title} </Typography>
<Button onClick={handleClose}> buy </Button>
</Toolbar>
</AppBar>
<List className={classes.dialogue}>
<img src={product.img} alt={product.title} />
<ListItem button>
<ListItemText primary={product.title} secondary={product.desc}/>
</ListItem>
</List>
</Dialog>
))}
</div>
);
}
I want to make onclick button generated by mapped array to reference to specific action (show specific dialog within array list). I also want to implement same method for onSubmit on 'buy' button in the Dialog.
Screenshoot: https://imgur.com/a/M4v5LOu
(I click buy on 'pineaple' but react render all list and show the latest object in a the list which is 'dragonfruit'.)
I guess i'll use redux but maybe not right now.
Anyway that's it, I really appreciate any response and helps :)
Thanks!
There are several ways you can solve this but I will show you one. You are making use of React Hooks and you have a hook for setting the open/close state. In my solution, I make slight modification by adding another hook to set the selected product and then checking if both open and the product are set.
export default function Posts(props) {
const classes = useStyles();
const [open, setOpen] = React.useState(false);
const [product, setProduct] = React.useState(null);
function handleClickOpen(event, item) {
event.persist();
setProduct(item);
setOpen(true);
}
function handleClose() {
setOpen(false);
}
return (
<div style={{ margin: 0, padding: 0 }}>
<Grid container spacing={1} justify="center">
{products.map(product => (
<Grid item xs={6} sm={3} md={2} key={product.id}>
<Card elevation={0}>
<CardActionArea>
<CardMedia
component="img"
width="auto"
height="auto"
image={product.img}
/>
<CardContent>
<Typography component="h2"> {product.title} </Typography>
<Typography variant="body2" color="primary" component="p">
{' '}
{product.price}{' '}
</Typography>
</CardContent>
</CardActionArea>
<CardActions>
<Button
variant={'outlined'}
size="small"
color="primary"
onClick={event => handleClickOpen(event, product)}
>
Buy
</Button>
</CardActions>
</Card>
</Grid>
))}
</Grid>
{open && product && (
<Dialog
key={product.id}
className={classes.dialogue}
fullScreen
open={open}
onClose={handleClose}
BackdropProps={{ classes: { root: classes.root } }}
PaperProps={{ classes: { root: classes.paper } }}
>
<AppBar position="sticky">
<Toolbar>
<IconButton
edge="start"
color="inherit"
onClick={handleClose}
aria-label="Close"
>
<CloseIcon />
</IconButton>
<Typography variant="h6" className={classes.title}>
{product.title}
</Typography>
<Button color="inherit" onClick={handleClose}>
buy
</Button>
</Toolbar>
</AppBar>
<List className={classes.dialogue}>
<Image
className={classes.images}
src={product.img}
alt={product.title}
/>
<ListItem button>
<ListItemText primary={product.title} secondary={product.desc} />
</ListItem>
</List>
</Dialog>
)}
</div>
);
}
In your code, you didn't have a way to track the currently selected product hence you always get the last item in the loop. By using another hook for the selected product, I can track the selected product. I hope this helps you and good luck in your mastery of React.
You are having two states open and close.
You are using map on array and showing the dialog box.
The dialog box will open when open state is true.
This will be true for all elements in the array. Dialog box will be shown for all elements.
Now, they will overlap on each other and you can only see the last one.
When you click on close dialog your open state set to false and all the dialogs are closed.
Hint :-
Maintain a state that will contain the id of element for which dialog is to be shown. Show dialog only when id state matches with the element's id

How do I close a card when onclick on a button in react?

I have a material-ui card in which it contains image, input field, check-box and a submit button. In which card is displaying onclick on some other option which is not mentioned in the below code. I want to close a card when I click on submit. How can I achieve this?
<Card
className="details-card"
style={{ paddingTop: "0px" }}
color="primary"
>
<CardHeader
style={{
paddingBottom: 0,
paddingTop: 0
}}
title="Image"
/>
<img src="https://unsplash.it/200/?random" />
<CardContent className="details-card-body">
<TextField label="Name" fullWidth />
<Grid container>
<Grid item xs={4}>
<Typography>
New User
<Checkbox
checked={this.state.addNew}
name="addNew"
onChange={this.handleCheckBox("addNew")}
value="new user"
inputProps={{ "aria-label": "Checkbox B" }}
/>
</Typography>
</Grid>
</Grid>
<Button variant="contained" color="primary">
Click to Tag
</Button>
</CardContent>
</Card>
Here below is my code on CodeSandbox
https://codesandbox.io/embed/lppzx48r0m
There are multiple ways to achieve what you want to do
you'll need a flag to conditionally hide or show the card.
For example lets take flag variable in state, and change state variable flag based on submit button and on the basis of this.state.flag you can do
{this.state.flag ?
(<Card
className="details-card"
style={{ paddingTop: "0px" }}
color="primary"
>
//Card content
</Card>)
:
null
}
You can also provide conditional css based on this.state.flag
<Card
className="details-card"
style={{ paddingTop: "0px", display: this.state.flag ? block : 'none'}}
color="primary"
>
//Card content
</Card>
P.S.: The second approach is not recommended because we are rendering element even if it is not needed.

Resources