next js 바텀 시트 접근성 적용

interface BottomSheetAccessibilityManagerProps {
  isOpen: boolean;
  bottomSheetId: string;
  children: React.ReactNode;
  initialFocusElementId?: string;
}

const BottomSheetAccessibilityManager = ({ 
  isOpen, 
  bottomSheetId, 
  children,
  initialFocusElementId 
}: BottomSheetAccessibilityManagerProps) => {
  const previousFocusRef = useRef<HTMLElement | null>(null);

  useEffect(() => {
    const bottomSheet = document.getElementById(bottomSheetId);
    
    if (isOpen && bottomSheet) {
      // 현재 포커스 저장
      previousFocusRef.current = document.activeElement as HTMLElement;
      
      // 형제 요소들 inert 처리
      const siblings = Array.from(bottomSheet.parentElement?.children || [])
        .filter(child => child !== bottomSheet);
      siblings.forEach(sibling => {
        sibling.setAttribute('inert', '');
      });

      // 포커스 이동 처리
      setTimeout(() => {
        // 페이지 로딩 시 자동 오픈이거나 이전 포커스가 없는 경우
        if (!previousFocusRef.current || previousFocusRef.current === document.body) {
          if (initialFocusElementId) {
            const initialFocusElement = document.getElementById(initialFocusElementId);
            if (initialFocusElement) {
              initialFocusElement.focus();
              return;
            }
          }
        }

        // 일반적인 포커스 이동 처리
        const focusableElement = bottomSheet.querySelector(
          'button, [href], input, select, textarea, [tabindex]:not([tabindex="-1"])'
        ) as HTMLElement;

        if (focusableElement) {
          focusableElement.focus();
        } else {
          bottomSheet.setAttribute('tabindex', '-1');
          bottomSheet.focus();
        }
      }, 500);
      
    } else if (!isOpen && bottomSheet) {
      // inert 속성 제거
      const siblings = Array.from(bottomSheet.parentElement?.children || [])
        .filter(child => child !== bottomSheet);
      siblings.forEach(sibling => {
        sibling.removeAttribute('inert');
      });

      // 이전 포커스로 복귀
      // 이전 포커스가 유효한 경우에만 포커스 이동
      setTimeout(() => {
        if (previousFocusRef.current && previousFocusRef.current !== document.body) {
          previousFocusRef.current.focus();
        }
      }, 500);
    }
  }, [isOpen, bottomSheetId, initialFocusElementId]);

  return <>{children}</>;
};

export default BottomSheetAccessibilityManager;

Comments

답글 남기기