Tips on automating the process of moving overflowing elements into a dropdown menu

Challenge Description

In need of a dynamic navigation bar, I faced the problem of displaying only the first X items on one line and have the remaining items hidden in a "Show more" dropdown. The challenge was to calculate the width of each item accurately without rendering all elements at once for performance reasons.

Potential Approach

To address this issue, I devised a method to measure the width of each item by considering text length and button padding. By comparing the total width of items with the screen width, I could determine which items should be shown on the initial display line. However, the difficulty lay in measuring the text width without rendering all items simultaneously, as it would impact performance negatively.

Answer №1

When determining the width of each item, it is necessary for the browser to render them first. Trying to find a workaround where items are not rendered initially may seem like premature optimization. Unless your menu contains thousands of top-level items, the rendering time is minimal compared to what an alternative scripting solution would require.

The JavaScript logic in the code below is straightforward and should not have a significant impact on performance. The loop iterates through the list of top-level items just once.

window.addEventListener( 'DOMContentLoaded', () => {
    const menu = document.querySelector( '#menu' )
    const items = menu.querySelectorAll( '.item' )
    const viewMore = menu.querySelector( '.view-more' )
    const overflow = menu.querySelector( '#overflow-menu' )
    
    const maxWidth = menu.offsetWidth
    let accumulator = viewMore.offsetWidth
    let c = 0
    
    while ( accumulator <= maxWidth && c < items.length - 1 ) {
        accumulator += items[c].offsetWidth
        c++
    }
    
    for ( c--; c < items.length; c++ ) {
        if ( ! items[c].classList.contains( 'view-more' ) ) {
            overflow.appendChild(items[c]);
        }
    }
    
    viewMore.addEventListener( 'click', () => {
        overflow.classList.toggle( 'visible' ) 
    } )
} )
#menu {
    display: flex;
}
.item {
    padding: 5px 10px;
    cursor: pointer;
    white-space: nowrap;
    color: black;
}
.item.view-more {
    background-color: black;
    color: white;
    border-radius: 5px;
    position: relative;
}
#overflow-menu {
    position: absolute;
    top: 100%;
    right: 0;
    display: none;
    flex-direction: column;
    background-color: white;
    box-shadow: 0 0 10px black;
}
#overflow-menu.visible {
    display: flex;
}
<div id="menu">
  <div class="item">Text</div>
  <div class="item">Of Varying</div>
  <div class="item">Lengths</div>
  <div class="item">That The Browser</div>
  <div class="item">Must</div>
  <div class="item">Render</div>
  <div class="item">In</div>
  <div class="item">Order To</div>
  <div class="item">Determine</div>
  <div class="item">The</div>
  <div class="item">Final Width</div>
  <div class="item">:)</div>
  
  <div class="item view-more">
      View More
      <div id="overflow-menu"></div>
  </div>
</div>

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

What is the best method for incorporating a drop-down menu in every row of a Material UI Table?

I am currently facing an issue with implementing the material-ui Drop Down Menu in each row within a material-ui Table. The problem arises when I attempt to change the value of one drop down; it results in every other drop down's value changing as wel ...

The type 'string[]' is missing the required property 'label', resulting in a typescript error

Within my codebase, I've defined a type called Person that looks like this : type Person = { value?: string[]; label?: string[]; }; Additionally, there is a promise function in my project: async function main(): Promise<Person> { const fo ...

Eslint is actively monitoring files specified in the eslintignore to ensure they meet the set

I am currently working on a TypeScript project that is bundled by Webpack. I want to integrate Eslint into the project, but I have encountered an issue where Eslint watches compiled files even if they are listed in the .eslintignore file. .eslintignore: . ...

Issues arise with controlling access due to cache-control and canvas properties

I am attempting to utilize the browser canvas feature to manipulate images that are hosted on cloudfront. My goal is to configure cloudfront in a way that allows the browser to cache images with cache control set to max-age, while still enabling canvas edi ...

Dividing Faces with Lengthy Edges in three.js into Two Separate Faces

I am currently working on a script that involves splitting overly long edges of faces into two separate faces instead of one large face. The final result is exported to a .obj file. Although the geometry reduction works fine, I have noticed some issues a ...

