-1

I have created this dummy top nav bar, where i have multiple drop-down which can be scrollable on x axis via buttons if multiple . But when i open the dropdown it is being opened in scroll view for y axis. rather it should open on top. Tried multiple things nothing worked. This looks like a simple issue, but clearly has exercised my brain.

Created a dummy nav bar here https://codesandbox.io/p/sandbox/87jmzv

enter image description here

    import React, { useState } from 'react';

const TopNav = () => {
  const [scrollPosition, setScrollPosition] = useState(0);

  // Array of dropdowns, each with its own set of options
  const dropdowns = [
    { id: 'dropdown1', label: 'Dropdown 1', options: ['Option 1', 'Option 2', 'Option 3'] },
    { id: 'dropdown2', label: 'Dropdown 2', options: ['Option A', 'Option B', 'Option C'] },
    { id: 'dropdown3', label: 'Dropdown 3', options: ['Option X', 'Option Y', 'Option Z'] },
    { id: 'dropdown2', label: 'Dropdown 2', options: ['Option A', 'Option B', 'Option C'] },
    { id: 'dropdown2', label: 'Dropdown 2', options: ['Option A', 'Option B', 'Option C'] },

    { id: 'dropdown2', label: 'Dropdown 2', options: ['Option A', 'Option B', 'Option C'] },

    { id: 'dropdown2', label: 'Dropdown 2', options: ['Option A', 'Option B', 'Option C'] },

    // You can add more dropdowns here
  ];

  const scrollLeft = () => {
    setScrollPosition((prev) => Math.max(prev - 200, 0));
  };

  const scrollRight = () => {
    setScrollPosition((prev) => Math.min(prev + 200, (dropdowns.length - 3) * 200));
  };

  return (
    <div className="top-nav">
      {/* Logo on the left */}
      <div className="logo">Logo</div>

      {/* Left Arrow Button */}
      <button className="arrow-button" onClick={scrollLeft}>←</button>

      {/* Scrollable Dropdown List */}
      <div className="dropdowns-container">
        <div className="dropdowns-wrapper" style={{ transform: `translateX(-${scrollPosition}px)` }}>
          {dropdowns.map((dropdown) => (
            <CustomDropdown key={dropdown.id} label={dropdown.label} options={dropdown.options} />
          ))}
        </div>
      </div>

      {/* Right Arrow Button */}
      <button className="arrow-button" onClick={scrollRight}>→</button>
    </div>
  );
};

const CustomDropdown = ({ label, options }) => {
  const [isOpen, setIsOpen] = useState(false);
  const [selectedOption, setSelectedOption] = useState(null);

  const toggleDropdown = () => {
    setIsOpen((prev) => !prev);
  };

  const selectOption = (option) => {
    setSelectedOption(option);
    setIsOpen(false); // Close dropdown after selecting
  };

  return (
    <div className="dropdown">
      <div className="dropdown-label" onClick={toggleDropdown}>
        {selectedOption || label}
      </div>
      {isOpen && (
        <div className="dropdown-list">
          {options.map((option, index) => (
            <div key={index} className="dropdown-item" onClick={() => selectOption(option)}>
              {option}
            </div>
          ))}
        </div>
      )}
    </div>
  );
};

export default TopNav;

css

/* Top Navigation Styling */
.top-nav {
    display: flex;
    align-items: center;
    padding: 10px;
    background-color: #f4f4f4;
    border-bottom: 1px solid #ccc;
}

/* Logo Styling */
.logo {
    font-size: 20px;
    font-weight: bold;
    margin-right: 20px;
}

/* Arrow Button Styling */
.arrow-button {
    background-color: transparent;
    border: none;
    font-size: 20px;
    cursor: pointer;
    padding: 5px;
}

/* Dropdown Container Styling */
.dropdowns-container {
    display: flex;
    overflow-x: hidden;
    width: 300px;
    border: 1px solid #ccc;
    padding: 5px;
}

/* Wrapper to handle scrolling */
.dropdowns-wrapper {
    display: flex;
    transition: transform 0.3s ease;
}

/* Individual Dropdown Styling */
.dropdown {
    margin: 0 10px;
    position: relative;
}

/* Label Styling */
.dropdown-label {
    font-size: 14px;
    margin-bottom: 5px;
    font-weight: bold;
    cursor: pointer;
    padding: 5px;
    background-color: #fff;
    border: 1px solid #ccc;
    border-radius: 4px;
}

/* Custom Dropdown List */
.dropdown-list {
    position: absolute;
    top: 30px;
    left: 0;
    background-color: #fff;
    border: 1px solid #ccc;
    padding: 5px 0;
    box-shadow: 0 2px 5px rgba(0, 0, 0, 0.2);
    z-index: 10;
    width: 150px;
}

/* Dropdown Item Styling */
.dropdown-item {
    padding: 8px 10px;
    cursor: pointer;
}

.dropdown-item:hover {
    background-color: #f4f4f4;
}
5
  • Please see Something in my web site or project doesn't work. Can I just paste a link to it? Relevant code needs to be included in the question to produce a minimal reproducible example which demonstrates the problem, as well as information about the problem itself and what debugging you have done. Commented Dec 20, 2024 at 20:27
  • @David Ive added link to sandbox to reproduce it. Commented Dec 20, 2024 at 20:29
  • 1
    External links can indeed be helpful, and can certainly be retained in the question. But please take some time to read my previous comment again, as well as the page(s) to which it links. Then please update the question accordingly. Commented Dec 20, 2024 at 20:33
  • .dropdowns-container { overflow-x: hidden } is most likely causing this. Take a look at this answer Commented Dec 20, 2024 at 22:39
  • @SigurdMazanti thats the problem, i need overflow-x: hidden to enable the horizontal scrolling. Thats whats making this tricky. Commented Dec 21, 2024 at 9:42

1 Answer 1

1

There's a simple solution for the primary issue here: overflow-x: clip. This behaves differently than overflow-x: hidden, allowing the dropdown content to spill out of the box in the y-axis.

You will likely need to do some extra work to close the dropdown when the trigger is outside of the viewable window of the container, though, otherwise the menu will show clipped along the x-axis.

screenshot showing dropdown contents outside of the container

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.