<div id="root"></div>
* {
    box-sizing: border-box;
}
.team-member {
    display: inline-block;
    position: relative;
}
.team-content {
    padding: 0;
    position: relative;
    z-index: 1;
    margin-top: 0;
    margin-bottom: 0px;
    width: 320px;
    text-align: center;
}
.team-content button {
    background-color: transparent;
    border: none;
    color: currentColor;
    -webkit-appearance: none;
}
.team-content .toggle-button * {
    text-decoration: underline;
}
.team-image {
    display: block;
    width: 190px;
    height: 190px;
    overflow: hidden;
    margin: auto;
    margin-top: 60px;
    margin-bottom: 20px;
    border-radius: 90px;
    box-shadow: 0 6px 20px rgba(0, 0, 0, 0.07);
    text-align: center;
}
.team-content .team-name {
    display: block;
    font-size: 18px;
    font-weight: 700;
    line-height: 1;
    margin: 0;
    margin-bottom: 10px;
}
.team-content .team-subtitle {
    margin-bottom: 0px;
    display: block;
    font-size: 14px;
    font-style: italic;
    line-height: 1;
    color: inherit;
}
.team-member .team-image img {
    margin: 0 auto;
    border: none;
    height: auto;
    width: 100%;
}
.team-content-overlay {
    background-color: #1c6300;
    color: #fff;
    top: 0;
    padding: 40px 35px;
    position: absolute;
    width: 190px;
    overflow: hidden;
    min-height: 190px;
    max-height: 190px;
    height: auto;
    left: 60px;
    opacity: 0.5;
    visibility: hidden;
    -webkit-transition: 0.25s ease-in;
    -o-transition: 0.25s ease-in;
    transition: 0.25s ease-in;
    z-index: 100;
    border-radius: 90px;
}
.active .team-content-overlay {
    opacity: 1;
    visibility: visible;
    margin-left: calc(95px - 50%);
    margin-top: 30px;
    max-height: 400px;
    width: 100%;
    height: auto;
    border-radius: 10px;
}
.team-content-overlay .gradient-overlay {
    position: absolute;
    width: 100%;
    height: 100%;
    z-index: 0;
    top: 0;
    left: 0;
}
.team-content .team-content-overlay .team-name {
    font-size: 18px;
    font-weight: 700;
    position: relative;
}
.team-content .team-content-overlay .team-subtitle {
    position: relative;
}
.team-close-button {
    border: none;
    font-weight: bold;
    position: absolute;
    top: 10px;
    right: 10px;

    &:focus {
      outline: 3px solid lightblue;
    }
}
.team-content-overlay p {
    color: #fff;
    opacity: 0;
    font-size: 8px;
    font-weight: 400;
    line-height: 22px;
    position: relative;
    font-size: 12px;
    // -webkit-transition: 0.25s ease-in;
    // -o-transition: 0.25s ease-in;
    // transition: 0.25s ease-in;
}
.active .team-content-overlay p {
    opacity: 1;
    font-size: 12px;
}
.team-socials {
    position: relative;
    margin: auto;
    margin-top: 45px;
    width: 100%;
    z-index: 101;
    text-align: center;
    line-height: 12px;
}
.team-socials a {
    color: #225165;
    outline: 0;
    text-decoration: none;
}
.team-socials svg {
    margin: 0 10px;
    width: 25px;
}
View Compiled

function CardFlip (props) {
    let toggleButtonRef = React.useRef(null)
    let closeButtonRef = React.useRef(null)
    let overlayRef = React.useRef(null)

    const [ isActive, setIsActive ] = React.useState(false)
    const [transitionStatus, changeTransitionStatus] = React.useState(0)
    
    React.useEffect(() => {
      const handler = (event) => {
        // you can listen for any animatable CSS property here!
        // Note: opacity alone is not enough to properly disable hidden content still in the DOM.
        if (event.propertyName === "opacity" && closeButtonRef.current !== null) {
          closeButtonRef.current.focus()
        }
      }
      window.addEventListener("transitionend", handler)
    }, [])
    const handleClick = (event) => {
        setIsActive(!isActive)
    }
    const closeOverlay = () => {
        setIsActive(false)
        toggleButtonRef.current.focus()
    }

    const activeClass = isActive ? "active" : ""
    // todo: reimplement focus trap
    const overlay = isActive
        ? <div>
            <div>
            <div className="gradient-overlay"></div>
            <button
                className="team-close-button"
                aria-label={`Close ${props.memberName}`}
                onClick={closeOverlay}
                ref={closeButtonRef}>X</button>
            <h5 className="team-name">{props.memberName}</h5>
            <span className="team-subtitle">{props.subtitle}</span>
            <p>{props.bio}</p>
            <div className="team-socials">
                <a href={props.twitterLink} target=" _blank" title="">
                  <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 404.98 404.98"><path d="M340.73 115.23a112.014 112.014 0 0 1-32.21 8.83c11.58-6.94 20.47-17.93 24.66-31.03a112.12 112.12 0 0 1-35.62 13.61c-10.23-10.9-24.81-17.71-40.94-17.71-30.98 0-56.09 25.11-56.09 56.09 0 4.4.5 8.68 1.45 12.78-46.62-2.34-87.94-24.67-115.61-58.6-4.83 8.28-7.59 17.92-7.59 28.2 0 19.46 9.9 36.63 24.95 46.69a55.803 55.803 0 0 1-25.41-7.02v.71c0 27.18 19.33 49.85 44.99 55a56.259 56.259 0 0 1-14.78 1.97c-3.61 0-7.13-.35-10.55-1.01 7.14 22.28 27.85 38.5 52.4 38.95-19.2 15.04-43.38 24.01-69.66 24.01-4.53 0-8.99-.27-13.38-.78 24.82 15.91 54.3 25.2 85.98 25.2 103.17 0 159.58-85.47 159.58-159.59 0-2.43-.05-4.85-.16-7.26a113.994 113.994 0 0 0 27.99-29.04z" fill="#fff"/></svg>
                </a>
            </div>
        </div>
        </div>
    : false
    return (
        <div className="team-member">
            <div className={`team-content ${activeClass}`}>
                <button className="toggle-button"
                    onClick={handleClick}
                    ref={toggleButtonRef}
                >
                    <span className="team-image">
                        <img src={props.image} alt="" />
                    </span>
                    <span className="team-name">{props.memberName}</span>
                    <span className="team-subtitle">{props.subtitle}</span>
                </button>

                <div role="dialog"
                    className="team-content-overlay"
                  ref={overlayRef}
                >
                    {overlay}
                </div>
            </div>
        </div>
    )
}

var friends = [{name: 'Rainier McCheddarton',
    headshot: 'https://s3-us-west-2.amazonaws.com/s.cdpn.io/68133/rainier-headshot.jpg',
    subtitle: 'Labradoodle, squeaker, cheese fan',
    bio: 'Doggo ipsum very hand that feed shibe heckin good boys and girls fat boi much ruin diet you are doing me the shock wrinkler length boy, I am bekom fat lotsa pats dat tungg tho shooberino.',
    twitterLink: 'http://twitter.com'
}]
ReactDOM.render(<CardFlip 
        member={friends[0]}
        memberName={friends[0].name}
        image={friends[0].headshot}
        subtitle={friends[0].subtitle}
        bio={friends[0].bio}
        twitterLink={friends[0].twitterLink} 
 />, document.getElementById('root'));
View Compiled

External CSS

This Pen doesn't use any external CSS resources.

External JavaScript

  1. https://cdnjs.cloudflare.com/ajax/libs/react/16.8.6/umd/react.production.min.js
  2. https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.6/umd/react-dom.production.min.js
  3. https://cdnjs.cloudflare.com/ajax/libs/what-input/5.2.1/what-input.min.js