Skip to content

BUGFIX: accept tabindex="-1" in template-require-aria-activedescendant-tabindex#6

Closed
johanrd wants to merge 1 commit intomasterfrom
fix/aria-activedescendant-accept-tabindex-neg1
Closed

BUGFIX: accept tabindex="-1" in template-require-aria-activedescendant-tabindex#6
johanrd wants to merge 1 commit intomasterfrom
fix/aria-activedescendant-accept-tabindex-neg1

Conversation

@johanrd
Copy link
Copy Markdown
Owner

@johanrd johanrd commented Apr 21, 2026

Fix: extend the accepted range from >= 0 to >= -1.

Three test cases moved from invalid to valid; rule doc updated to describe the new accepted range.

Prior art

Plugin Rule Reference
jsx-a11y aria-activedescendant-has-tabindex if (tabIndex >= -1) return;
lit-a11y aria-activedescendant-has-tabindex Same check.

Upstream [email protected] has the same false positive.

…="-1"

Before: any tabindex below 0 was flagged, and the autofix replaced
tabindex="-1" with tabindex="0". That silently changed semantics — -1 is
the canonical "focusable but not in tab order" value that composite
widgets with aria-activedescendant specifically want.

tabindex semantics:
  "0"  — focusable, in the natural tab order
  "-1" — focusable programmatically (e.g. via roving focus), skipped in
         tab order

Both are valid for elements that manage focus via aria-activedescendant;
see the W3C APG entry on "Managing focus in composites using
aria-activedescendant":
  https://www.w3.org/WAI/ARIA/apg/practices/keyboard-interface/#kbd_focus_activedescendant

Matches the check upstream in eslint-plugin-jsx-a11y
(aria-activedescendant-has-tabindex.js: `if (tabIndex >= -1) return;`).
lit-a11y's aria-activedescendant-has-tabindex has the same semantics.

Rule doc updated to describe the new accepted range. Tests moved the
three tabindex="-1" cases from invalid to valid.
@github-actions
Copy link
Copy Markdown

🏎️ Benchmark Comparison

Benchmark Control (p50) Experiment (p50) Δ
js small 13.64 ms 13.64 ms +0.0%
🟢 js medium 6.94 ms 6.71 ms -3.3%
🟢 js large 2.80 ms 2.74 ms -2.1%
gjs small 1.14 ms 1.12 ms -1.1%
gjs medium 560.18 µs 561.14 µs +0.2%
gjs large 222.83 µs 223.35 µs +0.2%
gts small 1.13 ms 1.14 ms +0.9%
gts medium 563.41 µs 561.52 µs -0.3%
gts large 222.57 µs 222.64 µs +0.0%

🟢 faster · 🔴 slower · 🟠 slightly slower · ⚪ within 2%

Full mitata output
clk: ~2.75 GHz
cpu: AMD EPYC 9V74 80-Core Processor
runtime: node 24.14.1 (x64-linux)

benchmark                   avg (min … max) p75 / p99    (min … top 1%)
------------------------------------------- -------------------------------
js small (control)            17.13 ms/iter  19.35 ms █                    
                      (11.63 ms … 35.41 ms)  31.31 ms █ █                  
                    (  5.69 mb …  10.13 mb)   7.30 mb ████▄▆▆▁▄▁▄▄▁▄▄▁▆▁▄▁▄

js small (experiment)         14.40 ms/iter  15.29 ms   ██▄                
                      (12.09 ms … 20.97 ms)  19.98 ms  ████▅  █            
                    (  6.14 mb …   8.30 mb)   6.84 mb ███████▅█▅█▅▁█▁▁▁▅▁▁▅

                             ┌                                            ┐
                             ╷┌───────────┬────┐                          ╷
          js small (control) ├┤           │    ├──────────────────────────┤
                             ╵└───────────┴────┘                          ╵
                              ╷ ┌──┬─┐          ╷
       js small (experiment)  ├─┤  │ ├──────────┤
                              ╵ └──┴─┘          ╵
                             └                                            ┘
                             11.63 ms           21.47 ms           31.31 ms

summary
  js small (experiment)
   1.19x faster than js small (control)

