Flexbox for creating pop-up menus

I'm currently working on creating a header component using FlexBox. Here is a visual representation of what I am aiming for:

https://i.sstatic.net/wRFHR.png

The red box represents a flexbox, while the green boxes are individual <div> elements within the flexbox. The element on the far right (labeled as 3) is linked to a click event. The goal is for a menu to appear directly below this box, but not within it, when clicked.

I've experimented with both absolute and relative positioning for divs 3 and 4, but I haven't been able to achieve the desired outcome. The closest I've come is using absolute positioning for div 4, which successfully creates a separate popup from div 3. However, div 4's width is limited by div 3 and the content wraps around.

Is there a way to create a popup element within div 4 that adjusts its width based on its content and doesn't wrap around?

Answer №1

If you are working with a simple markup structure as shown below, the best approach would likely involve using an absolutely positioned div

With this setup, your popup will be positioned outside the parent, without any restrictions on width/height

In this example, the popup is placed outside the third div, providing more flexibility in choosing its position based on responsiveness (various screen sizes, etc.)

For a script-based solution:

document.querySelector('.click').addEventListener('click', function(e){
  e.target.nextElementSibling.classList.toggle('clicked');
})
.parent {
  position: relative;
  display: flex;
  border: 1px solid red;
}
.parent div {
  flex: 2;
  border: 1px solid lime;
  margin: 1px;
}
.parent div:nth-child(2) {
  flex: 3;
}
.parent div:nth-child(3) {
  flex: 2;
}
.parent .popup {
  display: none;
  position: absolute;
  right: -2px;
  top: calc(100% + 3px);
  border: 1px solid blue;
}
.parent .popup.clicked {
  display: block;
}
<div class="parent">
  <div> 1 </div>
  <div> 2 </div>
  <div class="click"> 3 <br> (click to toggle) </div>
  <div class="popup"> This one can have text <br>
        that does pretty much what you want    
  </div>
</div>


Alternatively, this can be achieved without any script by utilizing a label and a checkbox

Updated Version

The popup will close when clicking anywhere on the page (Credits to I Love CSS)

.parent {
  position: relative;
  display: flex;
  border: 1px solid red;
}
.parent div {
  flex: 2;
  border: 1px solid lime;
  margin: 1px;
}
.parent div:nth-child(2) {
  flex: 3;
}
.parent div:nth-child(3) {
  flex: 2;
}
.parent .popup {
  display: none;
  position: absolute;
  right: -2px;
  top: calc(100% + 3px);
  border: 1px solid blue;
}
.parent .modal {
  display: none;
  position: fixed;
  left: 0;
  top: 0;
  right: 0;
  bottom: 0;
  background: white;
  opacity: 0.3;
}
.parent .click label[for=chkbox] {
  display: block;  
}
#chkbox {
  display: none;
}
#chkbox:checked ~ .modal,
#chkbox:checked ~ .popup {
  display: block;
}
<div class="parent">
  <div> 1 </div>
  <div> 2 </div>
  <div class="click"><label for="chkbox"> 3 <br> (click to toggle) </label></div>
  <input type="checkbox" id="chkbox">
  <label class="modal" for="chkbox"></label>
  <div class="popup"> This one can have text <br>
        that does pretty much what you want    
  </div>
</div>


Another script-less approach is implementing :focus

Updated Version

The popup will persist using :hover, allowing links to function as well (Credits to Andrei Gheorghiu)

.parent {
  position: relative;
  display: flex;
  border: 1px solid red;
}
.parent div {
  flex: 2;
  border: 1px solid lime;
  margin: 1px;
}
.parent div:nth-child(2) {
  flex: 3;
}
.parent div:nth-child(3) {
  flex: 2;
}
.parent .popup {
  display: none;
  position: absolute;
  right: -2px;
  top: calc(100% + 3px);
  border: 1px solid blue;
}
.click:focus + .popup {
  display: block;
}
.click + .popup:hover {
  display: block;
}
<div class="parent">
  <div> 1 </div>
  <div> 2 </div>
  <div class="click" tabindex="-1"> 3 <br> (click to toggle) </div>
  <div class="popup"> This one can have text <br>
        that does pretty much what you want <br><br>
        <a href="#" onclick="alert('hey');">links included</a>
  </div>
</div>

Answer №2

UPDATE 2: This configuration allows you to avoid hard-coding any top values on dropdowns, giving you more flexibility and ensuring alignment with the navbar stays consistent even when the viewport width changes.

$(".item-red").on("click", function() {
  $(".item-dropdown").toggleClass("display");
});
.container {
    display: flex;
    flex-flow: row wrap;
    text-align: center;
}
.item {
    flex: 2;
    padding: 5px;
    margin: 0;
}
.item-blue {
    background: lightblue;
}

