I'm using react-bootstrap 2.9.2 (bootstrap 5.3.2) to attempt to create a simple Navbar, with the first item in the Nav menu being a Dropdown list. The NavDropdown expands and the routes in the dropdown items work, but the dropdown never collapses. My understanding was that it should collapse in several scenarios by default, based on the behavior of the react-bootstrap example here. When expanded, I'd like it to collapse:
- when clicking the parent of the dropdown again ("Home" in my example below)
- when clicking a child within the dropdown (which navigates to a different route)
- when clicking outside the Navbar
None of these actions collapses the dropdown for my project. The only way I can currently collapse the dropdown is by refreshing the page. How can I get the dropdown to collapse for these 3 typical scenarios?
Below is some of the code I believe might be relevant, but happy to provide more if needed.
index.js:
import ReactDOM from 'react-dom/client';
import App from './App';
import { BrowserRouter } from 'react-router-dom';
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
<React.StrictMode>
<BrowserRouter>
<App />
</BrowserRouter>
</React.StrictMode>
);
App.js:
import './App.css'
import React from 'react';
import MainPage from './components/MainPage'
import { Header } from './components/Header';
import { NavHeader } from './components/NavHeader';
import { Routes, Route } from 'react-router-dom';
import TransactionsPage from './components/TransactionsPage';
function App() {
// This is what gets rendered on the page.
return (
<>
{ /* Display the decorative header, and navigation bar. */}
<Header />
<NavHeader />
{ /* Based on the selected route path, load a specific page. Index page is the default. */}
<Routes>
<Route exact path='/' element={<MainPage/>} />
<Route path='/home/:category' element={<MainPage/>} />
<Route path='/transactions' element={<TransactionsPage />} />
</Routes>
</>
)
}
export default App;
NavHeader.js:
import { Link, NavLink } from 'react-router-dom';
import { useState } from 'react';
import './NavHeader.css'
// Returns the navigation bar header.
export const NavHeader = () => {
const [expanded, setExpanded] = useState(false);
return (
<Navbar collapseOnSelect>
<Container>
<Navbar.Toggle aria-controls="responsive-navbar-nav" />
<Navbar.Collapse id="responsive-navbar-nav">
<Nav className="nav-header">
{/* Use Link from react-router-dom to define the routing links. */}
<NavDropdown
title="Home"
id="collapsible-nav-dropdown"
className="vertical-dropdown"
onToggle={() => setExpanded(!expanded)}
show={expanded}
>
<NavDropdown.Item as={NavLink} to="/home/stock">Stocks</NavDropdown.Item>
<NavDropdown.Item as={NavLink} to="/home/etf">ETFs</NavDropdown.Item>
<NavDropdown.Item as={NavLink} to="/home/full">Full</NavDropdown.Item>
</NavDropdown>
<Link to="/transactions" className="nav-item">Transactions & Performance</Link>
</Nav>
</Navbar.Collapse>
</Container>
</Navbar>
);
}
NavHeader.css:
.nav-header {
height: 4rem;
display: flex;
align-items: center;
background-color: black;
}
.nav-item {
color: grey;
margin-left: 20px;
margin-right: 20px;
font-size: 20px;
}
.vertical-dropdown .dropdown-menu {
display: flex;
flex-direction: column;
}
.vertical-dropdown .dropdown-item {
width: 100%;
text-align: left;
}
Here's what the Navbar looks like with the dropdown expanded:
Below is a list of a few of the things I've tried already that have not worked:
- Setting
expandedstate variable toNavDropdownvariableshow,open, andexpanded. All with no effect. - Tried various iterations of the
Dropdownexamples instead, includingDropdownButtonwithonToggle,onBlur,autoClose, etc, such as the solution here. None of these options would allow the dropdown to collapse as expected.
EDIT:
Based on the response, I've now modified the one section of the NavHeader.js file to be:
.vertical-dropdown.show .dropdown-menu {
display: flex;
flex-direction: column;
}
Now, there is better responsiveness when clicking a child in the dropdown, or clicking outside the Navbar. However, these click actions do not hide the dropdown; it "collapses" from a vertical list to a horizontal list, but still visible! How can I get the dropdown to truly collapse and actually hide the options without needing a full page refresh?
EDIT2:
When inspecting the drop-down element when "collapsed" (but still visible and displayed horizontally), it appears there is a still a display: block applied to this element:
I'm not sure where this comes from, as I don't see it in other examples. As a hacky-workaround, I was able to achieve the desired drop-down behavior (where it is actually hidden when clicking away) by adding this piece to my Navbar.css file:
.vertical-dropdown .dropdown-menu {
display: none;
}



The issue come from this css:
It defines that
.dropdown-menuwill always bedisplay: flex. However internally the dropdown usesdisplay: noneto hide it.You can fix that by specifying that the
.vertical-dropdownshould be open to apply the css using the.showclass:See the Codesandbox:
On another note the
.vertical-dropdown .dropdown-menuis already a flex element in thecolumndirection so you can actually remove all this extra css