user24889088
user24889088

Reputation: 1

How to move elements beneath downwards when expanding a div in React?

I am making a 'Team' section for a website, and I have a div containing 4 cards arranged horizontally in a row; each card has a team member's image, name, role, and a 'Read Bio' button. When a 'Read Bio' button is pressed on any of the cards, a div appears below it, containing the full bio of that team member, like this. I want the div to expand from the top down, and in doing so, push the elements below it smoothly downwards to make room for it. Right now, the Advisory Board heading is jumping downwards instead of moving smoothly downwards. I am using React and Framer Motion.

I want the effect to be very similar to the expanding bios in this website: https://www.centific.com.cn/zh-hans/our-leadership

const menuVars = {
    // animation specifications
};

<div className={styles.cardWrapper}>
    <div className={styles.cardsContainer}>
      {founders.map((member) => (
        <Card/>
      ))}
    </div>

    <AnimatePresence>
      {activeBio && (
        <motion.div
          key={activeBio}
          variants={menuVars}
          initial="initial"
          animate="animate"
          exit="exit"
          className={styles.bioContainer}
          style={{
            top: bioPosition?.top,
            transformOrigin: "top",
          }}
        >

         ...

    </AnimatePresence>

<div className={styles.sabInfoDiv}>
        <div className={styles.heading}>Advisory Board</div>
        <p className={styles.sabInfo}>
          Bla Bla Bla
        </p>
      </div>

(activeBio and bioContainer are both useState hooks that I have not shown in the code)

Upvotes: -1

Views: 33

Answers (1)

Ajoy_Sarker
Ajoy_Sarker

Reputation: 34

You can use this component. hope this helps.

import { useState, useRef } from 'react';
import { motion, AnimatePresence } from 'framer-motion';

const AdvisoryBoardPreview = () => {
  const [activeBio, setActiveBio] = useState(null);
  
  // Sample data for advisory board members
  const members = [
    {
      id: 1,
      name: "Dr. Jane Smith",
      role: "Research Director",
      bio: "Dr. Jane Smith has over 15 years of experience in molecular biology research. She previously led research teams at Stanford University and has published over 50 papers in leading scientific journals. Her expertise in genomics has been instrumental in guiding our research direction.",
    },
    {
      id: 2,
      name: "John Anderson",
      role: "Technology Advisor",
      bio: "John Anderson brings 20+ years of technology leadership experience from Silicon Valley. As former CTO of TechGiant Inc., he oversaw the development of groundbreaking AI applications. John advises on our technology roadmap and strategic partnerships.",
    },
    {
      id: 3,
      name: "Dr. Michael Wong",
      role: "Medical Advisor",
      bio: "Dr. Wong is a practicing cardiologist and medical researcher with appointments at University Medical Center. His clinical expertise helps ensure our developments meet real-world healthcare needs. He has received numerous awards for his contributions to cardiovascular medicine.",
    },
    {
      id: 4,
      name: "Sarah Johnson",
      role: "Ethics Advisor",
      bio: "Sarah Johnson is a bioethicist with expertise in emerging technology regulations. Her background includes policy development at national research institutions and advisory roles for government agencies. She helps us navigate complex ethical considerations in our work.",
    }
  ];

  const handleCardClick = (memberId) => {
    setActiveBio(activeBio === memberId ? null : memberId);
  };

  // Animation variants
  const menuVars = {
    initial: {
      scaleY: 0,
      opacity: 0,
    },
    animate: {
      scaleY: 1,
      opacity: 1,
      transition: {
        duration: 0.3,
        ease: "easeOut",
      },
    },
    exit: {
      scaleY: 0,
      opacity: 0,
      transition: {
        duration: 0.3,
        ease: "easeIn",
      },
    },
  };

  return (
    <div className="w-full max-w-4xl mx-auto p-4">
      <div className="border border-gray-200 rounded-lg p-6 mb-8">
        <div className="grid grid-cols-1 sm:grid-cols-2 md:grid-cols-4 gap-4 mb-4">
          {members.map((member) => (
            <div 
              key={member.id}
              className="border border-gray-200 rounded-lg overflow-hidden cursor-pointer transition-transform duration-300 hover:-translate-y-1 hover:shadow-lg"
              onClick={() => handleCardClick(member.id)}
            >
              <div className="bg-gray-200 h-32 flex items-center justify-center">
                <div className="text-gray-500 text-lg">Image</div>
              </div>
              <div className="p-4 text-center">
                <h3 className="font-medium text-lg">{member.name}</h3>
                <p className="text-sm text-gray-600 mb-2">{member.role}</p>
                <button className="text-blue-600 text-sm">Read Bio</button>
              </div>
            </div>
          ))}
        </div>

        <AnimatePresence>
          {activeBio && (
            <motion.div
              key={activeBio}
              variants={menuVars}
              initial="initial"
              animate="animate"
              exit="exit"
              className="relative w-full border border-gray-200 rounded-lg overflow-hidden mb-4"
              style={{ transformOrigin: "top" }}
            >
              <div className="p-6 bg-gray-50 relative">
                <button 
                  className="absolute top-4 right-4 text-xl"
                  onClick={() => setActiveBio(null)}
                >
                  ✕
                </button>
                <p className="pr-8">{members.find(m => m.id === activeBio)?.bio}</p>
              </div>
            </motion.div>
          )}
        </AnimatePresence>
      </div>


    </div>
  );
};

export default AdvisoryBoardPreview;

Upvotes: 0

Related Questions