How to make Card component clickable?

Viewed 41722

I use the Ant Design for my WebApp. For the Card, there's a hoverable prop that make the card seams clickable but there's no onClick prop. How do I make it really clickable?

This is my Code:

import React, { Component } from 'react';
import { Card, Avatar, Icon, Button, Divider } from 'antd';
import EventDetailsDrawer from '../ui/EventDetailsDrawer';

const { Meta } = Card;

class EventCard extends Component {

render() {
    return (
        <div onClick={alert("Hello from here")}>
            <Card
                hoverable
                cover={<img alt="example" src="https://assetsnffrgf-a.akamaihd.net/assets/m/1102015169/univ/art/1102015169_univ_lsr_lg.jpg" />}
                bodyStyle={{ marginBottom: "-5px" }}
                >
                    <Meta
                        //avatar={<Avatar src="https://zos.alipayobjects.com/rmsportal/ODTLcjxAfvqbxHnVXCYX.png" />}
                        avatar={<Button type="primary" shape="circle-outline">{this.props.owner}</Button>}
                        title={this.props.title}
                        description={this.props.descp}
                    />
                    <Divider style={{ marginLeft: "0px" }}></Divider>
                    <p><Icon type="clock-circle" style={{ fontSize: "15px", color: "#1890FE" }} theme="outlined" /><span style={{ marginLeft: "15px" }} />{this.props.date}</p>
                    <p><Icon type="environment" style={{ fontSize: "15px", color: "#1890FE" }} theme="outlined" /><span style={{ marginLeft: "15px" }} />{this.props.location}</p>
        </Card>
                    <EventDetailsDrawer></EventDetailsDrawer>
        </div>
                );
            }
        }

export default EventCard

I try to make a dive (around the Card) clickable, but the Code runs immediately after the app is loaded, since I pack each card into a list item. How to make Card component clickable?

Thanks for your answer :)

8 Answers

Notice that what you are attaching to the div's onClick listener is the value returned by alert and not actually a function that should be run whenever the div is clicked.

Try changing this:

<div onClick={alert("Hello from here")}>

To this:

<div onClick={() => alert("Hello from here")}>

I came here with a similar question. What worked for me is to wrap the <Card> with a <Link> component. Also, setting the hoverable property on the card will give it an effect that has it appear "clickable". For example:

<Link to={'/customer/list'}>
   <Card hoverable>

      // ... removed for brevity...

   </Card>
</Link>

Try this, onClick expects a function, and is invoking when render() is executed.

import React, {Component} from 'react';
import {Card, Avatar, Icon, Button, Divider} from 'antd';
import EventDetailsDrawer from '../ui/EventDetailsDrawer';

const {Meta} = Card;

class EventCard extends Component {
    render() {
        return (
            <div onClick={() => {alert("Hello from here")}}>
                <Card
                    hoverable
                    cover={<img alt="example"
                            src="https://assetsnffrgf-a.akamaihd.net/assets/m/1102015169/univ/art/1102015169_univ_lsr_lg.jpg"/>}
                            bodyStyle={{marginBottom: "-5px"}}
                >
                    <Meta
                        avatar={<Button type="primary" shape="circle-outline">{this.props.owner}</Button>}
                        title={this.props.title}
                        description={this.props.descp}
                    />
                    <Divider style={{marginLeft: "0px"}}></Divider>
                    <p>
                        <Icon type="clock-circle" style={{fontSize: "15px", color: "#1890FE"}} theme="outlined"/>
                        <span style={{marginLeft: "15px"}}/>
                        {this.props.date}
                    </p>
                    <p>
                        <Icon type="environment" style={{fontSize: "15px", color: "#1890FE"}} theme="outlined"/>
                        <span style={{marginLeft: "15px"}}/>
                        {this.props.location}
                    </p>
                </Card>
                <EventDetailsDrawer></EventDetailsDrawer>
            </div>
        );
    }
}

export default EventCard

Keep in mind make a div clickable is a very bad practice in terms of accessibility, because without mouse, you cannot tab to the card nor use enter or space to click the card.

My recommendation would be wrap the card with an unstyled button, so you can take all the advantages of a button (click, tab, keyboard support)

    import React, { Component } from 'react';
    import { Card, Avatar, Icon, Button, Divider } from 'antd';
    import EventDetailsDrawer from '../ui/EventDetailsDrawer';

    const { Meta } = Card;

    class EventCard extends Component {

    render() {
        return (
            <button onClick={alert("Hello from here")} className="unstyled-button">
                <Card />
            </button>
                    );
                }
            }

    export default EventCard

css

 .unstyled-button {
       border:none;
    }

maybe this will help:

youHandleClickFunc = (params) => {
console.log('you need params from Card', params)
}

render() {
        return (
          <Card handleClick={()=> this.youHandleClickFunc(param)}/>
        )
}

Since the antd Card already supports onClick, you can pass this onClick to your custom property like below:

// EventCard.js
import React from 'react';
import PropTypes from './propTypes';
import 'antd/dist/antd.css';
import { Card } from 'antd';

const { Meta } = Card;

const EventCard = ({
    myOnClick,
    ...restProps
}) => {
    return (
        <Card
            hoverable
            bodyStyle={{ marginBottom: "-5px" }}
            cover={<img alt="example" src="https://assetsnffrgf-a.akamaihd.net/assets/m/1102015169/univ/art/1102015169_univ_lsr_lg.jpg" />}
            onClick={() => myOnClick()}
        >
            <Meta 
                title={this.props.title}
                description={this.props.descp} />
        </Card>
    );
};

EventCard.propTypes = {
    myOnClick: PropTypes.func,
};

export default EventCard;

Where propTypes is:

// propTypes.js
import PropTypes from 'prop-types';

export default {
  ...PropTypes,
  ID: PropTypes.oneOfType([PropTypes.string, PropTypes.number]).isRequired,
  component: PropTypes.oneOfType([PropTypes.string, PropTypes.func]),
  date: PropTypes.oneOfType([PropTypes.instanceOf(Date), PropTypes.string]),
};

Then you can use it like:

myClickHandler = (params) => {
    console.log("Click!!!");
});

render() {
    return (
        <EventCard myOnClick={()=> this.myClickHandler("any parameters")} />
    );
}

This works well for me:

  <Card className={classes.root}>
      <CardActionArea
        onClick={(evt) => {
          console.log(evt.target);
          sayHi(evt);
        }}
      >
        <CardContent>
          <Typography variant="h5" component="h2">
            {props.job.label}
          </Typography>
        </CardContent>
      </CardActionArea>
      <CardActions></CardActions>
    </Card>

and sayHi is

  function sayHi(props) {
    history.push({
      pathname: "/another-page/",
      state: { jobId: props.job.id },
    });
  }

There is no possible, to make onClick here. You need to call an onClick event inside the Card component. Then if you need to pass some props, or use logic, just pass the function/content in the prop to Card. Something like that - <Card handleClick={this.handleClickMethod} />. Then inside Card component you can call the handleClick function.

Hope that helped you

Related