'Position Fixed Sidebar Content Moves on Bootstrap Modal Close
We have an simple React application with a basic sidebar & a bootstrap modal.
And here is where we are observing strange behavior. If we click the "X" our sidebar drops down the page just for a moment until the modal closes.
This behavior is not observed with any other button or input. Even if we click the "Close" button, which does the same thing (closes the modal), the sidebar does not move. It only moves when we mousedown on the "X".
If I mouse down on the "X" and move my cursor away, then mouse up, the sidebar remains in the "moved down" state, until I close the modal.
This is very strange and we have no idea what could be going on here, any help would be greatly appreciated.
Here is the code for the React Component:
import React, { useContext, useEffect, useState, FC } from 'react'
import { NavLink } from 'react-router-dom'
import { BoxSeam, House, Check2Circle, Download } from 'react-bootstrap-icons'
import { GlobalContext } from '../context/GlobalContext'
import Header from '../components/Header'
import Snackbar from '../components/Snackbar'
import SelectLocationModal from '../components/SelectLocationModal'
import IPropsWithChildren from '../ts/interfaces/IPropsWithChildren.interface'
import INavLink from '../ts/interfaces/INavLink.interface'
import styles from '../styles/layouts/Layout.module.scss'
const PrivateLayout: FC<IPropsWithChildren> = ({ children }) => {
// Sidebar default is closed below 768px screens & open on larger
// Therefore, isSidebarOpen is only an appropriate name for smaller screens
// On larger screens this would be interpreted as isSidebarClosed
const [isSidebarOpen, setIsSidebarOpen] = useState(false);
const { location, setLocation } = useContext(GlobalContext);
const navLinks: INavLink[] = [
{
to: '/',
icon: <BoxSeam />,
displayText: 'Containers',
disabled: false
},
{
to: '/receiving',
icon: <Download />,
displayText: "Receiving",
disabled: false
},
{
to: '/approve',
icon: <Check2Circle />,
displayText: "Approve",
disabled: false
}
]
const closeOnSmScreen = () => {
setIsSidebarOpen(false);
}
useEffect(() => {
const location = localStorage.getItem('LocationID');
if (location) {
setLocation(location);
}
}, [setLocation])
return (
<div>
<SelectLocationModal
isOpen={location === ''}
handleClose={() => null}
/>
<Header
setIsSidebarOpen={setIsSidebarOpen}
isSidebarOpen={isSidebarOpen}
/>
<div className={styles.wrapper}>
<nav className={`${styles.sidebar} ${isSidebarOpen ? styles.active : ''} bg-light`}>
<div className={styles.sidebarContent}>
<ul className="ps-0">
{
navLinks.map((navLink, i) => (
<li key={i}>
<NavLink
to={ navLink.to }
activeClassName={ navLink.disabled ? '' : styles.activeLink }
className={`${navLink.disabled ? styles.disabledLink : ''} d-flex align-items-center flex-md-column py-2 navLink`}
onClick={closeOnSmScreen}
exact
>
{navLink.icon}
<span>{navLink.displayText}</span>
</NavLink>
</li>
))
}
</ul>
</div>
</nav>
<div className={"childrenContainer container"}>
{children}
<Snackbar />
</div>
</div>
</div>
)
}
export default PrivateLayout
And the CSS:
@import '../variables.scss';
.childrenContainer {
padding-top: $headerHeight;
}
.activeLink {
color: white !important;
background-color: $primary;
}
// Sidebar
.wrapper {
display: flex;
align-items: stretch;
width: 100%;
}
.sidebar {
position: fixed;
top: $headerHeight;
z-index: 999;
min-width: 85vw;
min-height: calc(100vh - #{$headerHeight});
margin-left: -85vw;
transition: .2s ease-in;
}
.sidebar.active {
margin-left: 0;
box-shadow: 2px 0px 15px 0px #000;
}
.sidebarContent {
position: sticky;
li {
list-style: none;
a {
text-decoration: none;
color: var(--dark);
}
}
}
.disabledLink {
text-decoration: line-through !important;
}
.navLink {
padding-left: 1rem;
span {
padding-left: .5rem;
}
svg {
height: 1.25rem;
width: 1.25rem;
}
}
@media screen and (min-width:768px) {
.childrenContainer {
padding-top: $headerLgHeight;
}
.sidebar {
position: sticky;
padding-top: $headerLgHeight;
margin-left: 0;
max-width: $sidebarWidth;
min-width: $sidebarWidth;
height: 100vh;
}
.sidebar.active {
margin-left: -$sidebarWidth;
box-shadow: none;
background: white !important;
}
.sidebarContent {
position: fixed;
width: $sidebarWidth;
}
.navLink {
display: flex;
flex-direction: column;
align-items: center;
padding-left: 0;
span {
padding-left: 0;
font-size: .67rem;
}
svg {
height: 1.25rem;
width: 1.25rem;
}
}
}
Here is a code snadbox that reproduces the behavior described above (thanks Igor Gonak for initiating this).
Solution 1:[1]
Just remove "top" and it stops flipping:
.sidebar {
position: fixed;
// top: $headerHeight;
z-index: 999;
min-width: 85vw;
min-height: calc(100vh - #{$headerHeight});
margin-left: -85vw;
transition: .2s ease-in;
}
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 | Igor Gonak |