------------------------------------------- -------------------------------
js medium (control)            7.74 ms/iter   8.30 ms  █                   
                       (6.32 ms … 15.57 ms)  15.24 ms ██▂                  
                    (  2.64 mb …   4.57 mb)   3.57 mb ███▆▅▇▄▄▂▄▁▂▂▁▂▁▁▁▁▁▂

js medium (experiment)         7.47 ms/iter   7.76 ms █▂                   
                       (6.31 ms … 14.99 ms)  13.98 ms ██                   
                    (  2.71 mb …   4.29 mb)   3.54 mb ███▄▅▆▃▃▂▂▃▁▁▁▁▁▁▂▂▁▂

                             ┌                                            ┐
                             ╷┌─────┬──┐                                  ╷
         js medium (control) ├┤     │  ├──────────────────────────────────┤
                             ╵└─────┴──┘                                  ╵
                             ╷┌────┬┐                               ╷
      js medium (experiment) ├┤    │├───────────────────────────────┤
                             ╵└────┴┘                               ╵
                             └                                            ┘
                             6.31 ms           10.78 ms            15.24 ms

summary
  js medium (experiment)
   1.04x faster than js medium (control)

------------------------------------------- -------------------------------
js large (control)             3.38 ms/iter   3.47 ms  █                   
                       (2.38 ms … 14.34 ms)   8.58 ms  █                   
                    (313.74 kb …   2.91 mb)   1.44 mb ▄█▇▃▄▃▂▁▁▁▁▃▂▁▁▁▁▁▁▁▁

js large (experiment)          3.13 ms/iter   3.18 ms  █                   
                        (2.48 ms … 8.20 ms)   6.52 ms  █                   
                    (780.30 kb …   2.23 mb)   1.43 mb ▇█▇▃▃▂▂▂▃▂▁▁▂▁▁▁▁▂▁▁▁

                             ┌                                            ┐
                             ╷ ┌────┬┐                                    ╷
          js large (control) ├─┤    │├────────────────────────────────────┤
                             ╵ └────┴┘                                    ╵
                              ╷┌──┬┐                       ╷
       js large (experiment)  ├┤  │├───────────────────────┤
                              ╵└──┴┘                       ╵
                             └                                            ┘
                             2.38 ms            5.48 ms             8.58 ms

summary
  js large (experiment)
   1.08x faster than js large (control)

------------------------------------------- -------------------------------
gjs small (control)            1.27 ms/iter   1.17 ms █                    
                        (1.09 ms … 7.13 ms)   6.18 ms █                    
                    (272.45 kb …   1.66 mb)   1.06 mb █▂▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁

gjs small (experiment)         1.26 ms/iter   1.14 ms █                    
                        (1.09 ms … 6.62 ms)   6.16 ms █                    
                    (248.27 kb …   1.79 mb)   1.06 mb █▂▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁

                             ┌                                            ┐
                             ┌─┬                                          ╷
         gjs small (control) │ │──────────────────────────────────────────┤
                             └─┴                                          ╵
                             ┌┬                                           ╷
      gjs small (experiment) ││───────────────────────────────────────────┤
                             └┴                                           ╵
                             └                                            ┘
                             1.09 ms            3.64 ms             6.18 ms

summary
  gjs small (experiment)
   1.01x faster than gjs small (control)

------------------------------------------- -------------------------------
gjs medium (control)         623.09 µs/iter 568.93 µs █                    
                      (540.29 µs … 6.59 ms)   3.55 ms █                    
                    (124.90 kb …   1.23 mb) 541.06 kb █▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁

gjs medium (experiment)      623.69 µs/iter 569.53 µs █                    
                      (540.23 µs … 6.78 ms)   2.12 ms █                    
                    (348.97 kb …   1.26 mb) 541.53 kb █▄▂▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁

                             ┌                                            ┐
                             ┌┬                                           ╷
        gjs medium (control) ││───────────────────────────────────────────┤
                             └┴                                           ╵
                             ┌┬                      ╷
     gjs medium (experiment) ││──────────────────────┤
                             └┴                      ╵
                             └                                            ┘
                             540.23 µs           2.04 ms            3.55 ms

summary
  gjs medium (control)
   1x faster than gjs medium (experiment)

