본문 바로가기
코딩,프로그램

Blocked aria-hidden on an element because its descendant retained focus. The focus must not be hidden from assistive technology users. Avoid using aria-hidden on a focused element or its ancestor. Consider using the inert attribute instead, which will als

by successmylife 2025. 1. 22.

 

부트스트랩을 이용해서 프로그램을 사용중인데, 모달창이 닫힐때 항상 아래의 오류가 난다. 이 부분에 대한 해결책이 궁금하다.

list_mat.php:1 Blocked aria-hidden on an element because its descendant retained focus. The focus must not be hidden from assistive technology users. Avoid using aria-hidden on a focused element or its ancestor. Consider using the inert attribute instead, which will also prevent focus. For more details, see the aria-hidden section of the WAI-ARIA specification at https://w3c.github.io/aria/#aria-hidden.

Element with focus: button

Ancestor with aria-hidden: <div class=​"modal fade" id=​"detailModal" tabindex=​"-1" aria-labelledby=​"detailModalLabel" style=​"display:​ block;​ padding-left:​ 0px;​" aria-hidden=​"true">​…​</div>​

 

이제 인공지능의 능력을 이용해서 해결해 보는 과정을 담아봅니다.

 

질문하기 : )

 

이미 CDN은 선언되어있고, 해당 코드를 공유한다.

  1. 자바스크립트

$(document).ready(function(){

// 검색 버튼 클릭 시 폼 제출

$("#searchBtn").click(function(){

$("#board_form").submit();

});

// 테이블 행 클릭 시 상세 모달 열기

$("#myTable tbody tr").on('click', function(){

var steel_item = $(this).data('steel-item');

var spec = $(this).data('spec');

// AJAX 요청으로 상세 내역 가져오기

$.ajax({

url: 'fetch_detail.php',

type: 'POST',

data: { steel_item: steel_item, spec: spec },

dataType: 'json',

success: function(response){

if(response.error){

alert('오류: ' + response.error);

} else {

var tbody = $('#detailTable tbody');

tbody.empty();

$.each(response, function(index, row){

var tr = '<tr>' +

'<td class="text-center">' + row.inoutdate + '</td>' +

'<td class="text-center">' + row.item_code + '</td>' +

'<td class="text-center">' + row.spec + '</td>' +

'<td class="text-center">' + (row.total_in !== '' ? numberWithCommas(row.total_in) : '') + '</td>' +

'<td class="text-center">' + (row.total_out !== '' ? numberWithCommas(row.total_out) : '') + '</td>' +

'<td class="text-center">' + (row.stock !== '' ? numberWithCommas(row.stock) : '') + '</td>' +

'<td class="text-center">' + row.workplacename + '</td>' +

'<td class="text-center">' + row.secondord + '</td>' +

'<td class="text-center">' + row.supplier + '</td>' +

'<td class="text-center">' + row.company + '</td>' +

'</tr>';

tbody.append(tr);

});

// 모달 열기

var detailModal = new bootstrap.Modal(document.getElementById('detailModal'));

detailModal.show();

}

},

error: function(xhr, status, error){

console.error(xhr);

alert('데이터를 불러오는 중 오류가 발생했습니다.');

}

});

});

function numberWithCommas(x) {

if(x === '' || x === null) return '';

return x.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ",");

}

});