Customize your Bootstrap hamburger menu with a unique open and close button design

Currently, I am in the process of creating a hamburger menu with Bootstrap and I have managed to customize the open and close buttons according to my preferences. However, I am facing an issue where the hamburger icon is not displaying properly. See the c ...

Is it possible for the client to prevent the blocking of the Cross-Origin Resource Sharing (CORS) error?

I am encountering an issue with my web app that involves CORS operations when making $.getJSON AJAX calls. Typically, this functions properly on most client browsers due to the server having CORS enabled. However, I recently discovered that when using IE 1 ...

What are some ways to create a div section within a Google Map interface?

Is there a way to create a div area within the Google map iframe? Some of my code is already prepared here (). The image in this link () illustrates exactly what I'm trying to achieve. ...

Unable to use saved images with jQuery Slider

I'm currently facing an issue with adding a jQuery slider to my website. It seems that the slider is not displaying images that are saved on my computer, only images from external websites. Below is the code snippet where I have included an image fil ...

Does using AJAX with jQuery and PHP guarantee that the response will always be in JSON format?

While working on PHP validation with AJAX requests for user-submitted information, I encountered an issue. The problem arises when attempting to convert the JSON response from PHP to a Javascript object, as it throws the following error: "Uncaught SyntaxE ...

Extract content from whole webpage including HTML, CSS, and JavaScript

Currently I am working on developing a webpage version control backup/log system. The goal is to automatically save a static copy of the webpage, including all its CSS and JavaScript files, whenever there are any changes made. I have already figured out h ...

What action will prompt the event to export all data as a CSV file?

After exploring various suggestions on stackoverflow related to my question, I have not been successful. My current challenge involves implementing server-side pagination in UI-GRID. I am specifically struggling with exporting all data as a CSV file. Due ...

What is the correct method for typing a React functional component with properties?

Here's a react functional component I have created... const MyFunction = () => { // lots of logic MyFunction.loaded = someBoolean; return <div>just one line</div> } MyFunction.refresh = () => ....... I added two properti ...

Ways to display pre-selected information using MUI datagrid's checkboxSelection feature

I am currently working on a React web application and using a DataGrid component. I need to have certain rows pre-selected in the DataGrid just like they were selected previously by the user. At the moment, the user has access to Server A, C, and D. How c ...

Can you explain to me the syntax used in Javascript?

I'm a bit puzzled by the syntax used in this react HOC - specifically the use of two fat arrows like Component => props =>. Can someone explain why this works? const withLogging = Component => props => { useEffect(() => { fetch(`/ ...

Accordion menu designed exclusively with JavaScript

Implementation of required menu structure: Main Menu Submenu Contacts News Photo Submenu Submenu Submenu Main Menu Main Menu Main Menu When clicking on the "Main Menu" button, a list of "Submenu" elements opens. Clicking on the "Submenu" button ope ...

How to Display HTML Content from a WYSIWYG Editor in ASP.NET Webforms without Master Page Bootstrap Styles Interfering

I am facing an issue in ASP.NET Webforms with a Master Page that imports Bootstrap CSS, which is then used by all child pages of the site. One of the child pages contains HTML content generated from a WYSIWYG editor. However, the styles applied by Bootstr ...

Reorganizing asynchronous code into a nested synchronous structure in Meteor/React

Recently, I've been experimenting with running data fetching code in a container component and passing it to the display component in order to streamline my use of hooks and reduce load time. I've tested both await/sync and Meteor's wrapAsyn ...

An error has occurred with the Firefox Addon: the module `path` cannot be located within the resource://gre/modules/commonjs/http.js

Currently developing a Firefox add-on on Windows10 with node v5.8.0 and npm v3.5.3, using Firefox v.45.0 The issue arises from the following line of code: var path = require("path"); The error message reads: Message: Module `http` is not found at resou ...

What is the method for substituting one text with another using two-way data binding?

I implemented two different cases in my Mat-Table. When there is no data, the user will see a message saying "No Data Found". However, if the user enters text in the filter search, the "No Data Found" message should be hidden and replaced with the entered ...