Skip to content

Commit

Permalink
fix(a11y): focusing background elements with 100% sidebar
Browse files Browse the repository at this point in the history
Prevents background elements form being focused when the sidebar takes 100% screen with (mobile view).
  • Loading branch information
JammingBen committed Sep 18, 2024
1 parent 35f54c3 commit 6fab180
Show file tree
Hide file tree
Showing 3 changed files with 90 additions and 66 deletions.
1 change: 1 addition & 0 deletions changelog/unreleased/enhancement-a11y-improvements
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ The following accessibility improvements have been made:
- The contrasts of input borders have been aligned with the official WCAG requirements.
- The space member search in the right sidebar now has a label. Also, the search has been moved from the top of the sharing panel to the members section where all members are listed.
- Leaving dropdown menus via the keyboard navigation now closes them.
- When the sidebar is open and uses 100% of the screen width (mobile view), it is no longer possible to focus elements in the background.

https://github.com/owncloud/web/pull/11574
https://github.com/owncloud/web/pull/11591
Expand Down
2 changes: 1 addition & 1 deletion packages/web-pkg/src/components/ItemFilter.vue
Original file line number Diff line number Diff line change
Expand Up @@ -198,7 +198,7 @@ export default defineComponent({
const showDrop = async () => {
setDisplayedItems(props.items)
await nextTick()
unref(filterInputRef).focus()
unref(filterInputRef)?.focus()
}
watch(filterTerm, () => {
Expand Down
153 changes: 88 additions & 65 deletions packages/web-pkg/src/components/SideBar/SideBar.vue
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
<template>
<div
id="app-sidebar"
ref="appSideBar"
data-testid="app-sidebar"
:class="{
'has-active-sub-panel': hasActiveSubPanel,
'oc-flex oc-flex-center oc-flex-middle': loading
'oc-flex oc-flex-center oc-flex-middle': loading,
'app-sidebar-full-width': fullWidthSideBar
}"
>
<oc-spinner v-if="loading" />
Expand Down Expand Up @@ -95,7 +97,17 @@
<script lang="ts">
import { VisibilityObserver } from '../../observer'
import { computed, defineComponent, nextTick, PropType, ref, unref, watch } from 'vue'
import {
computed,
defineComponent,
nextTick,
onBeforeUnmount,
PropType,
ref,
unref,
useTemplateRef,
watch
} from 'vue'
import { SideBarPanel, SideBarPanelContext } from './types'
import { useGettext } from 'vue3-gettext'
Expand Down Expand Up @@ -129,6 +141,8 @@ export default defineComponent({
emits: ['close', 'selectPanel'],
setup(props) {
const { $gettext } = useGettext()
const appSideBar = useTemplateRef<HTMLElement>('appSideBar')
const panelContainer = useTemplateRef<HTMLElement[]>('panelContainer')
const rootPanels = computed(() => {
return props.availablePanels.filter(
Expand Down Expand Up @@ -201,59 +215,7 @@ export default defineComponent({
return $gettext('Back to main panels')
})
return {
displayPanels,
rootPanels,
subPanels,
activeSubPanelName,
activePanelName,
oldPanelName,
clearOldPanelName,
setOldPanelName,
hasActiveSubPanel,
hasActiveRootPanel,
accessibleLabelBack,
focussedElementId
}
},
data() {
return {
selectedFile: {}
}
},
watch: {
isOpen: {
handler: function (isOpen) {
if (!isOpen) {
return
}
this.$nextTick(() => {
this.initVisibilityObserver()
})
},
immediate: true
}
},
beforeUnmount() {
visibilityObserver.disconnect()
hiddenObserver.disconnect()
},
methods: {
setSidebarPanel(panel: string) {
this.$emit('selectPanel', panel)
},
resetSidebarPanel() {
this.$emit('selectPanel', null)
},
closeSidebar() {
this.$emit('close')
},
initVisibilityObserver() {
const initVisibilityObserver = () => {
visibilityObserver = new VisibilityObserver({
root: document.querySelector('#app-sidebar'),
threshold: 0.9
Expand All @@ -263,31 +225,93 @@ export default defineComponent({
threshold: 0.05
})
const doFocus = () => {
if (!this.focussedElementId) {
if (!unref(focussedElementId)) {
return
}
const element = document.getElementById(this.focussedElementId)
const element = document.getElementById(unref(focussedElementId))
if (!element) {
return
}
element.focus()
}
if (!this.$refs.panelContainer) {
if (!unref(panelContainer)) {
return
}
visibilityObserver.disconnect()
hiddenObserver.disconnect()
;(this.$refs.panelContainer as HTMLElement[]).forEach((panel) => {
unref(panelContainer).forEach((panel) => {
visibilityObserver.observe(panel, {
onEnter: doFocus,
onExit: doFocus
})
hiddenObserver.observe(panel, {
onExit: this.clearOldPanelName
onExit: clearOldPanelName
})
})
}
const fullWidthSideBar = computed(() => window.innerWidth <= 960)
const backgroundContentEl = computed(() => {
return unref(appSideBar).parentElement.querySelector('div') as HTMLElement
})
watch(
() => props.isOpen,
async (isOpen) => {
if (!isOpen) {
return
}
await nextTick()
initVisibilityObserver()
if (unref(fullWidthSideBar) && unref(backgroundContentEl)) {
// hide content behind sidebar when it has full width to avoid focusable elements
unref(backgroundContentEl).style.visibility = 'hidden'
}
},
{ immediate: true }
)
onBeforeUnmount(() => {
visibilityObserver.disconnect()
hiddenObserver.disconnect()
if (unref(backgroundContentEl)) {
unref(backgroundContentEl).style.visibility = 'visible'
}
})
return {
appSideBar,
displayPanels,
rootPanels,
subPanels,
activeSubPanelName,
activePanelName,
oldPanelName,
clearOldPanelName,
setOldPanelName,
hasActiveSubPanel,
hasActiveRootPanel,
accessibleLabelBack,
focussedElementId,
fullWidthSideBar
}
},
methods: {
setSidebarPanel(panel: string) {
this.$emit('selectPanel', panel)
},
resetSidebarPanel() {
this.$emit('selectPanel', null)
},
closeSidebar() {
this.$emit('close')
},
openPanel(panel: string) {
Expand All @@ -311,13 +335,12 @@ export default defineComponent({
min-width: 440px;
width: 440px;
}
.app-sidebar-full-width {
min-width: 100% !important;
width: 100% !important;
}
@media only screen and (max-width: 960px) {
#app-sidebar {
min-width: 100%;
width: 100%;
}
.files-wrapper {
flex-wrap: nowrap !important;
}
Expand Down

0 comments on commit 6fab180

Please sign in to comment.