Skip to content

Instantly share code, notes, and snippets.

@ryanw3b3r
Created August 17, 2023 13:04
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save ryanw3b3r/e22aa9212bbc1b8e8c37bc420ab0a6d0 to your computer and use it in GitHub Desktop.
Save ryanw3b3r/e22aa9212bbc1b8e8c37bc420ab0a6d0 to your computer and use it in GitHub Desktop.
Trap TAB and Shift+TAB in modal or any other element. Just wrap it in this component.
<script lang="ts" setup>
import { type Ref, onMounted, ref } from 'vue'
const selectors = 'a[href], input:not([disabled]), select:not([disabled]), textarea:not([disabled]), button:not([disabled])'
const wrapper: Ref<HTMLElement | undefined> = ref()
const focusableEls: Ref<Array<HTMLElement>> = ref([])
const firstFocusableEl: Ref<HTMLElement | undefined> = ref()
const lastFocusableEl: Ref<HTMLElement | undefined> = ref()
function handleBackwardMove(event: KeyboardEvent): void {
if (document.activeElement === firstFocusableEl.value) {
event.preventDefault()
lastFocusableEl.value!.focus()
}
}
function handleForwardMove(event: KeyboardEvent): void {
if (document.activeElement === lastFocusableEl.value) {
event.preventDefault()
firstFocusableEl.value!.focus()
}
}
function handleKeyDown(event: KeyboardEvent): void {
scanFocusableElements()
if ('Tab' === event.key) {
if (focusableEls.value.length === 1) {
event.preventDefault()
return
}
if (event.shiftKey) {
return handleBackwardMove(event)
}
return handleForwardMove(event)
}
}
function scanFocusableElements() {
const getEls: NodeListOf<Element> = wrapper.value!.querySelectorAll(selectors)
focusableEls.value = Array.from(getEls) as Array<HTMLElement>
firstFocusableEl.value = focusableEls.value[0]
lastFocusableEl.value = focusableEls.value.slice(-1)[0]
}
onMounted(() => {
scanFocusableElements()
wrapper.value!.addEventListener('keydown', handleKeyDown)
firstFocusableEl.value!.focus()
})
</script>
<template>
<div ref="wrapper">
<slot />
</div>
</template>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment