Skip to content
14 changes: 9 additions & 5 deletions js/src/offcanvas.js
Original file line number Diff line number Diff line change
Expand Up @@ -49,13 +49,15 @@ const SELECTOR_DATA_TOGGLE = '[data-bs-toggle="offcanvas"]'
const Default = {
backdrop: true,
keyboard: true,
scroll: false
scroll: false,
focusAfterClose: true
}

const DefaultType = {
backdrop: '(boolean|string)',
keyboard: 'boolean',
scroll: 'boolean'
scroll: 'boolean',
focusAfterClose: 'boolean'
}

/**
Expand Down Expand Up @@ -151,7 +153,9 @@ class Offcanvas extends BaseComponent {
new ScrollBarHelper().reset()
}

EventHandler.trigger(this._element, EVENT_HIDDEN)
EventHandler.trigger(this._element, EVENT_HIDDEN, {
focusAfterClose: this._config.focusAfterClose
})
}

this._queueCallback(completeCallback, this._element, true)
Expand Down Expand Up @@ -240,9 +244,9 @@ EventHandler.on(document, EVENT_CLICK_DATA_API, SELECTOR_DATA_TOGGLE, function (
return
}

EventHandler.one(target, EVENT_HIDDEN, () => {
EventHandler.one(target, EVENT_HIDDEN, event => {
// focus on trigger when it is closed
if (isVisible(this)) {
if (event.focusAfterClose && isVisible(this)) {
this.focus()
}
})
Expand Down
32 changes: 29 additions & 3 deletions js/tests/unit/offcanvas.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -192,10 +192,11 @@ describe('Offcanvas', () => {
expect(offCanvas._backdrop._config.isVisible).toBeTrue()
expect(offCanvas._config.keyboard).toBeTrue()
expect(offCanvas._config.scroll).toBeFalse()
expect(offCanvas._config.focusAfterClose).toBeTrue()
})

it('should read data attributes and override default config', () => {
fixtureEl.innerHTML = '<div class="offcanvas" data-bs-scroll="true" data-bs-backdrop="false" data-bs-keyboard="false"></div>'
fixtureEl.innerHTML = '<div class="offcanvas" data-bs-scroll="true" data-bs-backdrop="false" data-bs-keyboard="false" data-bs-focus-after-close="false"></div>'

const offCanvasEl = fixtureEl.querySelector('.offcanvas')
const offCanvas = new Offcanvas(offCanvasEl)
Expand All @@ -204,20 +205,23 @@ describe('Offcanvas', () => {
expect(offCanvas._backdrop._config.isVisible).toBeFalse()
expect(offCanvas._config.keyboard).toBeFalse()
expect(offCanvas._config.scroll).toBeTrue()
expect(offCanvas._config.focusAfterClose).toBeFalse()
})

it('given a config object must override data attributes', () => {
fixtureEl.innerHTML = '<div class="offcanvas" data-bs-scroll="true" data-bs-backdrop="false" data-bs-keyboard="false"></div>'
fixtureEl.innerHTML = '<div class="offcanvas" data-bs-scroll="true" data-bs-backdrop="false" data-bs-keyboard="false" data-bs-focus-after-close="false"></div>'

const offCanvasEl = fixtureEl.querySelector('.offcanvas')
const offCanvas = new Offcanvas(offCanvasEl, {
backdrop: true,
keyboard: true,
scroll: false
scroll: false,
focusAfterClose: true
})
expect(offCanvas._config.backdrop).toBeTrue()
expect(offCanvas._config.keyboard).toBeTrue()
expect(offCanvas._config.scroll).toBeFalse()
expect(offCanvas._config.focusAfterClose).toBeTrue()
})
})

Expand Down Expand Up @@ -598,6 +602,28 @@ describe('Offcanvas', () => {
offCanvas.hide()
})
})

it('should not focus when focusAfterClose is disabled', () => {
return new Promise(resolve => {
fixtureEl.innerHTML = '<div class="offcanvas"></div>'

const offCanvasEl = fixtureEl.querySelector('div')
const offCanvas = new Offcanvas(offCanvasEl, {
focusAfterClose: false
})
const spy = spyOn(offCanvas._focustrap, 'deactivate').and.callThrough()
offCanvas.show()

offCanvasEl.addEventListener('hidden.bs.offcanvas', () => {
expect(spy).toHaveBeenCalled()

// TODO HOW TO CHECK THAT THE TARGET-ELEMENT WAS NOT FOCUSED
resolve()
})

offCanvas.hide()
})
})
})

describe('dispose', () => {
Expand Down
1 change: 1 addition & 0 deletions site/content/docs/5.3/components/offcanvas.md
Original file line number Diff line number Diff line change
Expand Up @@ -309,6 +309,7 @@ const offcanvasList = [...offcanvasElementList].map(offcanvasEl => new bootstrap
| `backdrop` | boolean or the string `static` | `true` | Apply a backdrop on body while offcanvas is open. Alternatively, specify `static` for a backdrop which doesn't close the offcanvas when clicked. |
| `keyboard` | boolean | `true` | Closes the offcanvas when escape key is pressed. |
| `scroll` | boolean | `false` | Allow body scrolling while offcanvas is open. |
| `focusAfterClose` | boolean | `true` | Focus the offcanvas toggler after the offcanvas is closed. |
{{< /bs-table >}}

### Methods
Expand Down