Stacking context with nested mapping in Typescript React using Framer Motion

I have an array of skill objects, some of which have an array of subskills. I'm using nested mapping to render them as cards, flexbox to lay them out, and Framer Motion to staggered-ly animate them on page load (I've tried to make this happen as the skills come into view instead, but that's a different problem). When you hover over each skill, its subskills (if they exist) are also mapped out as cards, but they are eclipsed by the parent skill cards. I can't seem to understand the stacking context of this component.

const Skills = () => {
    const [activeSkill, setActiveSkill] = useState<string | null>(null);

    const handleMouseEnter = (skillName: string) => {
        setActiveSkill(skillName);
    };
    const handleMouseLeave = () => {
        setActiveSkill(null);
    };


    return (
        <>
            <div className={ss.intro}>
                <h2 className={ss.title}>A Heading</h2>
                <p>
                    Some words
                </p>
            </div>
            <motion.div
                className={ss.skills}
                variants={containerVariants}
                initial='closed'
                animate='open'
                {/* style={{ zIndex: 1000 }} I've tried this. Dev tools says 'position: static' to blame for not applying z-index */}
            >  
                {skills.map(({ name, icon, subskills }) => (
                    <motion.div
                        key={name}
                        className={ss.skill}
                        onMouseEnter={() => handleMouseEnter(name)}
                        onMouseLeave={handleMouseLeave}
                        variants={dropdownVariants}    
                        {/* style={{ zIndex: 1000 }} I've tried this */}
                    >
                        <Tooltip message={name}>{icon}</Tooltip>

                        {/* Render subskills */}
                        <AnimatePresence>
                            {activeSkill === name &&
                                <motion.div
                                    className={ss.subskills}
                                    variants={containerVariants}
                                    initial='closed'
                                    animate='open'
                                    exit='closed'
                                    {/* style={{ zIndex: 1000 }} I've tried this */} 
                                >
                                    {subskills && subskills.map(({
                                        name, icon
                                    }) => (
                                        <motion.div
                                            key={name}
                                            className={ss.subskill}
                                            variants={dropdownVariants}
                                            initial='closed'
                                            animate='open'
                                            exit='closed'
                                            onMouseEnter={
                                                () => handleMouseEnter(name)
                                            }
                                            onMouseLeave={handleMouseLeave}
                                            {/* style={{ zIndex: 1000 }} I've tried this */}
                                        >
                                            <Tooltip message={name}>
                                                {icon}
                                            </Tooltip>
                                        </motion.div>
                                    ))}
                                </motion.div>
                            }
                        </AnimatePresence>
                    </motion.div>
                ))}
            </motion.div>
        </>
    );
}; 

I've tried setting zIndex and z (this is fine in Framer Motion, it's basically translateZ()) in the style attribute in every layer of div tags, both individually and globally and in every combination I could think of. I've also tried setting z-index inside their respective class properties in the stylesheet (I'm using modules, so the cascade it a lot more manageable). I've also set ascending z-index values as I worked my way down into more nested elements. None of this worked.

I noticed that when I set the z-index to the element.style selector in the Dev Tools, then the subskills get rendered above what they need to, but only the subskills of the first skill card that I'm inspecting. The others are still eclipsed. What's more is that I can start at, say, 20 and it'll work, move it up to 30 and it'll work, but move it back down to 20 and they get eclipsed again. I'm not sure what else to do or how to understand what's going on.

Upvotes: 0

Views: 10

Answers (0)

Related Questions