@@ -150,17 +150,38 @@ module.exports = {
150150 const sourceCode = context . sourceCode || context . getSourceCode ( ) ;
151151 return {
152152 GlimmerElementNode ( node ) {
153- if ( node . tag !== 'a' ) {
153+ // Only the native <a> element — in strict GJS, a lowercase tag can be
154+ // shadowed by an in-scope local binding, and components shouldn't be
155+ // validated here. `isNativeElement` combines authoritative html/svg/
156+ // mathml tag lists with scope-shadowing detection.
157+ if ( ! isNativeElement ( node , sourceCode ) ) {
158+ return ;
159+ }
160+ if ( node . tag ?. toLowerCase ( ) !== 'a' ) {
154161 return ;
155162 }
156163
157164 // Only anchors acting as links (with href) are in scope. An <a> without
158165 // href is covered by `template-link-href-attributes` / not a link.
159- const hasHref = ( node . attributes || [ ] ) . some ( ( a ) => a . name === 'href' ) ;
166+ const attrs = node . attributes || [ ] ;
167+ const hasHref = attrs . some ( ( a ) => a . name === 'href' ) ;
160168 if ( ! hasHref ) {
161169 return ;
162170 }
163171
172+ // Skip anchors the author has explicitly hidden — either via the HTML
173+ // `hidden` boolean attribute (element is not rendered at all) or
174+ // `aria-hidden="true"` (element removed from the accessibility tree).
175+ // In both cases, "accessible name of an anchor" is moot.
176+ const hasHidden = attrs . some ( ( a ) => a . name === 'hidden' ) ;
177+ if ( hasHidden ) {
178+ return ;
179+ }
180+ const ariaHiddenAttr = attrs . find ( ( a ) => a . name === 'aria-hidden' ) ;
181+ if ( isAriaHiddenTrue ( ariaHiddenAttr ) ) {
182+ return ;
183+ }
184+
164185 if ( hasAccessibleNameAttribute ( node ) ) {
165186 return ;
166187 }
0 commit comments