Animated Fly-In Navigation Menu
A smooth animated navigation menu with staggered fly-in items, CodeRipple menu links and responsive interaction.
<div class="cr-slide-menu-wrap">
<button class="cr-menu-toggle" type="button">
<span class="cr-menu-toggle-icon">☰</span>
<span>Toggle Menu</span>
</button>
<nav class="cr-slide-menu">
<div class="cr-slide-menu-head">
<span>CodeRipple</span>
<button
class="cr-menu-close"
type="button"
aria-label="Close menu">
×
</button>
</div>
<ul class="cr-menu-list">
<li>
<a href="#" class="active">Home</a>
</li>
<li>
<a href="#">Components</a>
</li>
<li>
<a href="#">Categories</a>
</li>
<li>
<a href="#">Playground</a>
</li>
<li>
<a href="#">Blog</a>
</li>
<li>
<a href="#">About</a>
</li>
</ul>
</nav>
</div>
.cr-slide-menu-wrap{
position:relative;
min-height:620px;
display:flex;
align-items:flex-start;
justify-content:flex-start;
padding:40px;
overflow:visible;
background:#08111f;
border-radius:18px;
}
.cr-menu-toggle{
display:inline-flex;
align-items:center;
gap:10px;
padding:12px 18px;
border:1px solid #24344d;
border-radius:10px;
background:#0d1727;
color:#ffffff;
font-size:14px;
font-weight:700;
cursor:pointer;
}
.cr-menu-toggle-icon{
color:#22d3ee;
font-size:18px;
}
.cr-slide-menu{
position:absolute;
top:24px;
left:24px;
width:290px;
min-height:520px;
padding:22px 18px;
background:linear-gradient(
180deg,
#0d1727 0%,
#08111f 100%
);
border:1px solid #1f3048;
border-radius:16px;
box-shadow:0 25px 60px rgba(0,0,0,.45);
transform:translateX(-70px) scale(.96);
opacity:0;
visibility:hidden;
transition:
transform .4s cubic-bezier(.2,.8,.2,1),
opacity .3s ease,
visibility .3s ease;
}
.cr-slide-menu.is-open{
transform:translateX(0) scale(1);
opacity:1;
visibility:visible;
}
.cr-slide-menu-head{
display:flex;
align-items:center;
justify-content:space-between;
margin-bottom:24px;
padding:0 4px 15px;
border-bottom:1px solid rgba(255,255,255,.08);
}
.cr-slide-menu-head span{
color:#ffffff;
font-size:18px;
font-weight:800;
}
.cr-menu-close{
width:34px;
height:34px;
display:flex;
align-items:center;
justify-content:center;
padding:0;
border:1px solid #273850;
border-radius:8px;
background:#111c2d;
color:#8fa0b7;
font-size:22px;
cursor:pointer;
}
.cr-menu-list{
list-style:none;
margin:0;
padding:0;
}
.cr-menu-list > li{
margin-bottom:7px;
opacity:0;
transform:translateX(-28px);
transition:
opacity .35s ease,
transform .35s cubic-bezier(.2,.8,.2,1);
}
.cr-menu-list a{
display:block;
padding:11px 14px;
border-radius:9px;
color:#98a7bc;
font-size:14px;
font-weight:600;
text-decoration:none;
}
.cr-menu-list a:hover{
color:#ffffff;
background:#101c2e;
}
.cr-menu-list > li > a.active{
color:#ffffff;
background:linear-gradient(
90deg,
rgba(34,211,238,.18),
rgba(168,85,247,.18)
);
border:1px solid rgba(34,211,238,.22);
}
.cr-slide-menu.is-open
.cr-menu-list > li:nth-child(1){
opacity:1;
transform:translateX(0);
transition-delay:.12s;
}
.cr-slide-menu.is-open
.cr-menu-list > li:nth-child(2){
opacity:1;
transform:translateX(0);
transition-delay:.28s;
}
.cr-slide-menu.is-open
.cr-menu-list > li:nth-child(3){
opacity:1;
transform:translateX(0);
transition-delay:.44s;
}
.cr-slide-menu.is-open
.cr-menu-list > li:nth-child(4){
opacity:1;
transform:translateX(0);
transition-delay:.60s;
}
.cr-slide-menu.is-open
.cr-menu-list > li:nth-child(5){
opacity:1;
transform:translateX(0);
transition-delay:.76s;
}
.cr-slide-menu.is-open
.cr-menu-list > li:nth-child(6){
opacity:1;
transform:translateX(0);
transition-delay:.92s;
}
@media(max-width:600px){
.cr-slide-menu-wrap{
min-height:600px;
padding:20px;
}
.cr-slide-menu{
top:15px;
left:15px;
width:calc(100% - 30px);
max-width:290px;
min-height:500px;
}
}
const slideMenuWrap =
document.querySelector('.cr-slide-menu-wrap');
if (slideMenuWrap) {
const menu =
slideMenuWrap.querySelector('.cr-slide-menu');
const toggle =
slideMenuWrap.querySelector('.cr-menu-toggle');
const close =
slideMenuWrap.querySelector('.cr-menu-close');
if (toggle && menu) {
toggle.addEventListener('click', function () {
menu.classList.toggle('is-open');
});
}
if (close && menu) {
close.addEventListener('click', function () {
menu.classList.remove('is-open');
});
}
const menuLinks =
slideMenuWrap.querySelectorAll(
'.cr-menu-list a'
);
menuLinks.forEach(function (link) {
link.addEventListener('click', function (e) {
e.preventDefault();
menuLinks.forEach(function (item) {
item.classList.remove('active');
});
link.classList.add('active');
});
});
}
How This Animated Fly-In Navigation Menu Works
The Animated Fly-In Navigation Menu is a compact side-style navigation panel that enters from the left when the user clicks a toggle button. Its HTML contains three main parts: the external toggle button, the navigation panel itself, and a six-item menu containing Home, Components, Categories, Playground, Blog, and About links.
The .cr-slide-menu-wrap acts as the positioning container. It uses position: relative, which allows .cr-slide-menu to be positioned absolutely at top: 24px and left: 24px. The demo area has a dark #08111f background, 40px padding, and a minimum height of 620px.
The navigation panel is 290px wide with a minimum height of 520px. Its background transitions vertically from #0d1727 to #08111f, while a subtle border, 16px border radius, and large shadow separate it from the surrounding area. Before opening, the menu uses translateX(-70px) scale(.96), opacity: 0, and visibility: hidden. This places it slightly to the left while also making it invisible and unavailable visually.
When JavaScript adds the is-open class, the transform changes to translateX(0) scale(1), opacity becomes 1, and visibility becomes visible. The transform takes .4s and uses cubic-bezier(.2,.8,.2,1), while opacity and visibility use .3s transitions. This combination creates the fly-in effect without relying on CSS keyframes. For more detail about this approach, see the MDN CSS transitions documentation.
The individual menu items have their own entrance animation. Every list item starts at translateX(-28px) with zero opacity. Once the parent menu receives is-open, the items return to translateX(0) and become fully visible. Different transition-delay values create the staggered sequence: the first link begins at .12s, followed by .28s, .44s, .60s, .76s, and finally .92s for the sixth item.
The navigation also includes visual active and hover states. A normal link uses the muted #98a7bc text color. Hovering changes its text to white and adds a dark background. The active link receives a cyan-to-purple transparent gradient, white text, and a subtle cyan border. Home has the active class in the initial HTML.
JavaScript manages both the panel and link states. It first finds .cr-slide-menu-wrap, then searches within it for the menu, toggle button, and close button. Clicking the toggle runs classList.toggle('is-open'), allowing the same button to open or close the panel. Clicking the × button explicitly removes is-open.
Each menu link also receives a click listener. The script calls preventDefault(), removes active from every menu link, and then adds active to the selected link. This demo therefore updates the visual selection but does not navigate to another page.
For smaller screens, a media query at 600px reduces the wrapper padding and repositions the panel to 15px from the top and left. Its width becomes calc(100% - 30px) with a maximum width of 290px, allowing it to fit narrow displays without becoming wider than the desktop version.
Customizing the Animated Fly-In Navigation Menu
The component can be adjusted through its existing CSS and HTML values while keeping the same JavaScript behavior.
- Change the
290pxmenu width and520pxminimum height to create a different panel size. - Modify
translateX(-70px)to control how far from the left the menu begins its fly-in animation. - Adjust the
.4stransform duration to make the main panel enter faster or slower. - Edit the
.12sthrough.92stransition delays to change the staggered timing of the six links. - Change the cyan and purple active-state colors in the
linear-gradient()to match another interface theme. - Replace Home, Components, Categories, Playground, Blog, and About with the navigation labels required by your project.
- Adjust the
600pxmedia-query breakpoint or the mobile15pxoffsets to fit a different responsive layout.
Where to Use This Animated Fly-In Navigation Menu
The menu works well when navigation needs to stay out of the main interface until the visitor chooses to open it.
- Developer dashboards and web tools
- Portfolio and personal websites
- Compact application navigation
- Component libraries and documentation interfaces
- Dark-themed landing pages
- Mobile-friendly navigation layouts
The staggered links make the component particularly suitable for a short navigation list where each option should remain easy to scan. If you prefer a menu that expands links around a central button instead, the Radial Social Media Menu provides a different compact navigation pattern.
Frequently Asked Questions
Does the Animated Fly-In Navigation Menu use JavaScript?
Yes. JavaScript toggles the is-open class on the menu, handles the dedicated close button, and changes the active state when a navigation link is clicked.
How is the staggered fly-in effect created?
Each list item starts with zero opacity and translateX(-28px). When the menu opens, the items move to translateX(0) and become visible. Increasing transition delays from .12s to .92s make them appear one after another.
Does clicking a menu link navigate to another page?
Not in the current component. Every link uses href="#", and the JavaScript calls preventDefault() when a link is clicked. The click only changes which link has the active class.
Is the Animated Fly-In Navigation Menu responsive?
Yes. Below 600px, the wrapper uses less padding and the menu switches to width: calc(100% - 30px), while retaining a max-width of 290px.
The Animated Fly-In Navigation Menu combines CSS transforms, opacity transitions, staggered delays, and straightforward JavaScript class handling to create an animated navigation panel with selectable menu items.
