useTrapTab.ts 1.6 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859
  1. // Copyright (C) 2012-2024 Zammad Foundation, https://zammad-foundation.org/
  2. import { ref, type Ref } from 'vue'
  3. import { getFocusableElements } from '#shared/utils/getFocusableElements.ts'
  4. import { onKeyStroke } from '@vueuse/core'
  5. export const useTrapTab = (
  6. container: Ref<HTMLElement | undefined>,
  7. noAutoActivation = false,
  8. ) => {
  9. const trapFocus = (e: KeyboardEvent) => {
  10. const focusableElements = getFocusableElements(container.value)
  11. const firstFocusableElement = focusableElements[0]
  12. const lastFocusableElement = focusableElements[focusableElements.length - 1]
  13. if (e.shiftKey) {
  14. // if shift key pressed for shift + tab combination
  15. if (document.activeElement === firstFocusableElement) {
  16. lastFocusableElement.focus() // add focus for the last focusable element
  17. e.preventDefault()
  18. }
  19. return
  20. }
  21. if (document.activeElement === lastFocusableElement) {
  22. // if focused has reached to last focusable element then focus first focusable element after pressing tab
  23. firstFocusableElement.focus() // add focus for the first focusable element
  24. e.preventDefault()
  25. }
  26. }
  27. const active = ref(!noAutoActivation)
  28. const activateTabTrap = () => {
  29. active.value = true
  30. }
  31. const deactivateTabTrap = () => {
  32. active.value = false
  33. }
  34. onKeyStroke(
  35. (e) => {
  36. if (!active.value) return
  37. const isTab = e.key === 'Tab' || e.keyCode === 9
  38. if (!isTab) return
  39. trapFocus(e)
  40. },
  41. { target: container as Ref<EventTarget> },
  42. )
  43. return {
  44. activateTabTrap,
  45. deactivateTabTrap,
  46. }
  47. }