primeng icon indicating copy to clipboard operation
primeng copied to clipboard

Panel: Broken aria-labelledby (id off by one)

Open thesam opened this issue 1 year ago • 3 comments

Describe the bug

The panel content has an aria-labelledby attribute which is supposed to refer to the panel header.

<div role="region" class="p-toggleable-content ng-tns-c1141093477-0 ng-trigger ng-trigger-panelContent" id="pn_id_7_content" aria-labelledby="pn_id_8_header">

The id is generated automatically in the component. pn_id_7_content should refer to pn_id_7_header but right now it refers to pn_id_8_header.

I think the cause of this problem is that the id() getter is called twice from the template, which returns two different id:s.

Environment

PrimeNG examples: https://primeng.org/panel

Reproducer

https://stackblitz.com/edit/2fkkkb?file=src%2Fapp%2Fdemo%2Fpanel-basic-demo.html

Angular version

16.2.0

PrimeNG version

16.8.0

Build / Runtime

Angular CLI App

Language

TypeScript

Node version (for AoT issues node --version)

N/A

Browser(s)

Chrome

Steps to reproduce the behavior

Create a PrimeNG Panel

Expected behavior

No response

thesam avatar Nov 21 '23 13:11 thesam

was this fixed?

adulfan avatar Jan 11 '24 19:01 adulfan

in version 17 the problem changed. the id counter is right but if we use a custom header it points to a non existing element. Can be reproduced here: https://primeng.org/panel#template:

image

bschnabel avatar Jun 20 '24 10:06 bschnabel

I implemented a workaround for this bug as an Angular directive:

import { AfterViewInit, Directive, ElementRef } from '@angular/core';

/**
 * This is a workaround for the ariaref bug reported here: https://github.com/primefaces/primeng/issues/14166#issuecomment-2180395602
 *
 */
@Directive({
  // eslint-disable-next-line @angular-eslint/directive-selector
  selector: 'p-panel',
})
export class PrimengPanelAriarefFixDirective implements AfterViewInit {
  constructor(private element: ElementRef) {}

  ngAfterViewInit(): void {
    const elem = this.element.nativeElement.querySelector(
      'div[role=region]'
    ) as HTMLDivElement;
    const id = elem.getAttribute('aria-labelledby');

    // check if element with id exists, if not, remove the aria-labelledby attribute
    if (!document.getElementById(id)) {
      elem.removeAttribute('aria-labelledby');
    }
  }
}

I put it in a shared module which gets imported everywhere where the I use p-panel with custom headers.

bschnabel avatar Jun 21 '24 08:06 bschnabel

Hi,

So sorry for the delayed response! Improvements have been made to many components recently, both in terms of performance and enhancement. Therefore, this improvement may have been developed in another issue ticket without realizing it. You can check this in the documentation. If there is no improvement on this, can you reopen the issue so we can include it in our roadmap? Please don't forget to add your feedback as a comment after reopening the issue. These will be taken into account by us and will contribute to the development of this feature. Thanks a lot for your understanding!

Best Regards,

mertsincan avatar Dec 04 '24 11:12 mertsincan

@mertsincan I do not seem to have permissions to reopen an issue.

So my feedback as a comment: the behaviour is still not right. you can check in on https://primeng.org/panel#template

image

the reference is not pointing to the header but to the toggle button

bschnabel avatar Dec 04 '24 11:12 bschnabel