.item-green {
    background: lightgreen;
    flex: 3;
}
.item-red {
    background: lightgray;
    flex: 1;
}
.item-red:hover {
    cursor: pointer;
}
.container-dropdown {
    display: flex;
    flex-flow: row wrap;
    position: relative;
    text-align: center;
}
.item-dropdown {
    width: 240px;
    display: none;
    background: gold;
    position: absolute;
    right: 0;
    z-index: 1;
    padding: 5px;
}
.display {
    display: flex;
}
.content {
    text-align: center;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="container">
    <div class="item item-blue">Lorem</div>
    <div class="item item-green">Lorem ipsum dolor kjghj</div>
    <div class="item item-red">Lorem ipsum dolor
    </div>
</div>
<div class="container-dropdown">
    <div class="item-dropdown">Lorem ipsum dolor sit amet, consectetur adipisicing elit. Fuga voluptate, ipsum consequuntur maiores unde laboriosam suscipit velit corporis.</div>
</div>
<div class="content">Content - lorem ipsum dolor sit amet, consectetur adipisicing elit. Quibusdam delen iti soluta qui, incidunt, neque est doloribus esse deserunt modi, mollitia delectus illum! Ullam nihil reiciendis animi eligendi nemo non. Incidunt.</div>

Answer №3

The behavior of dropdown menus is quite standard and does not depend on the specific display method used for the "menu bar" items (such as flexbox, grid, or table). The key conditions to consider are:

  • The parent element should have position:relative;
  • The child element should have position:absolute; top: 100%;
  • Whether the child should be visible on hover, or based on a specific class applied to the parent, is a matter of design preference and user experience.

By using negative margins, you can make the dropdown menus larger than their parent elements. You can even make them full-page size and create mega-menus, as they are absolutely positioned elements.

For instance, take a look at this sample code:

.menu {
  display: flex;
  background-color: white;
}
.menu > * {
  position: relative;
  flex: 1 0 auto;
  padding: 10px;
  border-right: 1px solid #eee;
  cursor: pointer;
}
.menu > *:last-child {
  border-right: none;
}
.menu > * .dropdown {
  position: absolute;
  top: 100%;
  left: 0;
  display: none;
  background-color: white;
  border-top: 1px solid #eee;
  padding: 10px;
}
.menu > *:hover .dropdown {
  display: block;
}
<div class="menu">
  <div>Item 1</div>
  <div>Item 2
    <div class="dropdown">
      Dropdown content here.
    </div>
  </div>
  <div>Item 3
    <div class="dropdown">
      Another dropdown content.
    </div>
  </div>
</div>

Regarding your specific request:

You want the width of the dropdown to be determined by its content and not wrap.

In this case, you can create a full-width mega-menu element with a transparent background, and position the content inside it using techniques like float:right or flex. If the content exceeds the full-width limit, it will automatically wrap. Here's an example:

// JavaScript code to handle dropdown toggling
var closeDropdowns = function(e) {
  $('.menu div').removeClass('active');
}
$('body').on('click', closeDropdowns);

$('.menu div').on('click', function(e){
  if (!$(this).hasClass('active')) {
    closeDropdowns();
  }
  e.stopPropagation();
  $(this).toggleClass('active');
})
body {
  margin: 0;
  padding: 0;
  background-color: #f5f5f5;
}

.menu {
  display: flex;
  position: relative;
}
.menu > * {
  position: relative;
  flex: 1 0 auto;
  padding: 10px;
  border: solid white;
  border-width: 0 1px 1px 0;  
  cursor: pointer;
  transition: background-color .3s ease-in-out;
}
.menu > *:last-child {
  border-right: none;
}
.menu > * .dropdown {
  position: absolute;
  top: 100%;
  left: 0;
  display: none;
  background-color: white;
  border-top: 1px solid #eee;
  padding: 10px;
}
.menu > *:hover .dropdown, .menu > *.active .dropdown  {
  display: block;
}
/* Additional styling for active/hover states */
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="menu">
  <div>Item 1</div>
  <div>Item 2
    <div class="dropdown">
      Dropdown content here.
    </div>
  </div>
  <div>Item 3
    <div class="dropdown">
      Another dropdown content.
    </div>
  </div>
</div>

Feel free to experiment with the code and adjust it to suit your specific needs. Keep in mind the added functionality for toggling dropdowns on click in this example.

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Centered Layout using HTML and CSS

Exploring the world of Ruby on Rails and HTML has been quite an adventure. Today's question veers away from RoR and focuses on HTML and CSS. As I attempt to center my body, a peculiar issue arises: Help me solve this problem here How can I align the ...

Moving a DIV below a fixed-positioned element

I have a website with a scrollable div. It works well, but I also need an absolutely positioned div on top of it - and it still needs to scroll smoothly without any hindrance. You can check out a basic JSFiddle demonstration here: http://jsfiddle.net/41ra ...

What is the solution to having a div move along with window resizing without displacing adjacent divs?

After much effort, I still can't seem to get this working correctly. I've been playing around with a section named "RightExtra" and a div inside it called "RightExtraContent". My goal is to allow these two divs to move freely when the window is ...

The mobile-responsive dropdown navigation bar functions well on browsers with small widths, but does not work properly on my phone

I am experiencing an issue with the mobile responsive dropdown navigation bar on my website. It works perfectly fine on a small width browser, but when I try to open it on my phone, nothing happens. This is puzzling me as I am new to making websites respon ...

Upon refreshing the page, the React application alters the font style

While working on my ReactJS application, I noticed that the font changes after the page loads and then reloads. Take a look at the examples below: Before reloading (press f5): https://i.sstatic.net/tJFjU.png After reloading (press f5): https://i.sstati ...

Tips for storing checkbox preferences in a user account on an HTML/PHP website

Hello! I am currently working on a website. I have included a checkbox that updates the option selected in phpMyAdmin. The issue I am facing is that when I press submit and then refresh the page using F5, the preference I chose disappears on the client s ...

Establishing the Backbone router configuration

Having trouble identifying the issue with my Backbone router. Is there an error within this code block? The index route is functioning correctly, but the classes route doesn't seem to be triggered (for example, when I try navigating to a URL like loca ...

showcasing a set of div elements by using forward and backward buttons

I am dealing with 5 divs that have text content inside. To navigate through each div, I have implemented a back and next button system. <a href="" class="back-btn off">Back</a> | <a href="" class="next-btn">Next</a> <div class ...

Is it possible to have an icon change color in a TableRow column when hovering over any part of that particular row?

I am currently using material-ui version 4.9.5. To illustrate my issue, I have created a simplified example here. I have a Table that is populated with basic JSON data. Each row in the table consists of an icon element along with its corresponding color a ...

Prevent horizontal HTML scrolling while displaying a layer

I am currently working with a .layer div element that darkens the page to highlight a modal. However, I have encountered an issue where upon triggering the event, the div does not occupy 100% of the screen and the original browser scroll bar disappears. I ...

Convert price to Indonesian Rupiah currency format with the help of Vue.js

Can someone help me convert the price format from IDR 50,000.00 to IDR 50.000 using JavaScript and Vue? I found a script on this website, but I am having trouble understanding how it works. The script looks like this: replace(/(\d)(?=(\d{3})+(?: ...

Consistent validation success with login authentication

I am currently working on a project that involves querying a server for user authentication using C# and ASP.NET, as I am still learning these technologies. Previously, I worked with JSP. The issue I am facing : For some reason, my methods are always re ...

Utilizing Isotope JS on your Wordpress website

I'm in the process of integrating the .js plugin, Isotope, into my Wordpress installation. It should be positioned at the bottom of this page: To achieve this, I am referring to an example on codepen: https://codepen.io/desandro/pen/mEinp The script ...

Interpolation problem with AngularJS translation service

I've successfully implemented a ternary operator in my HTML: {{ qp.QP_TRANSFERS === '1' ? qp.QP_TRANSFER_TYPE_NAME + ' transfer' : 'No transfer' }} In addition, I am utilizing a translation service with JSON objects. He ...

What is the best way to retrieve classes from arrays and apply styling to them using javascript?

Imagine having 3 unique classes: alpha, beta, and gamma. Each class contains 3 individual div elements like so: <div class="alpha"></div> <div class="alpha"></div> <div class="alpha"></div> <div class="beta">< ...

What is the best way to store objects in files using Node.js?

As I manage my Node server, a question arises - what is the best way to convert objects into a serialized format and save them to a file? ...

Surprising spacing found between CSS header elements

As I am in the process of redesigning a website, I have encountered an issue with certain elements in the header section. Specifically, the header consists of a logo, some text, and a navigation bar. There seems to be a thick gap between the bottom of the ...

Switching the Focus in Laravel Layouts

My understanding of CSS media queries includes: @media screen and (orientation: portrait) { div.container { ... } } @media screen and (orientation: landscape) { div.container { ... } } Despite this knowledge, I am looking ...

What is the procedure for selecting an element based on its child containing specifically filtered text?

Imagine a webpage with the following elements: <div data-search="type1"> any HTML <!-- .click is a child of any level --> <span class="click" data-source="page1.html">blue</span> <!-- let's call it "click1 ...

Tips for ensuring that images fully occupy my carousel slides

I am struggling to make my images fit properly within the slides. Here is the code snippet I have tried along with some screenshots: <div className="relative h-24 w-20 sm:h-44 sm:w-100 md:h-44 md:w-60 flex-shrink-0"> <Carousel showThu ...