<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;
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;
transition: 0.25s ease-in;
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
This Pen doesn't use any external CSS resources.