<!-- A recreation of a micro-interaction designed by Lu Yuhang [7ahang] -->
<!-- https://dribbble.com/shots/11983664-Folder-Open-Animation -->
<div class="folder" id="js_folder">
<div class="folder-summary" id="js_toggle-folder">
<div class="folder-summary__start">
<button class="folder-collapse-button" id="js_folder-collapse-button">
<svg id="js_folder-collapse-button-icon" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-chevron-up">
<polyline points="18 15 12 9 6 15"></polyline>
</svg>
</button>
<div class="folder-summary__file-count" id="js_folder-summary-amount">
<span class="folder-summary__file-count__amount">3</span>
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="currentColor" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-folder">
<path d="M22 19a2 2 0 0 1-2 2H4a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h5l2 3h9a2 2 0 0 1 2 2z"></path>
</svg>
</div>
</div>
<div class="folder-summary__details">
<div class="folder-summary__details__name">
Portfolio
</div>
<div class="folder-summary__details__share">
Design by
<a class="shared-user" href="https://dribbble.com/7ahang" target="_blank" rel="noopener noreferrer">
<svg class="shared-user__avatar" width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<circle cx="12" cy="12" r="12" fill="#1C213E" />
<circle cx="12" cy="12" fill="#BFBFC0" r="6.168" />
<circle cx="12.561" cy="11.439" r="5.607" fill="url(#paint0_radial)" fill-opacity=".5" />
<defs>
<radialGradient id="paint0_radial" cx="0" cy="0" r="1" gradientUnits="userSpaceOnUse" gradientTransform="rotate(109.486 3.244 10.282) scale(7.73263)">
<stop stop-color="#758EA9" />
<stop offset="1" stop-color="#668097" stop-opacity="0" />
</radialGradient>
</defs>
</svg>
<span class="shared-user__name">7ahang</span>
</a>
</div>
</div>
<div class="folder-summary__end">
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
<path d="M6 12c0 1.657-1.343 3-3 3s-3-1.343-3-3 1.343-3 3-3 3 1.343 3 3zm9 0c0 1.657-1.343 3-3 3s-3-1.343-3-3 1.343-3 3-3 3 1.343 3 3zm9 0c0 1.657-1.343 3-3 3s-3-1.343-3-3 1.343-3 3-3 3 1.343 3 3z" /></svg>
</div>
</div>
<ul class="folder-content" id="js_folder-content">
<li class="folder-item js_folder-item">
<div class="folder-item__icon">
<svg width="50" height="70" viewBox="0 0 50 70" fill="none" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" clip-rule="evenodd" d="M33 0H5a5 5 0 00-5 5v60a5 5 0 005 5h40a5 5 0 005-5V17L33 0z" fill="#5085E8" />
<path d="M50 29L35 16l15 .867V29z" fill="url(#paint0_linear)" opacity=".1" />
<path fill-rule="evenodd" clip-rule="evenodd" d="M33 0l17 17H38a5 5 0 01-5-5V0z" fill="#A4BEF6" />
<path fill="#fff" fill-opacity=".75" d="M13 39h24v3H13zM13 57h17v3H13zM13 51h24v3H13zM13 45h24v3H13z" />
<defs>
<linearGradient id="paint0_linear" x1="42.5" y1="16" x2="42.5" y2="29" gradientUnits="userSpaceOnUse">
<stop />
<stop offset="1" stop-opacity="0" />
</linearGradient>
</defs>
</svg>
</div>
<div class="folder-item__details">
<div class="folder-item__details__name">
Graduate-reports.doc
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="#ecc31c" stroke-widt class="feather feather-star">
<polygon points="12 2 15.09 8.26 22 9.27 17 14.14 18.18 21.02 12 17.77 5.82 21.02 7 14.14 2 9.27 8.91 8.26 12 2"></polygon>
</svg>
</div>
<div class="folder-item__details__date">Created 2020.4.25</div>
</div>
<div class="folder-item__size">16.7 MB</div>
</li>
<li class="folder-item js_folder-item">
<div class="folder-item__icon">
<svg width="50" height="70" viewBox="0 0 50 70" fill="none" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" clip-rule="evenodd" d="M33 0H5a5 5 0 00-5 5v60a5 5 0 005 5h40a5 5 0 005-5V17L33 0z" fill="#36A95E" />
<path d="M50 29L35 16l15 .867V29z" fill="url(#paint0_linear)" opacity=".1" />
<path fill-rule="evenodd" clip-rule="evenodd" d="M33 0l17 17H38a5 5 0 01-5-5V0z" fill="#A0D0B3" />
<path fill-rule="evenodd" clip-rule="evenodd" d="M12 60V39h25v21H12zm14-3h8v-3h-8v3zm-3-3v3h-8v-3h8zm3-3h8v-3h-8v3zm-3-3v3h-8v-3h8zm3-3h8v-3h-8v3zm-3-3v3h-8v-3h8z" fill="#fff" fill-opacity=".75" />
<defs>
<linearGradient id="paint0_linear" x1="42.5" y1="16" x2="42.5" y2="29" gradientUnits="userSpaceOnUse">
<stop />
<stop offset="1" stop-opacity="0" />
</linearGradient>
</defs>
</svg>
</div>
<div class="folder-item__details">
<div class="folder-item__details__name">
Festival Visual Design.xlsx
</div>
<div class="folder-item__details__date">
Created 2020.5.17
</div>
</div>
<div class="folder-item__size">
216.5 MB
</div>
</li>
<li class="folder-item js_folder-item">
<div class="folder-item__icon">
<svg width="50" height="70" viewBox="0 0 50 70" fill="none" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" clip-rule="evenodd" d="M33 0H5a5 5 0 00-5 5v60a5 5 0 005 5h40a5 5 0 005-5V17L33 0z" fill="#E8B52C" />
<path d="M50 29L35 16l15 .867V29z" fill="url(#paint0_linear)" opacity=".1" />
<path fill-rule="evenodd" clip-rule="evenodd" d="M33 0l17 17H38a5 5 0 01-5-5V0z" fill="#EEDA86" />
<path fill-rule="evenodd" clip-rule="evenodd" d="M34 39H13v21h24V39h-3zM16 54.75h18v-10.5H16v10.5z" fill="#fff" fill-opacity=".75" />
<defs>
<linearGradient id="paint0_linear" x1="42.5" y1="16" x2="42.5" y2="29" gradientUnits="userSpaceOnUse">
<stop />
<stop offset="1" stop-opacity="0" />
</linearGradient>
</defs>
</svg>
</div>
<div class="folder-item__details">
<div class="folder-item__details__name">
Portfolio 2020.ppt
</div>
<div class="folder-item__details__date">
Created 2020.6.7
</div>
</div>
<div class="folder-item__size">
25.8 MB
</div>
</li>
</ul>
</div>
@import url("https://fonts.googleapis.com/css2?family=Noto+Sans+TC:wght@400;500&display=swap");
html {
box-sizing: border-box;
}
*, *:before, *:after {
box-sizing: inherit;
}
html,
body {
height: 100%;
width: 100%;
}
body {
background: #efeff0;
font-family: "Noto Sans TC", sans-serif;
font-weight: 400;
display: flex;
align-items: center;
justify-content: center;
}
// ------- FOLDER
.folder {
background: #ffffff;
border-radius: 10px;
box-shadow: 0 20px 25px -5px rgba(0, 0, 0, 0.1),
0 10px 10px -5px rgba(0, 0, 0, 0.04);
overflow: hidden;
width: 450px;
}
// ------ SHARED USER
.shared-user {
align-items: center;
color: #6a696a;
display: inline-flex;
font-weight: 500;
margin-left: 5px;
outline: none;
text-decoration: none;
&__avatar {
width: 15px;
height: 15px;
margin-right: 3px;
}
}
// ------- FOLDER SUMMARY
.folder-summary {
padding: 15px 20px 15px 15px;
cursor: pointer;
display: flex;
line-height: 1;
height: 80px;
position: relative;
&__start {
position: relative;
}
&__file-count {
position: absolute;
top: -3px;
&__amount {
color: #ffffff;
font-size: 12px;
left: 50%;
position: absolute;
top: 50%;
transform: translate(-50%, -50%);
}
svg {
color: #5166fa;
height: 30px;
width: auto;
}
}
&__details {
padding: 2px 0 0 13px;
&__name {
color: #393738;
font-size: 20px;
font-weight: 500;
}
&__share {
align-items: center;
color: #b5b4b5;
display: flex;
font-size: 15px;
margin-top: 8px;
}
}
&__end {
margin-left: auto;
svg {
fill: #c3c2c3;
}
}
&::after {
background: #e6e6e6;
bottom: -2px;
content: "";
height: 2px;
left: 0;
position: absolute;
right: 0;
}
}
// ------- CHEVRON BUTTON
.folder-collapse-button {
appearance: none;
background: transparent;
border-radius: 30px;
border: 0;
cursor: pointer;
height: 30px;
opacity: 0;
outline: none;
position: absolute;
position: relative;
width: 30px;
z-index: 1;
&::after {
background: #efeff0;
border-radius: 40px;
content: "";
height: 35px;
left: 50%;
opacity: 0;
position: absolute;
top: 50%;
transform: translate(-50%, -50%);
transition: all 0.2s ease-out;
width: 35px;
}
&:hover::after {
opacity: 1;
}
svg {
color: #9c9c9e;
left: 50%;
position: absolute;
stroke-width: 3;
top: 50%;
transform: translate(-50%, -50%);
z-index: 2;
}
}
// ------------ FOLDER ITEM
.folder-item {
align-items: flex-start;
display: flex;
height: 80px;
line-height: 1;
opacity: 0;
padding: 20px 25px;
position: relative;
&__icon svg {
display: block;
height: 40px;
width: auto;
}
&__details {
padding: 1px 0 0 15px;
&__name {
color: #393738;
font-size: 17px;
font-weight: 500;
position: relative;
svg {
height: auto;
position: absolute;
top: 50%;
transform: translate(5px, calc(-50% + 1px));
width: 20px;
}
}
&__date {
color: #b5b4b5;
font-size: 15px;
margin-top: 8px;
}
}
&__size {
color: #6a696a;
font-weight: 500;
margin-left: auto;
margin-top: 2px;
}
&:not(:last-child)::after {
background: #edecee;
bottom: 0;
content: "";
height: 1px;
left: 80px;
position: absolute;
right: 0;
}
}
View Compiled
const toggleFolder = document.getElementById("js_toggle-folder");
// --------- ANIMATION
const showFolderContentAnimation = anime.timeline({
easing: "easeOutCubic",
autoplay: false
});
showFolderContentAnimation
.add({
targets: "#js_folder-content",
height: [0, 240],
duration: 350
})
.add(
{
targets: "#js_folder-summary-amount",
opacity: [1, 0],
duration: 400
},
"-=350"
)
.add(
{
targets: "#js_folder-collapse-button",
opacity: [0, 1],
duration: 400
},
"-=300"
)
.add(
{
targets: "#js_folder-collapse-button-icon",
duration: 300,
translateX: ["-50%", "-50%"],
translateY: ["-50%", "-50%"],
rotate: ["0deg", "180deg"]
},
"-=400"
)
.add(
{
targets: ".js_folder-item",
translateY: [20, 0],
opacity: [0, 1],
duration: 300,
delay: (el, i, l) => i * 120
},
"-=275"
);
// --------- TRIGGER
toggleFolder.addEventListener("click", () => {
if (showFolderContentAnimation.began) {
showFolderContentAnimation.reverse();
if (
showFolderContentAnimation.progress === 100 &&
showFolderContentAnimation.direction === "reverse"
) {
showFolderContentAnimation.completed = false;
}
}
if (showFolderContentAnimation.paused) {
showFolderContentAnimation.play();
}
});
This Pen doesn't use any external CSS resources.