Home > other >  How to make only one card out of a grid of cards expand at a time?
How to make only one card out of a grid of cards expand at a time?

Time:07-29

I have a grid of 'cards' displaying games that when clicked expand down to show more information however when I click on one ALL of the cards expand open and I'm wanting only one to expand at a time.

Here is a codesandbox of what I have so far. Thanks for any help!

CodePudding user response:

Here's working component. The component state must reflect currently open card or null if no card is open. Also changed class to className since it's the proper way to set component class from CSS

export const GameCard = () => {

  const [openedCard, setOpenedCard] = useState(null);

  return (
    <div id="card_wrapper">
      {games.map((game) => (
        <motion.div
          transition={{ layout: { duration: 1, type: "spring" } }}
          layout
          onClick={() => setOpenedCard(game.id)}
          key={game.id}
          className="card"
          name={game.name}
          style={{
            backgroundImage: `url(${game.background})`,
            backgroundSize: "cover",
            backgroundRepeat: "no-repeat"
          }}
        >
          <motion.h2 layout="position">
            {" "}
            <img src={game.logo} alt={game.alt} />
          </motion.h2>
          {openedCard === game.id && (
            <motion.div
              initial={{ opacity: 0 }}
              animate={{ opacity: 1 }}
              transition={{ duration: 1 }}
              className="expand"
            >
              <p> {game.description} </p>
            </motion.div>
          )}
        </motion.div>
      ))}
    </div>
  );
};

CodePudding user response:

try this :

// add new state to capture the index of the clicked element :
const [elementId, setElementId] = useState(null);

and in the return part capture the clicked index inside the onClick :

return (
    <div id="card_wrapper">
      {games.map((game) => (
        <motion.div
          transition={{ layout: { duration: 1, type: "spring" } }}
          layout
          onClick={() => {
            setIsOpen(!isOpen);
            setElementId(game.id);
       }}
...)

and finally render motion only when (isOpen) and (game.id === elementId) :

{isOpen && game.id === elementId && (
            <motion.div
              initial={{ opacity: 0 }}
              animate={{ opacity: 1 }}
              transition={{ duration: 1 }}
              
            >

full sandbox example : here

  • Related