I have got follow html:
nav {
width: 100px;
}
.nav-menu {
background-color: orange;
}
.dropdown {
position: relative;
}
a[data-toggle="dropdown"] {
display: flex;
align-items: center;
background: transparent;
color: blue;
padding: 10px 15px;
border-radius: 4px;
transition: background 0.3s ease;
white-space: nowrap;
}
a[data-toggle="dropdown"]:hover {
color: black;
}
.nav-menu {
display: flex;
flex-wrap: wrap;
gap: 10px;
list-style-type: none;
padding: 0;
margin: 0;
align-items: center;
width: 100%;
}
.dropdown-menu {
list-style: none;
padding: 10px 15px;
margin: 0;
position: absolute;
top: 100%;
left: 0;
min-width: 200px;
background: #ffffff;
box-shadow: 0 4px 10px rgba(0, 0, 0, 0.15);
border-radius: 6px;
overflow: hidden;
transform: scaleY(0);
transform-origin: top;
opacity: 0;
transition: transform 0.3s ease, opacity 0.3s ease;
z-index: 1000;
}
.dropdown-menu.show {
transform: scaleY(1);
opacity: 1;
}
.dropdown-menu:before {
display: block;
position: absolute;
top: 0;
right: 0;
bottom: 0;
left: 0;
clip-path: inset(0 0 0 0);
}
<nav>
<ul class="nav-menu">
<li class="dropdown">
<a href="#" data-toggle="dropdown">About</a>
<ul class="dropdown-menu">
<li><a href="/foo.html">Foo</a></li>
<li><a href="/bar.html">Bar</a></li>
<li><a href="/bar.html">Some long text here</a></li>
</ul>
</li>
</ul>
</nav>
But I want to make menu be shown no wider than the dimensions of the container (orange color). The menu must always fit into the container.
https://jsfiddle.net/Suliman123/8tg67sq4/
If menu is longer that container text menu it's text should be fully displayed. In my case there is a lot of menu items. And if no space from right it always have space from left.
Here is illustration: https://jsfiddle.net/Suliman123/Lno7a5p0/ menu here should not be bigger than black region.
We use offsetWidth
property in JS to calculate the width of the button - then the event listener in js will apply this width to the dropdown using style.width
property.
You need to make these changes in CSS in the .dropdown-menu:
width: auto;
min-width: unset;
This will remove any preset width or min-width in the CSS and will let the JS add on to your CSS.
This will be your updated JS:
document.querySelectorAll('.dropdown').forEach((dropdown) => {
const button = dropdown.querySelector('a[data-toggle="dropdown"]');
const menu = dropdown.querySelector('.dropdown-menu');
button.addEventListener('click', (event) => {
event.preventDefault();
document.querySelectorAll('.dropdown-menu.show').forEach((openMenu) => {
if (openMenu !== menu) {
openMenu.classList.remove('show');
}
});
const buttonWidth = button.offsetWidth;
menu.style.width = `${buttonWidth}px`;
menu.classList.toggle('show');
});
});
// to close the dropdown when clicked anywhere else on the page
document.addEventListener('click', (event) => {
if (!event.target.closest('.dropdown')) {
document.querySelectorAll('.dropdown-menu.show').forEach((menu) => {
menu.classList.remove('show');
});
}
});
Your complete HTML, CSS and JS would become:
document.querySelectorAll('.dropdown').forEach((dropdown) => {
const button = dropdown.querySelector('a[data-toggle="dropdown"]');
const menu = dropdown.querySelector('.dropdown-menu');
button.addEventListener('click', (event) => {
event.preventDefault();
document.querySelectorAll('.dropdown-menu.show').forEach((openMenu) => {
if (openMenu !== menu) {
openMenu.classList.remove('show');
}
});
const buttonWidth = button.offsetWidth;
menu.style.width = `${buttonWidth}px`;
// Toggle the visibility of the dropdown menu
menu.classList.toggle('show');
});
});
document.addEventListener('click', (event) => {
if (!event.target.closest('.dropdown')) {
document.querySelectorAll('.dropdown-menu.show').forEach((menu) => {
menu.classList.remove('show');
});
}
});
nav {
width: 100px;
}
.nav-menu {
background-color: orange;
}
.dropdown {
position: relative;
}
a[data-toggle="dropdown"] {
display: flex;
align-items: center;
background: transparent;
color: blue;
padding: 10px 15px;
border-radius: 4px;
transition: background 0.3s ease;
white-space: nowrap;
}
a[data-toggle="dropdown"]:hover {
color: black;
}
.nav-menu {
display: flex;
flex-wrap: wrap;
gap: 10px;
list-style-type: none;
padding: 0;
margin: 0;
align-items: center;
width: 100%;
}
.dropdown-menu {
list-style: none;
padding: 10px 15px;
margin: 0;
position: absolute;
top: 100%;
left: 0;
background: #ffffff;
box-shadow: 0 4px 10px rgba(0, 0, 0, 0.15);
border-radius: 6px;
overflow: hidden;
transform: scaleY(0);
transform-origin: top;
opacity: 0;
transition: transform 0.3s ease, opacity 0.3s ease;
z-index: 1000;
/* just need to add this - this will remove any preset width or min-width */
width: auto;
min-width: unset;
}
.dropdown-menu.show {
transform: scaleY(1);
opacity: 1;
}
.dropdown-menu:before {
/* content: ""; */
display: block;
position: absolute;
top: 0;
right: 0;
bottom: 0;
left: 0;
clip-path: inset(0 0 0 0);
}
<!-- UNCHANGED - NOTHING NEEDS TO BE CHANGED HERE IN HTML -->
<nav>
<ul class="nav-menu">
<li class="dropdown">
<a href="#" data-toggle="dropdown">About</a>
<ul class="dropdown-menu">
<li><a href="/foo.html">Foo</a></li>
<li><a href="/bar.html">Bar</a></li>
</ul>
</li>
</ul>
</nav>