Skip to content

Commit 0d054bb

Browse files
patrickhlaukeGeoSotffoodd
authored
Remove explicit use of aria-hidden for offcanvas when closed (#35589)
Remove explicit use of aria-hidden & visibility for offcanvas when closed, handling it with css Co-authored-by: GeoSot <geo.sotis@gmail.com> Co-authored-by: Gaël Poupard <ffoodd@users.noreply.github.com>
1 parent f7a1b18 commit 0d054bb

File tree

3 files changed

+71
-17
lines changed

3 files changed

+71
-17
lines changed

js/src/offcanvas.js

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,8 @@ const EVENT_LOAD_DATA_API = `load${EVENT_KEY}${DATA_API_KEY}`
3131
const ESCAPE_KEY = 'Escape'
3232

3333
const CLASS_NAME_SHOW = 'show'
34+
const CLASS_NAME_SHOWING = 'showing'
35+
const CLASS_NAME_HIDING = 'hiding'
3436
const CLASS_NAME_BACKDROP = 'offcanvas-backdrop'
3537
const OPEN_SELECTOR = '.offcanvas.show'
3638

@@ -99,24 +101,23 @@ class Offcanvas extends BaseComponent {
99101
}
100102

101103
this._isShown = true
102-
this._element.style.visibility = 'visible'
103-
104104
this._backdrop.show()
105105

106106
if (!this._config.scroll) {
107107
new ScrollBarHelper().hide()
108108
}
109109

110-
this._element.removeAttribute('aria-hidden')
111110
this._element.setAttribute('aria-modal', true)
112111
this._element.setAttribute('role', 'dialog')
113-
this._element.classList.add(CLASS_NAME_SHOW)
112+
this._element.classList.add(CLASS_NAME_SHOWING)
114113

115114
const completeCallBack = () => {
116115
if (!this._config.scroll) {
117116
this._focustrap.activate()
118117
}
119118

119+
this._element.classList.add(CLASS_NAME_SHOW)
120+
this._element.classList.remove(CLASS_NAME_SHOWING)
120121
EventHandler.trigger(this._element, EVENT_SHOWN, { relatedTarget })
121122
}
122123

@@ -137,14 +138,13 @@ class Offcanvas extends BaseComponent {
137138
this._focustrap.deactivate()
138139
this._element.blur()
139140
this._isShown = false
140-
this._element.classList.remove(CLASS_NAME_SHOW)
141+
this._element.classList.add(CLASS_NAME_HIDING)
141142
this._backdrop.hide()
142143

143144
const completeCallback = () => {
144-
this._element.setAttribute('aria-hidden', true)
145+
this._element.classList.remove(CLASS_NAME_SHOW, CLASS_NAME_HIDING)
145146
this._element.removeAttribute('aria-modal')
146147
this._element.removeAttribute('role')
147-
this._element.style.visibility = 'hidden'
148148

149149
if (!this._config.scroll) {
150150
new ScrollBarHelper().reset()

js/tests/unit/offcanvas.spec.js

Lines changed: 53 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -242,23 +242,46 @@ describe('Offcanvas', () => {
242242
expect(offCanvas.show).toHaveBeenCalled()
243243
})
244244

245-
it('should call hide method if show class is present', () => {
245+
it('should call hide method if show class is present', done => {
246246
fixtureEl.innerHTML = '<div class="offcanvas"></div>'
247247

248248
const offCanvasEl = fixtureEl.querySelector('.offcanvas')
249249
const offCanvas = new Offcanvas(offCanvasEl)
250-
offCanvas.show()
251-
expect(offCanvasEl).toHaveClass('show')
252250

253-
spyOn(offCanvas, 'hide')
251+
offCanvasEl.addEventListener('shown.bs.offcanvas', () => {
252+
expect(offCanvasEl).toHaveClass('show')
253+
spyOn(offCanvas, 'hide')
254254

255-
offCanvas.toggle()
255+
offCanvas.toggle()
256256

257-
expect(offCanvas.hide).toHaveBeenCalled()
257+
expect(offCanvas.hide).toHaveBeenCalled()
258+
done()
259+
})
260+
261+
offCanvas.show()
258262
})
259263
})
260264

261265
describe('show', () => {
266+
it('should add `showing` class during opening and `show` class on end', done => {
267+
fixtureEl.innerHTML = '<div class="offcanvas"></div>'
268+
const offCanvasEl = fixtureEl.querySelector('.offcanvas')
269+
const offCanvas = new Offcanvas(offCanvasEl)
270+
271+
offCanvasEl.addEventListener('show.bs.offcanvas', () => {
272+
expect(offCanvasEl).not.toHaveClass('show')
273+
})
274+
275+
offCanvasEl.addEventListener('shown.bs.offcanvas', () => {
276+
expect(offCanvasEl).not.toHaveClass('showing')
277+
expect(offCanvasEl).toHaveClass('show')
278+
done()
279+
})
280+
281+
offCanvas.show()
282+
expect(offCanvasEl).toHaveClass('showing')
283+
})
284+
262285
it('should do nothing if already shown', () => {
263286
fixtureEl.innerHTML = '<div class="offcanvas show"></div>'
264287

@@ -353,6 +376,30 @@ describe('Offcanvas', () => {
353376
})
354377

355378
describe('hide', () => {
379+
it('should add `hiding` class during closing and remover `show` & `hiding` classes on end', done => {
380+
fixtureEl.innerHTML = '<div class="offcanvas"></div>'
381+
const offCanvasEl = fixtureEl.querySelector('.offcanvas')
382+
const offCanvas = new Offcanvas(offCanvasEl)
383+
384+
offCanvasEl.addEventListener('hide.bs.offcanvas', () => {
385+
expect(offCanvasEl).not.toHaveClass('showing')
386+
expect(offCanvasEl).toHaveClass('show')
387+
})
388+
389+
offCanvasEl.addEventListener('hidden.bs.offcanvas', () => {
390+
expect(offCanvasEl).not.toHaveClass('hiding')
391+
expect(offCanvasEl).not.toHaveClass('show')
392+
done()
393+
})
394+
395+
offCanvas.show()
396+
offCanvasEl.addEventListener('shown.bs.offcanvas', () => {
397+
offCanvas.hide()
398+
expect(offCanvasEl).not.toHaveClass('showing')
399+
expect(offCanvasEl).toHaveClass('hiding')
400+
})
401+
})
402+
356403
it('should do nothing if already shown', () => {
357404
fixtureEl.innerHTML = '<div class="offcanvas"></div>'
358405

scss/_offcanvas.scss

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,17 @@
1212
outline: 0;
1313
@include box-shadow($offcanvas-box-shadow);
1414
@include transition(transform $offcanvas-transition-duration ease-in-out);
15+
16+
&.showing,
17+
&.show:not(.hiding) {
18+
transform: none;
19+
}
20+
21+
&.showing,
22+
&.hiding,
23+
&.show {
24+
visibility: visible;
25+
}
1526
}
1627

1728
.offcanvas-backdrop {
@@ -77,7 +88,3 @@
7788
border-top: $offcanvas-border-width solid $offcanvas-border-color;
7889
transform: translateY(100%);
7990
}
80-
81-
.offcanvas.show {
82-
transform: none;
83-
}

0 commit comments

Comments
 (0)