Skip to content

Offcanvas: Improve offcanvas drawer support for same-page navigation #38514

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 2 commits into from

Conversation

RichDeBourke
Copy link

Add an option to not return focus to the offcanvas toggle button after an offcanvas nav drawer is closed.

Description

A navbar can be configured with an offcanvas drawer where the menu slides in (when a navbar button is clicked or tapped). Currently, the offcanvas drawer acts like a modal in that closing the drawer causes focus to be reapplied to the navbar button.

Reapplying focus is the expected behavior for a modal used for actions such as adjusting settings (e.g. font size), but is unexpected when the user clicks a same-page link. The expectation is focus will be on the destination element.

There is an additional complication with Chromium browsers if clicking the same-page link is used to close the drawer (in addition to starting a smooth scroll to an HTML element). On Chromium browsers, setting focus stops any in-process scrolls. Bootstrap sets the offcanvas transition time to 0.3s. Chrome takes around 0.4s and Edge takes around 0.7s to scroll to a new position, so the scroll does not have time to complete. Firefox will complete the scroll. (Don’t have info on Safari.)

Change details

Make the following changes to the offcanvase.js source file

  • Add a focus config setting to the list of Default config values. Value is normally true.
  • Define the focus config DefaultType as boolean.
  • In the EventHandler.on function, move the EventHandler.one function call to after the data const value is set, and wrap the EventHandler.one function in an if statement that only calls the EventHandler.one function if data._config.focus is set to true.
    const Default = {
        backdrop: true,
        keyboard: true,
        scroll: false,
        focus: true
    }

    const DefaultType = {
        backdrop: '(boolean|string)',
        keyboard: 'boolean',
        scroll: 'boolean',
        focus: 'boolean'
    }
    const data = Offcanvas.getOrCreateInstance(target)
    if (data._config.focus) {
        EventHandler.one(target, EVENT_HIDDEN, () => {
            // focus on trigger when it is closed
           if (isVisible(this)) {
               this.focus({ preventScroll: true })
           }
       })
    }

EventHandler.one sets this.focus() to take place after the offcanvas drawer has been hidden. Making the EventHandler.one conditional makes it possible to use links on the offcanvas drawer to move around a page and have the tab-order in the right sequence, rather than restarting from the navbar.

Setting the focus option

The focus setting can be set by either a data-bs-focus="false" or a data-bs-config= '{"focus": false}' data attribute on the offcanvas div.

Maintaining current functionality

If the new focus variable is left at the default value (true), then offcanvas sidebars will operate the same way they do now.

Changes to the documentation

offcanvas.md

Add a line to the Options table in offcanvas.md to provide information about the new variable.

focus boolean true Return focus to the data-bs-toggle element.

Example

Add a functional example of using offcanvas for a single-page website to the Examples section.

  • Add a new folder, navbar-single in the examples folder
  • Add two images for the new example
  • Update examples.yml

Motivation & Context

For a single-page website with a navigation menu (the menu links point to elements on the same page) and the need to use a hamburger style menu button (the menu items will not fit across the top of the page on a mobile device), there are the following issues with the current offcanvas drawer slide-in menu:

  • Clicking a link on the menu will scroll the page to the right point, but when the menu is closed, focus is returned to the hamburger button.
    • If the navbar is set to fixed-top, causing the navbar to always be showing, the hamburger button will have the focus.
    • If the navbar is not set to fixed-top, the page will scroll to the button and the button will have the focus.
  • If focus is set to the hamburger button, using the tab key will start from the hamburger button from the top of the page, rather than continuing from the linked point on the page.
  • If the link click is used to close the offcanvas drawer (either through a listener or an attribute), on Chromium based browsers, the scroll will be terminated, so it may not reach the destination.

It would be nice (the motivation for the change) for users, when clicking a same-page link, for the page to scroll to that position and focus be associated with the element the page scrolled to.

Type of changes

  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Refactoring (non-breaking change)
  • Breaking change (fix or feature that would change existing functionality)

Checklist

  • I have read the contributing guidelines
  • My code follows the code style of the project (using npm run lint)
  • My change introduces changes to the documentation
  • I have updated the documentation accordingly
  • I have added tests to cover my changes
  • All new and existing tests passed

Codepen examples

Standard (unmodified) offcanvas.js for single pages w/ autoclose menu

Demonstrates how focus is returned to the menu button and Chromium based browsers stop scrolling.
https://codepen.io/richdebourke/pen/zYmomJz

Modified offcanvas.js for single pages w/ autoclose menu

Demonstrates how the modified offcanvas.js skips returning focus to the menu button, leaving it at the destination element.
https://codepen.io/richdebourke/pen/ExdNKWm

Chromium browsers stop scrolling when focus is set

Demonstrate how Chromium based browsers stop scrolling when focus is set to another element.
https://codepen.io/richdebourke/pen/NWObWdd

Additional information

Automatically closing the offcanvas drawer

For same-page links, an offcanvas element can be automatically closed by either including a data-bs-dismiss="offcanvas" attribute on the link (in a span tag) or by using an event listener to get the offcanvas instance and calling hide(). For links on the offcanvas drawer to a different page, the drawer wouldn’t need to be closed.

React Bootstrap focus option

React Bootstrap has a restoreFocus function that controls whether to restore focus to a button or not

Related issues

Pull request #38079 by @ChellyAhmed: Posted on February 17, 2023 – Prevent Scrolling back when focus on close. Adds preventScroll: true object to the this.focus() method, which results in the page not scrolling to the menu button if page has scrolled to a new point. The menu still needs to be closed manually and focus is point to the menu button rather than to the active point on the page. The pull request is still pending as of this writing.

Issue #34447: Posted on July 7, 2021 – offcanvas: causes re-focus of trigger element after hidden. It was closed by @GeoSot with a note that, “I am pretty sure that it is not a bug, as modal and collapse have the same behavior, to indicate in purpose the trigger element.”

While Bootstrap’s modal and collapse functions do return focus to the trigger element when a navbar is collapsed, most websites, for same-page menus, let the focus follow the link.

Add an option to not return focus to the offcanvas toggle button after an offcanvas nav drawer is closed.
@RichDeBourke
Copy link
Author

Since the default Bootstrap offcanvas nav setup, in addition to always setting the focus back on the nav-bar toggler, doesn't include an aria-expanded attribute, I've created a custom offcanvas.js file that I compile with the rest of the Bootstrap components that I need, rather than trying to change the standard offcanvas.js file.

As it appears there is limited interest in this type of modification, I'm going to close the pull request.

@RichDeBourke
Copy link
Author

Since the default Bootstrap offcanvas nav setup, in addition to always setting the focus back on the nav-bar toggler, doesn't include an aria-expanded attribute, I've created a custom offcanvas.js file that I compile with the rest of the Bootstrap components that I need, rather than trying to change the standard offcanvas.js file.

As it appears there is limited interest in this type of modification, I'm going to close the pull request.

@RichDeBourke RichDeBourke deleted the offcanvas-focus-option branch October 7, 2023 09:43
@SNor42
Copy link

SNor42 commented Jan 18, 2024

@RichDeBourke : I just want to thank you. Simply implemented your, and the TOC worked :)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants