Carbon: SideNav and overlay behaviour on click

Created on 7 Aug 2019  路  10Comments  路  Source: carbon-design-system/carbon

What package(s) are you using?

  • [X] carbon-components
  • [X] carbon-components-react

Detailed description

I use the UI shell with a SideNav, and a HashRouter, similar to what's described in the Carbon React tutorial.

On small or medium viewports, when you click on the HeaderMenuButton, the SideNav is expanded, and the rest of the page content is masked by a gray overlay.

Then there are 2 related issues:

  1. If the user clicks on a SideNavLink, the content loads into the content area, but the SideNav remains expanded, and does not close, as is expected.
  2. If the user wants to close the SideNav (as a result of 1, or simply because he wants to remain on the same page), he must click on the HeaderMenuButton (currently displaying as a cross). Clicking anywhere on the overlay or the menu bar does not close the SideNav as expected.

In both cases, user expects the SideNav to be closed after a click inside or outside of it, because that's the way most apps behave.

Bug seems browser-independent.
Using Node.js 10.16.2 (LTS). Dependencies and versions from package.json:

  "dependencies": {
    "@carbon/grid": "^10.4.0",
    "@carbon/icons-react": "^10.4.1",
    "carbon-components": "^10.4.1",
    "carbon-components-react": "^7.4.1",
    "carbon-icons": "^7.0.7",
    "react": "^16.8.6",
    "react-dom": "^16.8.6",
    "react-router-dom": "^5.0.1",
    "react-scripts": "3.0.1"
  },

Steps to reproduce the issue

Setup project with the UI Shell like in the Carbon React tutorial:

  • use and from react-router-dom
  • App structure (stripped pseudo-code, does not contain the Router):
<HeaderContainer render={ ({ isSideNavExpanded, onClickSideNavExpand }) => (
  <>
    <Header>
      <SkipToContent />
      <HeaderMenuButton onClick={onClickSideNavExpand} isActive={isSideNavExpanded} />
      <HeaderName>Name</HeaderName>
      <SideNav expanded={isSideNavExpanded} isPersistent={false}>
        <SideNavItems>
          <SideNavLink element={Link} to="link1">Link 1</SideNavLink>
          <SideNavLink element={Link} to="link2">Link 2</SideNavLink>
        </SideNavItems>
      </SideNav>
    </Header>
    <p>Content area</p>
  </>
  )}
/>

Additional information

Picture below shows a prototype: clicking on any of the zones pointed to by an arrow should close the side navigation.

image

ui-shell high 馃槺 react 3 bug 馃悰

Most helpful comment

@nxn-4-wdf yo. i ran into another problem where the sidenav stays there if you resize the browser so i amended the code to look like this. this fixes both the click out issue you describes as well as a broken ghosted sidenav on resize

      <HeaderContainer
        render={({ isSideNavExpanded, onClickSideNavExpand }) => {
          window.addEventListener(
            'resize',
            () => {
              const viewportWidth =
                window.innerWidth || document.documentElement.clientWidth;
              if (viewportWidth > 1056) {
                if (isSideNavExpanded === true) onClickSideNavExpand();
              }
            },
            false
          );
          return (
            <Fragment>
              <Header
                aria-label="Carbon Tutorial"
                onClick={
                  isSideNavExpanded === true ? onClickSideNavExpand : null
                }>

All 10 comments

React code example reproducing the issue: https://codesandbox.io/s/sidenavissues-jtrzb

Result here: https://jtrzb.csb.app/#/
To reproduce:

  • Reduce viewport width to less than 40rem, so that the HeaderMenuButton is displayed on the top-left corner.
  • Click on the menu button to display the SideNav.
  • Click on the different zones (see picture above in section "Additional information") does not close the SideNav, as expected.

Related issues with keyboard navigation:

  • pressing the Enter-key when a SideNavLink is selected does not close the side navigation
  • pressing the ESC-key does not close the side navigation

@nxn-4-wdf hey man, i ran into this problem too. just change your

<HeaderContainer
        render={({ isSideNavExpanded, onClickSideNavExpand }) => (
          <Fragment>
            <Header
              aria-label="nxn-4-wdf's Totally Tubular Application Worth Millions"
              onClick={
                isSideNavExpanded === true ? onClickSideNavExpand : null
              }>

tadaaaaa

@nxn-4-wdf yo. i ran into another problem where the sidenav stays there if you resize the browser so i amended the code to look like this. this fixes both the click out issue you describes as well as a broken ghosted sidenav on resize

      <HeaderContainer
        render={({ isSideNavExpanded, onClickSideNavExpand }) => {
          window.addEventListener(
            'resize',
            () => {
              const viewportWidth =
                window.innerWidth || document.documentElement.clientWidth;
              if (viewportWidth > 1056) {
                if (isSideNavExpanded === true) onClickSideNavExpand();
              }
            },
            false
          );
          return (
            <Fragment>
              <Header
                aria-label="Carbon Tutorial"
                onClick={
                  isSideNavExpanded === true ? onClickSideNavExpand : null
                }>

@dryhurst Thanks for your code!
I have used it in my code and solves all the use cases except one:

  • It calls onClickSideNavExpand on clicking on the sidebar link items, but does not hide the sidenav panel. It is weird because I can see how it removes the overlay background and change the header menu button... I think maybe the nav items is preventing it to be closed when they get the focus.
<HeaderContainer
          render={({ isSideNavExpanded, onClickSideNavExpand }) => {
            window.addEventListener(
              'resize',
              () => {
                const viewportWidth =
                  window.innerWidth || document.documentElement.clientWidth;
                if (viewportWidth > 1056) {
                  if (isSideNavExpanded === true) onClickSideNavExpand();
                }
              },
              false
            )

            return (
              <Fragment>
                <Header
                  aria-label="my app"
                  onClick={ isSideNavExpanded === true ? onClickSideNavExpand : null}
                  >
                  <SkipToContent />
                  <HeaderMenuButton
                    aria-label="Open menu"
                    onClick={onClickSideNavExpand}
                    isActive={isSideNavExpanded}
                  />
                  <HeaderName element={NavLink} to="/" prefix="">
                    MyApp
                  </HeaderName>
                  <HeaderNavigation aria-label="Carbon Tutorial">
                    <HeaderMenuItem element={NavLink} to="/about">About</HeaderMenuItem>
                    <HeaderMenuItem element={NavLink} to="/help">Help</HeaderMenuItem>
                    <HeaderMenuItem element={NavLink} to="/contact">Contact</HeaderMenuItem>
                    <HeaderMenuItem element={NavLink} to="/theme">Theme</HeaderMenuItem>
                  </HeaderNavigation>
                  <SideNav
                    aria-label="Side navigation"
                    expanded={isSideNavExpanded}
                    isPersistent={false}>
                    <SideNavItems>
                      <HeaderSideNavItems>
                        <HeaderMenuItem element={NavLink} to="/about">About</HeaderMenuItem>
                        <HeaderMenuItem element={NavLink} to="/help">Help</HeaderMenuItem>
                        <HeaderMenuItem element={NavLink} to="/contact">Contact</HeaderMenuItem>
                        <HeaderMenuItem element={NavLink} to="/theme">Theme</HeaderMenuItem>
                      </HeaderSideNavItems>
                    </SideNavItems>
                  </SideNav>
                </Header>
              </Fragment>
          )}}
        />

Thanks!

Hey, I have solved it with a workaround, I have identified that by clicking on the nav items it didn't remove the bx--side-nav--expanded class of the side nav panel.

<SideNav
   aria-label="Side navigation"
   expanded={isSideNavExpanded}
   isPersistent={false}
   className="global_sidenav">
      <SideNavItems>
         <HeaderSideNavItems>
            <HeaderMenuItem element={NavLink} to="/about" onClick={hideSideNav}>About</HeaderMenuItem>
            <HeaderMenuItem element={NavLink} to="/help" onClick={hideSideNav}>Help</HeaderMenuItem>
            <HeaderMenuItem element={NavLink} to="/contact" onClick={hideSideNav}>Contact</HeaderMenuItem>
            <HeaderMenuItem element={NavLink} to="/theme" onClick={hideSideNav}>Theme</HeaderMenuItem>
         </HeaderSideNavItems>
      </SideNavItems>
</SideNav>

`` const hideSideNav = () => { var sidenav = document.getElementsByClassName('global_sidenav'); sidenav[0].classList.remove('bx--side-nav--expanded'); };

@nxn-4-wdf hey man, i ran into this problem too. just change your

<HeaderContainer
        render={({ isSideNavExpanded, onClickSideNavExpand }) => (
          <Fragment>
            <Header
              aria-label="nxn-4-wdf's Totally Tubular Application Worth Millions"
              onClick={
                isSideNavExpanded === true ? onClickSideNavExpand : null
              }>

tadaaaaa

this will trigger when you try to expand a sidenav menu as well.

let onHeaderClick = (evt, hprops) => {
  if(evt.target.className.includes && evt.target.className.includes('nav__overlay')) {
    hprops.onClickSideNavExpand(evt)
  }
}

<HeaderContainer render={hprops => (
  <Header aria-label="example" onClick={(evt) => {onHeaderClick(evt, hprops)}}>
)} />

HeaderMenuButton not rendering on Chrome but I can see it when I open the CodeSandBox, any reason for this?

HeaderMenuButton not rendering on Chrome but I can see it when I open the CodeSandBox, any reason for this?

<HeaderMenuButton
    aria-label="Open menu"
    onClick={onClickSideNavExpand}
    isActive={isSideNavExpanded}
/>

make sure you have this added. also.. this appears only on low width pages. (max ~1050px)

Is there a way to display the HeaderMenuButton even if the page width is more than 1050px? And when the HeaderMenuButton is expanded the background is not greyed out.

^would like to second this question. Basically, is there a way to turn responsiveness off through props or something? It seems odd it forces you to use responsiveness.

Was this page helpful?
0 / 5 - 0 ratings