```````````````````````````

  1. html 코드

<!-- 8. 모달 창 (재고 상세 내역) -->

<div class="modal fade" id="detailModal" tabindex="-1" aria-labelledby="detailModalLabel" aria-hidden="true">

<div class="modal-dialog modal-full">

<div class="modal-content table-container">

<div class="modal-header">

<h5 id="detailModalLabel" class="modal-title">재고 상세 내역</h5>

<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="닫기"></button>

</div>

<div class="modal-body">

<table class="table table-hover" id="detailTable">

<thead class="table-primary">

<tr>

<th class="text-center" >입출고일자</th>

<th class="text-center" >품목코드</th>

<th class="text-center" >규격</th>

<th class="text-center" >입고수량</th>

<th class="text-center" >출고수량</th>

<th class="text-center" >재고</th>

<th class="text-center" >현장명</th>

<th class="text-center" >발주처</th>

<th class="text-center" >공급처</th>

<th class="text-center" >사급</th>

</tr>

</thead>

<tbody>

<!-- AJAX로 로드된 데이터 -->

</tbody>

</table>

</div>

<div class="modal-footer">

<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">닫기</button>

<button type="button" class="btn btn-success downloadExcel">엑셀 다운로드</button>

</div>

</div>

</div>

</div>

 

클로드에게 물어본 결과를 공유해 봅니다.

 

이 오류는 모달이 닫힐 때 접근성(accessibility) 관련 문제가 발생하는 것입니다. 주요 원인은 모달이 닫힐 때 `aria-hidden="true"`가 설정되어 있는데, 내부에 포커스 가능한 요소(버튼 등)가 있어서 발생하는 충돌입니다.

이 문제를 해결하기 위해 다음과 같은 방법들을 시도해볼 수 있습니다:

1. 모달 설정을 수정하는 방법:
```javascript
$(document).ready(function(){
    // 모달 인스턴스 생성
    const detailModal = new bootstrap.Modal(document.getElementById('detailModal'), {
        backdrop: 'static',  // 배경 클릭으로 닫히지 않도록 설정
        keyboard: true      // ESC로 닫을 수 있도록 설정
    });

    // 모달이 완전히 닫힌 후 포커스 처리
    $('#detailModal').on('hidden.bs.modal', function () {
        // 포커스를 다른 요소로 이동
        document.body.focus();
    });
```

2. HTML 구조 수정:
```html
<div class="modal fade" id="detailModal" tabindex="-1" aria-labelledby="detailModalLabel">
    <!-- aria-hidden 속성 제거 -->
    <div class="modal-dialog modal-full" role="document">
        <div class="modal-content table-container">
            <!-- 나머지 코드는 동일 -->
        </div>
    </div>
</div>
```

3. 모달 닫기 버튼의 처리를 수정:
```javascript
// 모달 닫기 버튼 클릭 이벤트
$('.btn-close, .btn-secondary').on('click', function() {
    // 포커스를 해제하고 모달 닫기
    $(this).blur();
    detailModal.hide();
});
```

4. CSS를 통한 해결방법:
```css
.modal.fade {
    &[aria-hidden="true"] {
        pointer-events: none;
        
        button, [tabindex] {
            pointer-events: none;
            tabindex: -1;
        }
    }
}
```

이러한 방법들을 조합하여 사용하면 오류를 해결할 수 있습니다. 가장 추천하는 방법은 1번과 2번을 함께 적용하는 것입니다. 이렇게 하면:

1. 모달이 닫힐 때 포커스가 적절히 처리됩니다.
2. 접근성 관련 속성들이 올바르게 설정됩니다.
3. 스크린 리더 사용자들에게도 더 나은 경험을 제공할 수 있습니다.

추가로, Bootstrap 5.x 버전을 사용중이라면, 최신 버전으로 업데이트하는 것도 이 문제를 해결하는데 도움이 될 수 있습니다.

 

$(document).ready(function(){
    // 검색 버튼 클릭 시 폼 제출
    $("#searchBtn").click(function(){
        $("#board_form").submit();
    });

    // 테이블 행 클릭 시 상세 모달 열기
    $("#myTable tbody tr").on('click', function(){
        var steel_item = $(this).data('steel-item');
        var spec = $(this).data('spec');

        // AJAX 요청으로 상세 내역 가져오기
        $.ajax({
            url: 'fetch_detail.php',
            type: 'POST',
            data: { steel_item: steel_item, spec: spec },
            dataType: 'json',
			success: function(response){
				if(response.error){
					alert('오류: ' + response.error);
				} else {
					var tbody = $('#detailTable tbody');
					tbody.empty();
					$.each(response, function(index, row){
						var tr = '<tr>' +
							'<td class="text-center">' + row.inoutdate + '</td>' +
							'<td class="text-center">' + row.item_code + '</td>' +
							'<td class="text-center">' + row.spec + '</td>' +
							'<td class="text-center">' + (row.total_in !== '' ? numberWithCommas(row.total_in) : '') + '</td>' +
							'<td class="text-center">' + (row.total_out !== '' ? numberWithCommas(row.total_out) : '') + '</td>' +
							'<td class="text-center">' + (row.stock !== '' ? numberWithCommas(row.stock) : '') + '</td>' +
							'<td class="text-center">' + row.workplacename + '</td>' +
							'<td class="text-center">' + row.secondord + '</td>' +
							'<td class="text-center">' + row.supplier + '</td>' +
							'<td class="text-center">' + row.company + '</td>' +
							'</tr>';
						tbody.append(tr);
					});
					// 모달 열기
					var detailModal = new bootstrap.Modal(document.getElementById('detailModal'));
					detailModal.show();
					// 모달이 완전히 닫힌 후 포커스 처리
					$('#detailModal').on('hidden.bs.modal', function () {
						// 포커스를 다른 요소로 이동
						document.body.focus();
					});		
					// 모달 닫기 버튼 클릭 이벤트
					$('.btn-close').on('click', function() {
						// 포커스를 해제하고 모달 닫기
						$(this).blur();
						detailModal.hide();
					});
				}
			},
            error: function(xhr, status, error){
                console.error(xhr);
                alert('데이터를 불러오는 중 오류가 발생했습니다.');
            }
        });
    });

	function numberWithCommas(x) {
		if(x === '' || x === null) return '';
		return x.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ",");
	}

});

 

위의 코드로 실행하니 실제 오류가 없어졌다.

 

정말 많은 고민을 했던 부분인데... 해소되서 너무 좋다.

 

chatGPT에서는 사실 해결되지 않는 것인데, 클로드가 더 코드지향적인가?라는 생각을 잠시 하게 되네요~

 

더 코드개발하는 사람에게 적합한 것이 클로드가 아닌가 싶은 시점입니다.

 

아직 유료결재를 안해서... 하루 무료량만 사용하고 있지만, 조만간 결재를 해야할 것 같아요^^

 

 

실제 모달창이 뜨고 오류가 없는 것을 확인했습니다.

 

 

반응형