------------------------------------------- -------------------------------
gjs large (control)          256.65 µs/iter 231.40 µs  █                   
                      (215.36 µs … 6.64 ms) 398.39 µs ▆█▂                  
                    (182.86 kb …   1.31 mb) 217.56 kb ███▃▂▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁

gjs large (experiment)       248.57 µs/iter 230.16 µs  ▅█                  
                      (214.07 µs … 6.15 ms) 315.63 µs  ██                  
                    ( 63.98 kb … 739.05 kb) 216.53 kb ▃██▇█▄▂▁▁▁▁▁▁▁▁▁▁▁▁▁▁

                             ┌                                            ┐
                             ╷┌────────┬                                  ╷
         gjs large (control) ├┤        │──────────────────────────────────┤
                             ╵└────────┴                                  ╵
                             ╷ ┌─────┬                ╷
      gjs large (experiment) ├─┤     │────────────────┤
                             ╵ └─────┴                ╵
                             └                                            ┘
                             214.07 µs         306.23 µs          398.39 µs

summary
  gjs large (experiment)
   1.03x faster than gjs large (control)

------------------------------------------- -------------------------------
gts small (control)            1.42 ms/iter   1.22 ms █                    
                        (1.09 ms … 8.48 ms)   7.00 ms █                    
                    (222.98 kb …   1.73 mb)   1.06 mb █▅▂▁▁▁▁▁▂▁▁▁▁▁▁▁▁▁▁▁▁

gts small (experiment)         1.38 ms/iter   1.36 ms █                    
                       (1.10 ms … 10.40 ms)   7.02 ms █▂                   
                    (227.96 kb …   1.94 mb)   1.05 mb ██▃▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁

                             ┌                                            ┐
                             ┌─┬                                          ╷
         gts small (control) │ │──────────────────────────────────────────┤
                             └─┴                                          ╵
                             ┌─┬                                          ╷
      gts small (experiment) │ │──────────────────────────────────────────┤
                             └─┴                                          ╵
                             └                                            ┘
                             1.09 ms            4.06 ms             7.02 ms

summary
  gts small (experiment)
   1.03x faster than gts small (control)

------------------------------------------- -------------------------------
gts medium (control)         615.76 µs/iter 570.61 µs █                    
                      (542.18 µs … 6.82 ms)   1.55 ms █▅                   
                    (540.29 kb …   1.08 mb) 542.15 kb ██▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁

gts medium (experiment)      632.22 µs/iter 570.01 µs █                    
                      (539.21 µs … 7.29 ms)   3.67 ms █                    
                    ( 88.69 kb …   1.04 mb) 541.26 kb █▂▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁

                             ┌                                            ┐
                             ┌┬             ╷
        gts medium (control) ││─────────────┤
                             └┴             ╵
                             ┌┬                                           ╷
     gts medium (experiment) ││───────────────────────────────────────────┤
                             └┴                                           ╵
                             └                                            ┘
                             539.21 µs           2.10 ms            3.67 ms

summary
  gts medium (control)
   1.03x faster than gts medium (experiment)

------------------------------------------- -------------------------------
gts large (control)          245.06 µs/iter 228.78 µs  █▆                  
                      (214.05 µs … 5.80 ms) 307.45 µs  ██                  
                    (216.09 kb … 913.40 kb) 217.01 kb ▃████▅▂▁▁▁▁▁▁▁▁▁▁▁▁▁▁

gts large (experiment)       249.95 µs/iter 230.12 µs  █                   
                      (214.48 µs … 6.28 ms) 336.29 µs  █                   
                    (162.19 kb … 953.01 kb) 216.69 kb ▃██▇▃▂▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁

                             ┌                                            ┐
                             ╷ ┌────────┬                      ╷
         gts large (control) ├─┤        │──────────────────────┤
                             ╵ └────────┴                      ╵
                             ╷ ┌──────────┬                               ╷
      gts large (experiment) ├─┤          │───────────────────────────────┤
                             ╵ └──────────┴                               ╵
                             └                                            ┘
                             214.05 µs         275.17 µs          336.29 µs

summary
  gts large (control)
   1.02x faster than gts large (experiment)

@johanrd
Copy link
Copy Markdown
Owner Author

johanrd commented Apr 21, 2026

Moved upstream to ember-cli#2714. See that PR for ongoing review.

@johanrd johanrd closed this Apr 21, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant