4

I have a simple bootstrap 5 offcanvas element. This contains a simple link to an anchor in the body of the html page.

I configured the offcanvas to have no backdrop and enables body scrolling.

Now when I open the offcanvas en click the link. The body scrolls to that section of the page. But when I close the offcanvas. The body scrolls back to the top. How can I keep the body where it is?

It seems like that the button that is used to open the offcanvas gets the focus back. I tried something like this.

var myOffcanvas = document.getElementById('offcanvasExample');
    //var bsOffcanvas = new bootstrap.Offcanvas(myOffcanvas)
    myOffcanvas.addEventListener('hidden.bs.offcanvas', function (event) {
        //event.stopPropagation();
        //event.preventDefault();
        // Give the document focus
        // Remove focus from any focused element
        if (document.activeElement) {
            document.activeElement.blur();
        }
        window.focus();

    });

but the page keeps scrolling back to the button.

Kind regards

4 Answers4

8

It is solved. The button should not use data-bs-toggle="offcanvas". If you make a on click handler for the button that toggles the offcanvas with the javascript functions of bootstrap it all works.

Here is my code

document.addEventListener("DOMContentLoaded", function(){
  var myOffcanvas = document.getElementById('offcanvasExample');
  var bsOffcanvas = new bootstrap.Offcanvas(myOffcanvas);
  document.getElementById("OpenMenu").addEventListener('click',function (e){
    e.preventDefault();
    e.stopPropagation();
    bsOffcanvas.toggle();
  });
});
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.0.0-beta3/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-eOJMYsd53ii+scO/bJGFsiCZc+5NDVN2yr8+0RDqr0Ql0h+rP48ckxlpbzKgwra6" crossorigin="anonymous">
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.0.0-beta3/dist/js/bootstrap.bundle.min.js" integrity="sha384-JEW9xMcG8R+pH31jmWH6WWP0WintQrMb4s7ZOdauHnUtxwoG2vI5DkLtS3qm9Ekf" crossorigin="anonymous"></script>
<!-- the Offcanvas button //-->
<button class="nav-link btn btn-outline-primary" id="OpenMenu">open</button>


<!-- the Offcanvas element //-->
<div class="offcanvas offcanvas-start" data-bs-scroll="true" data-bs-backdrop="false" tabindex="-1" id="offcanvasExample" aria-labelledby="offcanvasExampleLabel">
<div class="offcanvas-header">
<h5 class="offcanvas-title text-primary" id="offcanvasExampleLabel">Test</h5>
<button type="button" class="btn-close text-reset" data-bs-dismiss="offcanvas" aria-label="Close"></button>
</div>
<div class="offcanvas-body">
<a href="#test">test</a>
</div>
</div>
<div class="my-5 py-5">
Test content
</div>
<div class="my-5 py-5">Test content</div>
<div class="my-5 py-5">Test content</div>
<div class="my-5 py-5">Test content</div>
<div class="my-5 py-5">Test content</div>
<div class="my-5 py-5">Test content</div>
<div class="my-5 py-5">Test content</div>
<div class="my-5 py-5">Test content</div>
<div class="my-5 py-5"><a name="test" id="test">Scroll here</a></div>
<div class="my-5 py-5">Test content</div>
<div class="my-5 py-5">Test content</div>
<div class="my-5 py-5">Test content</div>
<div class="my-5 py-5">Test content</div>
<div class="my-5 py-5">Test content</div>
  • 1
    I can confirm it works with `bootstrap 5.1`. – Da CodeKid Oct 05 '21 at 02:11
  • Isn't there a way to "hook into" the Bootstrap offcanvas functionality and disable it? I tried it, but couldn't disable the return to the caller so far. I will try your solution... but please let me know if you found another way! – MikhailRatner Nov 11 '21 at 08:54
  • Thank you @Roel, I was able to use your code and made it work with Angular 12! I posted my answer below, since it was a bit different to yours. Really appreciate that you posted your solution! – MikhailRatner Nov 15 '21 at 10:40
  • thanks you have saved me. just in case you are facing cannot read property 'parentNode' try this offcanvas init ``` var offcanvasElementList = [].slice.call(document.querySelectorAll('.offcanvas')) var offcanvasList = offcanvasElementList.map(function (offcanvasEl) { var cok = new bootstrap.Offcanvas(offcanvasEl) document.getElementById("OpenMenu").addEventListener("click",function (e){ console.log("open clicked"); e.preventDefault(); e.stopPropagation(); cok.toggle(); }); }) ``` – Dark Cyber Feb 01 '22 at 08:49
1

Although I don't manipulate the offcanvas with Javascript, I had a similar problem. Scroll back to top on close offcanvas. Here the reason was different (and I still do not understand exactly what happens). However, I solved it by changing the button that opens the offcanvas, I changed the <button type="button"> tag to a <a type="button">.

I write it here to fix it, in case someone has a similar problem.

Andrés Peña
  • 83
  • 1
  • 6
  • Not sure, but in the documentation they say "Be sure to use the – MikhailRatner Nov 11 '21 at 09:21
0

I followed Roel Van der Plankens solution and made his JS part work with ANGULAR 12.

If your Offcanvas is in the Header Component, write something like this:

import { Component, OnInit } from "@angular/core";
import * as bootstrap from "bootstrap";

@Component({
  selector: "app-header",
  templateUrl: "./header.component.html",
  styleUrls: ["./header.component.scss"]
})
export class HeaderComponent implements OnInit {

  ngOnInit(): void {

    const offcanvasNavbar = document.getElementById('offcanvasExample');
    const openOffcanvas = document.getElementById('OpenMenu');

    if (offcanvasNavbar && openOffcanvas != null) {
      const bsOffcanvasNavbar = new bootstrap.Offcanvas(offcanvasNavbar);

      openOffcanvas.addEventListener('click', function () {
        //e.preventDefault();
        //e.stopPropagation();
        bsOffcanvasNavbar.toggle();
      });
    };
  };
};

To make this work, you have to install @types/bootstrap with this command in the terminal:

npm i --save-dev @types/bootstrap

Otherwise you are not able to use new bootstrap...

Unlike Roel Van der Plankens, I did not need

e.preventDefault();
e.stopPropagation();

Not sure if this is due to my version of Bootstrap being 5.1 or Angular 12. I left it commented out, maybe someone else might need that part of code.

MikhailRatner
  • 452
  • 6
  • 13
0

Solve Sticky navbar first

As mentioned above, after clicking a link in the offcanvas, the focus goes back to the top navbar menu button (the trigger). If you have a faulty "sticky-top" navbar, when you click on the link, the page scrolls down and, the navbar goes way up instead of staying in view. Therefore, the focus on the trigger scrolls way up again.

Setting the navbar to "fixed-top" made me realise it worked fine when the navbar was visible, and that I had first to fix the sticky problem, because the navbar wouldn't go way up when I click on a link in the offcanvas.

Fxp
  • 115
  • 8