Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ES Lint: Add a rule to prevent use of the disabled attribute #59518

Closed
wants to merge 1 commit into from

Conversation

scruffian
Copy link
Contributor

What?

Adds a rule to prevent the use of the disabled attribute.

Why?

The disabled attribute should be banned in this project. It causes accessibility issues for keyboard and screen reader users but offers developers a very nice shortcut.

How?

Adds a new ES Lint rule to catch this.

Testing Instructions

  1. Add disabled to any React component
  2. Try to commit your change
  3. The linter should stop you

@scruffian scruffian added [Focus] Accessibility (a11y) Changes that impact accessibility and need corresponding review (e.g. markup changes). [Type] Code Quality Issues or PRs that relate to code quality labels Mar 1, 2024
@scruffian scruffian requested a review from alexstine March 1, 2024 23:00
@scruffian scruffian self-assigned this Mar 1, 2024
Copy link

github-actions bot commented Mar 1, 2024

The following accounts have interacted with this PR and/or linked issues. I will continue to update these lists as activity occurs. You can also manually ask me to refresh this list by adding the props-bot label.

If you're merging code through a pull request on GitHub, copy and paste the following into the bottom of the merge commit message.

Co-authored-by: scruffian <scruffian@git.wordpress.org>
Co-authored-by: alexstine <alexstine@git.wordpress.org>
Co-authored-by: draganescu <andraganescu@git.wordpress.org>
Co-authored-by: joedolson <joedolson@git.wordpress.org>
Co-authored-by: jeryj <jeryj@git.wordpress.org>
Co-authored-by: andrewhayward <andrewhayward@git.wordpress.org>
Co-authored-by: mirka <0mirka00@git.wordpress.org>
Co-authored-by: afercia <afercia@git.wordpress.org>
Co-authored-by: tyxla <tyxla@git.wordpress.org>

To understand the WordPress project's expectations around crediting contributors, please review the Contributor Attribution page in the Core Handbook.

Copy link

github-actions bot commented Mar 1, 2024

Size Change: 0 B

Total Size: 1.71 MB

ℹ️ View Unchanged
Filename Size
build/a11y/index.min.js 955 B
build/annotations/index.min.js 2.69 kB
build/api-fetch/index.min.js 2.32 kB
build/autop/index.min.js 2.1 kB
build/blob/index.min.js 578 B
build/block-directory/index.min.js 7.22 kB
build/block-directory/style-rtl.css 1.03 kB
build/block-directory/style.css 1.03 kB
build/block-editor/content-rtl.css 4.38 kB
build/block-editor/content.css 4.38 kB
build/block-editor/default-editor-styles-rtl.css 394 B
build/block-editor/default-editor-styles.css 394 B
build/block-editor/index.min.js 252 kB
build/block-editor/style-rtl.css 15.7 kB
build/block-editor/style.css 15.7 kB
build/block-library/blocks/archives/editor-rtl.css 61 B
build/block-library/blocks/archives/editor.css 60 B
build/block-library/blocks/archives/style-rtl.css 90 B
build/block-library/blocks/archives/style.css 90 B
build/block-library/blocks/audio/editor-rtl.css 150 B
build/block-library/blocks/audio/editor.css 150 B
build/block-library/blocks/audio/style-rtl.css 122 B
build/block-library/blocks/audio/style.css 122 B
build/block-library/blocks/audio/theme-rtl.css 126 B
build/block-library/blocks/audio/theme.css 126 B
build/block-library/blocks/avatar/editor-rtl.css 116 B
build/block-library/blocks/avatar/editor.css 116 B
build/block-library/blocks/avatar/style-rtl.css 104 B
build/block-library/blocks/avatar/style.css 104 B
build/block-library/blocks/block/editor-rtl.css 305 B
build/block-library/blocks/block/editor.css 305 B
build/block-library/blocks/button/editor-rtl.css 415 B
build/block-library/blocks/button/editor.css 414 B
build/block-library/blocks/button/style-rtl.css 627 B
build/block-library/blocks/button/style.css 626 B
build/block-library/blocks/buttons/editor-rtl.css 337 B
build/block-library/blocks/buttons/editor.css 337 B
build/block-library/blocks/buttons/style-rtl.css 332 B
build/block-library/blocks/buttons/style.css 332 B
build/block-library/blocks/calendar/style-rtl.css 239 B
build/block-library/blocks/calendar/style.css 239 B
build/block-library/blocks/categories/editor-rtl.css 113 B
build/block-library/blocks/categories/editor.css 112 B
build/block-library/blocks/categories/style-rtl.css 124 B
build/block-library/blocks/categories/style.css 124 B
build/block-library/blocks/code/editor-rtl.css 53 B
build/block-library/blocks/code/editor.css 53 B
build/block-library/blocks/code/style-rtl.css 121 B
build/block-library/blocks/code/style.css 121 B
build/block-library/blocks/code/theme-rtl.css 124 B
build/block-library/blocks/code/theme.css 124 B
build/block-library/blocks/columns/editor-rtl.css 108 B
build/block-library/blocks/columns/editor.css 108 B
build/block-library/blocks/columns/style-rtl.css 421 B
build/block-library/blocks/columns/style.css 421 B
build/block-library/blocks/comment-author-avatar/editor-rtl.css 125 B
build/block-library/blocks/comment-author-avatar/editor.css 125 B
build/block-library/blocks/comment-content/style-rtl.css 92 B
build/block-library/blocks/comment-content/style.css 92 B
build/block-library/blocks/comment-template/style-rtl.css 199 B
build/block-library/blocks/comment-template/style.css 198 B
build/block-library/blocks/comments-pagination-numbers/editor-rtl.css 123 B
build/block-library/blocks/comments-pagination-numbers/editor.css 121 B
build/block-library/blocks/comments-pagination/editor-rtl.css 222 B
build/block-library/blocks/comments-pagination/editor.css 209 B
build/block-library/blocks/comments-pagination/style-rtl.css 235 B
build/block-library/blocks/comments-pagination/style.css 231 B
build/block-library/blocks/comments-title/editor-rtl.css 75 B
build/block-library/blocks/comments-title/editor.css 75 B
build/block-library/blocks/comments/editor-rtl.css 840 B
build/block-library/blocks/comments/editor.css 839 B
build/block-library/blocks/comments/style-rtl.css 637 B
build/block-library/blocks/comments/style.css 636 B
build/block-library/blocks/cover/editor-rtl.css 647 B
build/block-library/blocks/cover/editor.css 650 B
build/block-library/blocks/cover/style-rtl.css 1.69 kB
build/block-library/blocks/cover/style.css 1.68 kB
build/block-library/blocks/details/editor-rtl.css 65 B
build/block-library/blocks/details/editor.css 65 B
build/block-library/blocks/details/style-rtl.css 98 B
build/block-library/blocks/details/style.css 98 B
build/block-library/blocks/embed/editor-rtl.css 322 B
build/block-library/blocks/embed/editor.css 322 B
build/block-library/blocks/embed/style-rtl.css 410 B
build/block-library/blocks/embed/style.css 410 B
build/block-library/blocks/embed/theme-rtl.css 126 B
build/block-library/blocks/embed/theme.css 126 B
build/block-library/blocks/file/editor-rtl.css 316 B
build/block-library/blocks/file/editor.css 316 B
build/block-library/blocks/file/style-rtl.css 280 B
build/block-library/blocks/file/style.css 281 B
build/block-library/blocks/file/view.min.js 324 B
build/block-library/blocks/footnotes/style-rtl.css 201 B
build/block-library/blocks/footnotes/style.css 199 B
build/block-library/blocks/form-input/editor-rtl.css 227 B
build/block-library/blocks/form-input/editor.css 227 B
build/block-library/blocks/form-input/style-rtl.css 343 B
build/block-library/blocks/form-input/style.css 343 B
build/block-library/blocks/form-submission-notification/editor-rtl.css 340 B
build/block-library/blocks/form-submission-notification/editor.css 340 B
build/block-library/blocks/form-submit-button/style-rtl.css 69 B
build/block-library/blocks/form-submit-button/style.css 69 B
build/block-library/blocks/form/view.min.js 471 B
build/block-library/blocks/freeform/editor-rtl.css 2.61 kB
build/block-library/blocks/freeform/editor.css 2.61 kB
build/block-library/blocks/gallery/editor-rtl.css 947 B
build/block-library/blocks/gallery/editor.css 952 B
build/block-library/blocks/gallery/style-rtl.css 1.72 kB
build/block-library/blocks/gallery/style.css 1.72 kB
build/block-library/blocks/gallery/theme-rtl.css 108 B
build/block-library/blocks/gallery/theme.css 108 B
build/block-library/blocks/group/editor-rtl.css 647 B
build/block-library/blocks/group/editor.css 647 B
build/block-library/blocks/group/style-rtl.css 57 B
build/block-library/blocks/group/style.css 57 B
build/block-library/blocks/group/theme-rtl.css 78 B
build/block-library/blocks/group/theme.css 78 B
build/block-library/blocks/heading/style-rtl.css 189 B
build/block-library/blocks/heading/style.css 189 B
build/block-library/blocks/html/editor-rtl.css 336 B
build/block-library/blocks/html/editor.css 337 B
build/block-library/blocks/image/editor-rtl.css 894 B
build/block-library/blocks/image/editor.css 893 B
build/block-library/blocks/image/style-rtl.css 1.6 kB
build/block-library/blocks/image/style.css 1.59 kB
build/block-library/blocks/image/theme-rtl.css 126 B
build/block-library/blocks/image/theme.css 126 B
build/block-library/blocks/image/view.min.js 1.54 kB
build/block-library/blocks/latest-comments/style-rtl.css 357 B
build/block-library/blocks/latest-comments/style.css 357 B
build/block-library/blocks/latest-posts/editor-rtl.css 213 B
build/block-library/blocks/latest-posts/editor.css 212 B
build/block-library/blocks/latest-posts/style-rtl.css 478 B
build/block-library/blocks/latest-posts/style.css 478 B
build/block-library/blocks/list/style-rtl.css 88 B
build/block-library/blocks/list/style.css 88 B
build/block-library/blocks/media-text/editor-rtl.css 266 B
build/block-library/blocks/media-text/editor.css 263 B
build/block-library/blocks/media-text/style-rtl.css 505 B
build/block-library/blocks/media-text/style.css 503 B
build/block-library/blocks/more/editor-rtl.css 431 B
build/block-library/blocks/more/editor.css 431 B
build/block-library/blocks/navigation-link/editor-rtl.css 668 B
build/block-library/blocks/navigation-link/editor.css 669 B
build/block-library/blocks/navigation-link/style-rtl.css 259 B
build/block-library/blocks/navigation-link/style.css 257 B
build/block-library/blocks/navigation-submenu/editor-rtl.css 296 B
build/block-library/blocks/navigation-submenu/editor.css 295 B
build/block-library/blocks/navigation/editor-rtl.css 2.26 kB
build/block-library/blocks/navigation/editor.css 2.26 kB
build/block-library/blocks/navigation/style-rtl.css 2.26 kB
build/block-library/blocks/navigation/style.css 2.25 kB
build/block-library/blocks/navigation/view.min.js 1.02 kB
build/block-library/blocks/nextpage/editor-rtl.css 395 B
build/block-library/blocks/nextpage/editor.css 395 B
build/block-library/blocks/page-list/editor-rtl.css 377 B
build/block-library/blocks/page-list/editor.css 377 B
build/block-library/blocks/page-list/style-rtl.css 175 B
build/block-library/blocks/page-list/style.css 175 B
build/block-library/blocks/paragraph/editor-rtl.css 235 B
build/block-library/blocks/paragraph/editor.css 235 B
build/block-library/blocks/paragraph/style-rtl.css 335 B
build/block-library/blocks/paragraph/style.css 335 B
build/block-library/blocks/post-author/style-rtl.css 175 B
build/block-library/blocks/post-author/style.css 176 B
build/block-library/blocks/post-comments-form/editor-rtl.css 96 B
build/block-library/blocks/post-comments-form/editor.css 96 B
build/block-library/blocks/post-comments-form/style-rtl.css 508 B
build/block-library/blocks/post-comments-form/style.css 508 B
build/block-library/blocks/post-content/editor-rtl.css 74 B
build/block-library/blocks/post-content/editor.css 74 B
build/block-library/blocks/post-date/style-rtl.css 61 B
build/block-library/blocks/post-date/style.css 61 B
build/block-library/blocks/post-excerpt/editor-rtl.css 71 B
build/block-library/blocks/post-excerpt/editor.css 71 B
build/block-library/blocks/post-excerpt/style-rtl.css 141 B
build/block-library/blocks/post-excerpt/style.css 141 B
build/block-library/blocks/post-featured-image/editor-rtl.css 666 B
build/block-library/blocks/post-featured-image/editor.css 662 B
build/block-library/blocks/post-featured-image/style-rtl.css 342 B
build/block-library/blocks/post-featured-image/style.css 342 B
build/block-library/blocks/post-navigation-link/style-rtl.css 215 B
build/block-library/blocks/post-navigation-link/style.css 214 B
build/block-library/blocks/post-template/editor-rtl.css 99 B
build/block-library/blocks/post-template/editor.css 98 B
build/block-library/blocks/post-template/style-rtl.css 409 B
build/block-library/blocks/post-template/style.css 408 B
build/block-library/blocks/post-terms/style-rtl.css 96 B
build/block-library/blocks/post-terms/style.css 96 B
build/block-library/blocks/post-time-to-read/style-rtl.css 69 B
build/block-library/blocks/post-time-to-read/style.css 69 B
build/block-library/blocks/post-title/style-rtl.css 100 B
build/block-library/blocks/post-title/style.css 100 B
build/block-library/blocks/preformatted/style-rtl.css 125 B
build/block-library/blocks/preformatted/style.css 125 B
build/block-library/blocks/pullquote/editor-rtl.css 135 B
build/block-library/blocks/pullquote/editor.css 135 B
build/block-library/blocks/pullquote/style-rtl.css 354 B
build/block-library/blocks/pullquote/style.css 354 B
build/block-library/blocks/pullquote/theme-rtl.css 168 B
build/block-library/blocks/pullquote/theme.css 168 B
build/block-library/blocks/query-pagination-numbers/editor-rtl.css 122 B
build/block-library/blocks/query-pagination-numbers/editor.css 121 B
build/block-library/blocks/query-pagination/editor-rtl.css 221 B
build/block-library/blocks/query-pagination/editor.css 211 B
build/block-library/blocks/query-pagination/style-rtl.css 288 B
build/block-library/blocks/query-pagination/style.css 284 B
build/block-library/blocks/query-title/style-rtl.css 63 B
build/block-library/blocks/query-title/style.css 63 B
build/block-library/blocks/query/editor-rtl.css 486 B
build/block-library/blocks/query/editor.css 486 B
build/block-library/blocks/query/view.min.js 958 B
build/block-library/blocks/quote/style-rtl.css 237 B
build/block-library/blocks/quote/style.css 237 B
build/block-library/blocks/quote/theme-rtl.css 223 B
build/block-library/blocks/quote/theme.css 226 B
build/block-library/blocks/read-more/style-rtl.css 140 B
build/block-library/blocks/read-more/style.css 140 B
build/block-library/blocks/rss/editor-rtl.css 149 B
build/block-library/blocks/rss/editor.css 149 B
build/block-library/blocks/rss/style-rtl.css 289 B
build/block-library/blocks/rss/style.css 288 B
build/block-library/blocks/search/editor-rtl.css 184 B
build/block-library/blocks/search/editor.css 184 B
build/block-library/blocks/search/style-rtl.css 629 B
build/block-library/blocks/search/style.css 628 B
build/block-library/blocks/search/theme-rtl.css 114 B
build/block-library/blocks/search/theme.css 114 B
build/block-library/blocks/search/view.min.js 478 B
build/block-library/blocks/separator/editor-rtl.css 146 B
build/block-library/blocks/separator/editor.css 146 B
build/block-library/blocks/separator/style-rtl.css 229 B
build/block-library/blocks/separator/style.css 229 B
build/block-library/blocks/separator/theme-rtl.css 194 B
build/block-library/blocks/separator/theme.css 194 B
build/block-library/blocks/shortcode/editor-rtl.css 323 B
build/block-library/blocks/shortcode/editor.css 323 B
build/block-library/blocks/site-logo/editor-rtl.css 754 B
build/block-library/blocks/site-logo/editor.css 754 B
build/block-library/blocks/site-logo/style-rtl.css 204 B
build/block-library/blocks/site-logo/style.css 204 B
build/block-library/blocks/site-tagline/editor-rtl.css 86 B
build/block-library/blocks/site-tagline/editor.css 86 B
build/block-library/blocks/site-title/editor-rtl.css 116 B
build/block-library/blocks/site-title/editor.css 116 B
build/block-library/blocks/site-title/style-rtl.css 57 B
build/block-library/blocks/site-title/style.css 57 B
build/block-library/blocks/social-link/editor-rtl.css 184 B
build/block-library/blocks/social-link/editor.css 184 B
build/block-library/blocks/social-links/editor-rtl.css 682 B
build/block-library/blocks/social-links/editor.css 681 B
build/block-library/blocks/social-links/style-rtl.css 1.49 kB
build/block-library/blocks/social-links/style.css 1.48 kB
build/block-library/blocks/spacer/editor-rtl.css 350 B
build/block-library/blocks/spacer/editor.css 350 B
build/block-library/blocks/spacer/style-rtl.css 48 B
build/block-library/blocks/spacer/style.css 48 B
build/block-library/blocks/table/editor-rtl.css 395 B
build/block-library/blocks/table/editor.css 395 B
build/block-library/blocks/table/style-rtl.css 639 B
build/block-library/blocks/table/style.css 639 B
build/block-library/blocks/table/theme-rtl.css 146 B
build/block-library/blocks/table/theme.css 146 B
build/block-library/blocks/tag-cloud/style-rtl.css 251 B
build/block-library/blocks/tag-cloud/style.css 253 B
build/block-library/blocks/template-part/editor-rtl.css 403 B
build/block-library/blocks/template-part/editor.css 403 B
build/block-library/blocks/template-part/theme-rtl.css 101 B
build/block-library/blocks/template-part/theme.css 101 B
build/block-library/blocks/term-description/style-rtl.css 111 B
build/block-library/blocks/term-description/style.css 111 B
build/block-library/blocks/text-columns/editor-rtl.css 95 B
build/block-library/blocks/text-columns/editor.css 95 B
build/block-library/blocks/text-columns/style-rtl.css 166 B
build/block-library/blocks/text-columns/style.css 166 B
build/block-library/blocks/verse/style-rtl.css 99 B
build/block-library/blocks/verse/style.css 99 B
build/block-library/blocks/video/editor-rtl.css 552 B
build/block-library/blocks/video/editor.css 555 B
build/block-library/blocks/video/style-rtl.css 185 B
build/block-library/blocks/video/style.css 185 B
build/block-library/blocks/video/theme-rtl.css 126 B
build/block-library/blocks/video/theme.css 126 B
build/block-library/classic-rtl.css 179 B
build/block-library/classic.css 179 B
build/block-library/common-rtl.css 1.11 kB
build/block-library/common.css 1.11 kB
build/block-library/editor-elements-rtl.css 75 B
build/block-library/editor-elements.css 75 B
build/block-library/editor-rtl.css 12.4 kB
build/block-library/editor.css 12.3 kB
build/block-library/elements-rtl.css 54 B
build/block-library/elements.css 54 B
build/block-library/index.min.js 217 kB
build/block-library/reset-rtl.css 472 B
build/block-library/reset.css 472 B
build/block-library/style-rtl.css 14.8 kB
build/block-library/style.css 14.8 kB
build/block-library/theme-rtl.css 688 B
build/block-library/theme.css 693 B
build/block-serialization-default-parser/index.min.js 1.12 kB
build/block-serialization-spec-parser/index.min.js 2.87 kB
build/blocks/index.min.js 51.8 kB
build/commands/index.min.js 15.6 kB
build/commands/style-rtl.css 935 B
build/commands/style.css 930 B
build/components/index.min.js 223 kB
build/components/style-rtl.css 11.8 kB
build/components/style.css 11.8 kB
build/compose/index.min.js 12.6 kB
build/core-commands/index.min.js 2.77 kB
build/core-data/index.min.js 72.8 kB
build/customize-widgets/index.min.js 12.1 kB
build/customize-widgets/style-rtl.css 1.33 kB
build/customize-widgets/style.css 1.33 kB
build/data-controls/index.min.js 640 B
build/data/index.min.js 8.95 kB
build/date/index.min.js 17.9 kB
build/deprecated/index.min.js 451 B
build/dom-ready/index.min.js 324 B
build/dom/index.min.js 4.65 kB
build/edit-post/classic-rtl.css 558 B
build/edit-post/classic.css 558 B
build/edit-post/index.min.js 23.7 kB
build/edit-post/style-rtl.css 5.65 kB
build/edit-post/style.css 5.64 kB
build/edit-site/index.min.js 216 kB
build/edit-site/style-rtl.css 15.4 kB
build/edit-site/style.css 15.4 kB
build/edit-widgets/index.min.js 17.3 kB
build/edit-widgets/style-rtl.css 4.23 kB
build/edit-widgets/style.css 4.23 kB
build/editor/index.min.js 64 kB
build/editor/style-rtl.css 5.34 kB
build/editor/style.css 5.33 kB
build/element/index.min.js 4.83 kB
build/escape-html/index.min.js 537 B
build/format-library/index.min.js 7.89 kB
build/format-library/style-rtl.css 492 B
build/format-library/style.css 490 B
build/hooks/index.min.js 1.55 kB
build/html-entities/index.min.js 448 B
build/i18n/index.min.js 3.58 kB
build/interactivity/file.min.js 447 B
build/interactivity/image.min.js 1.67 kB
build/interactivity/index.min.js 12.9 kB
build/interactivity/navigation.min.js 1.15 kB
build/interactivity/query.min.js 740 B
build/interactivity/router.min.js 1.36 kB
build/interactivity/search.min.js 618 B
build/is-shallow-equal/index.min.js 527 B
build/keyboard-shortcuts/index.min.js 1.74 kB
build/keycodes/index.min.js 1.46 kB
build/list-reusable-blocks/index.min.js 2.11 kB
build/list-reusable-blocks/style-rtl.css 851 B
build/list-reusable-blocks/style.css 849 B
build/media-utils/index.min.js 2.9 kB
build/modules/importmap-polyfill.min.js 12.2 kB
build/notices/index.min.js 948 B
build/nux/index.min.js 2 kB
build/nux/style-rtl.css 747 B
build/nux/style.css 742 B
build/patterns/index.min.js 5.67 kB
build/patterns/style-rtl.css 553 B
build/patterns/style.css 552 B
build/plugins/index.min.js 1.8 kB
build/preferences-persistence/index.min.js 2.05 kB
build/preferences/index.min.js 2.82 kB
build/preferences/style-rtl.css 710 B
build/preferences/style.css 712 B
build/primitives/index.min.js 975 B
build/priority-queue/index.min.js 1.52 kB
build/private-apis/index.min.js 1 kB
build/react-i18n/index.min.js 623 B
build/react-refresh-entry/index.min.js 9.47 kB
build/react-refresh-runtime/index.min.js 6.78 kB
build/redux-routine/index.min.js 2.7 kB
build/reusable-blocks/index.min.js 2.72 kB
build/reusable-blocks/style-rtl.css 256 B
build/reusable-blocks/style.css 256 B
build/rich-text/index.min.js 10.4 kB
build/router/index.min.js 1.79 kB
build/server-side-render/index.min.js 1.95 kB
build/shortcode/index.min.js 1.39 kB
build/style-engine/index.min.js 2.1 kB
build/token-list/index.min.js 582 B
build/url/index.min.js 3.72 kB
build/vendors/inert-polyfill.min.js 2.48 kB
build/vendors/react-dom.min.js 41.8 kB
build/vendors/react.min.js 4.02 kB
build/viewport/index.min.js 957 B
build/warning/index.min.js 249 B
build/widgets/index.min.js 7.21 kB
build/widgets/style-rtl.css 1.17 kB
build/widgets/style.css 1.17 kB
build/wordcount/index.min.js 1.02 kB

compressed-size-action

Copy link
Contributor

@alexstine alexstine left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍 I am sure the checks will fail though from existing usage.

@scruffian
Copy link
Contributor Author

👍 I am sure the checks will fail though from existing usage.

It will only check changed code. I'd like more detail on why this is a good idea though. Are we sure there is never a case when disabled could be valid?

@alexstine
Copy link
Contributor

@scruffian It could be under some very specific situations and I think one of the ESLint exclude rules could be used in these cases. All in all, I do not think we should be encouraging inaccessible code, there is no way to make the disabled attribute accessible via keyboard. Instead of passing disabled, it would need to look something like this.

<button type="button" className="some-button" aria-disabled="true" onClick={ ( e ) => event.preventDefault() }>Test disabled button</button>

This way, the button is disabled for clicks but it still remains in the tab order for keyboard users. It is quite tricky to see buttons visually but tab key never lands on them.

Happy to hear feedback from @afercia and @joedolson. I think this is still a good step to take.

@joedolson
Copy link
Contributor

I think having linting rules that check for this is a good idea. Creating controls or interface elements that are unfindable is highly problematic. We can be willing to address exceptions, but I think one of the benefits to linting tools is that we have to make a conscious decision to override our tooling, which is a good double check on our intentions, to assess whether this is a legitimate case for disabling something.

I'll also note that any disabled input or control should come with some indication of why it's disabled and what conditions are required to make it enabled; otherwise disabled controls can be very confusing.

@jeryj
Copy link
Contributor

jeryj commented Mar 4, 2024

@WordPress/gutenberg-components - Could the <Button /> component be also changed so that when disabled is passed, it defaults to being aria-disabled?

@alexstine
Copy link
Contributor

@jeryj I think that is a logical next step but preventing this in the first place is good. This allows us to avoid inaccessible defaults in the future dev work.

@andrewhayward
Copy link
Contributor

While I can understand the motivation behind this PR, and agree generally with the comments so far, I'm not sure whether this is the best way to proceed as a first step.

Have we looked properly at where and how disabled is currently being used? How much is in native elements, and how much is in custom components? To @jeryj's point, there may well be components that just won't work as expected with aria-disabled instead of disabled, which would be confusing for consumers, and which we should probably fix first.

Perhaps the lint rule could/should initially only look at native elements?

// ✅ These would be fine (for now, at least):
...( <Button disabled /> );
...( <Checkbox disabled /> );

// ⛔️ These would not be:
...( <button disabled /> );
...( <input type="checkbox" disabled /> );

@alexstine
Copy link
Contributor

@andrewhayward The way I understood it, this rule would only catch new errors, not existing.

@andrewhayward
Copy link
Contributor

The way I understood it, this rule would only catch new errors, not existing.

Sorry @alexstine, I wasn't super clear.

My concern is that if someone makes a change that involves setting disabled on a component that expects it as a prop, a blanket ban will give them rather confusing messaging about not using it. The following diff, for example, would fail the linter, even though it's an appropriate usage.

  <MyComponent
    { ...props }
+   disabled
  />

Equally, I would find it very confusing to have eslint overrides dotted around to bypass 'restricted syntax' errors, where disabled is being used in a known and expected context.

  <MyComponent
    { ...props }
+   {/* eslint-disable-next-line no-restricted-syntax */}
+   disabled
  />

As an aside, it actually looks like the lint rule is catching all current instances of disabled.

@alexstine
Copy link
Contributor

@andrewhayward Understand your concern totally. How do you think we should better educate developers on disabled usage? In the current usage in the project, it is causing lots of issues.

@mirka
Copy link
Member

mirka commented Mar 5, 2024

Related: #56547

This topic (not necessarily this PR specifically) affects many of our components and will potentially result in changes to their default behavior and API design. In this PR thread, it looks like there is an implicit consensus that focusable disabled should not only be the default behavior, but should be enforced 100% of the time. In my research, I could not find evidence that this is a widely held consensus or a de facto standard outside of this project.

Given that focusable disabled is not the default behavior with native form elements in the browser, and the APG says to use your best judgement in each instance, could some of you elaborate on the following:

  • Why should focusable disabled be the default in Gutenberg, and/or @wordpress/components?
  • Should we disallow anyone from opting out from focusable disabled in whatever circumstance? Why?

I don't have a strong opinion either way, but I just want to make sure we have good, documented arguments to justify the decision before making broad changes to our component APIs.

@alexstine
Copy link
Contributor

@mirka Answers.

Why should focusable disabled be the default in Gutenberg, and/or @wordpress/components?

Because, it is really confusing when you can visually see a button and not be able to access it with the keyboard. For blind users like myself, I might want to tab to the save button and hear that it is disabled so I can go try to figure out why vs. just never being able to find it in the first place. The third big reason and one that has hurt all of us a time or two in the project is disabled buttons cannot take focus so this is a really easy way to introduce focus loss especially in React where disabled can be dynamically added/removed.

Should we disallow anyone from opting out from focusable disabled in whatever circumstance? Why?

I feel like there might be some use-cases for this but having a hard time coming up with any at the moment.

Others I am sure will chime in.

Could we instead convert this to a warning? It wouldn't be a failure but something that would make developers ask "am I sure I should use disabled here?"

@mirka
Copy link
Member

mirka commented Mar 5, 2024

To be clear, I'm not questioning the pros of focusable disabled, rather I want to know why in our particular project it clearly outweighs the cons. The cons being:

  • Potentially adding a lot of disabled elements in the tab order, increasing the time it takes to reach a desired element.
  • Going against browser defaults, which can misalign with developer expectations. disabled is a standard HTML attribute, and if we are going to change that prop name to mean aria-disabled in our packages we need to be very intentional about that decision. Not just in terms of focusability behavior expectations, but also because disabled is commonly used as a query/CSS selector.

If most of us here think that yes, the pros overwhelmingly outweigh the cons, that's great. Let's get that discussion written down so we can point to it to justify our decision. Because contrary to what I assumed before I looked it up, there are not a lot of external sources we can point to that says "focusable disabled is always the desirable behavior and we should petition browser vendors to change their defaults", for example.

@alexstine
Copy link
Contributor

@mirka Understood, your concerns are well noted. :) Want to make sure things are done right.

Potentially adding a lot of disabled elements in the tab order, increasing the time it takes to reach a desired element.

My personal opinion about this, if it is available to the sighted, it should be available to all. That kind of goes back to the concerns I raised over the use of inert but that was a much more severe issue.

I also do not think we have to change disabled itself as much as I just want to warn developers that they probably shouldn't use it. For example:

<button type="button" name="save" className="save-btn" disabled>Save Changes</button>

This should return something like:

Warning: The usage of disabled is not recommended due to lack of keyboard accessibility. Did you mean to pass disabled? Alternatively, consider using aria-disabled to ensure the element remains in the tab order.

Does ESLint have such an ability? I am perfectly fine with just trying out the warning as a starting proof of concept.

So, the idea isn't to change how HTML attributes are used or how CSS selectors can target, simply warn developers that this might be a bad idea. Going forward, I think we could help devs out by introducing accessibleDisabled prop in all of our components but that can be a later discussion. Just trying to stop the damage right now.

Also worth noting, I agree. This should be restricted to new code only and Gutenberg development. This should not be published in the ESLint package for people simply creating custom blocks.

Thanks.

Copy link
Contributor

@draganescu draganescu left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's land this and see what it enables everyone to avoid.

@scruffian
Copy link
Contributor Author

I can't find a way to make only this rule a warning

@alexstine
Copy link
Contributor

All, how can we move this forward? We really need to start putting some accessibility safety checks in place because Gutenberg has simply become way too unmanageable to review all new PRs for a single day in the time I have available. The solution, let's try to add some guard rails and hope people follow them.

@mirka I was actually thinking a bit about your comments from earlier and the other thing I'll add, there are a lot of standards out there on the web today. Some good, some okay, some bad. The one common theme, most of the choices that are being made at the W3C level are not by the users that are impacted by such choices. I'm still brainstorming on how to fix that bigger issue but I think as an open-source community, if we divert from standards we can all agree cause more harm than good, let's go for it. It's really ironic that people making standards for screen readers are not majority visually impaired/blind, at a certain point, I just take too much of an issue with that to read every standard as pure truth. It would be like me trying to set standards for users of wheelchairs. While I have some idea about wide doors, ramps, elevators, automatic doors, I don't have that type of disability that will truly allow me to ever fully understand it.

Thanks.

@afercia
Copy link
Contributor

afercia commented May 2, 2024

Going against browser defaults, which can misalign with developer expectations. disabled is a standard HTML attribute

The problem is not the disabled HTML attribute itself. Rather, it's how it is used in this project. I'd argue that, in a way, also dynamically disabling a button 'goes against browser defaults'.

Many developers that decide to dynamically disable a focusable control while it may have keyboard focus aren't educated or trained to understand how much that is impactful. For seven years, contributors that are more aware that this is a huge problem tried to educate other contributors to avoid this pattern. Alas, it appears that education efforts aren't enough. There several cases where focus losses triggered by a disabled attributed added dynamically keep being coded, reviewed, and merged in this project.

At this point, I think the only viable solution is to enforce education via code by adding an ESLint rule.

However, as I mentioned on another pull request, there are legitimate cases where an interactive control needs to be 'truly' disabled.

Perhaps, a viable option could be:

  • Add a rule that triggers an error when it finds the disabled attribute.
  • The error message should clearly explain that developers who want to disable the rule with a comment MUST double check and test to avoid focus losses.
  • Allow developers to disable the rule with an eslint-disable comment but reguire the comment to have a disable reason.
  • The disable reason should clearly state that the disabled attribute has been tested, it doesn't trigger a focus loss, and as such it's a legitimate use.

I'd tend to think something like the above would also have an important educational value:

  • It would reenforce contributors responsibility and awareness.
  • It would educate contributors to follow good accessibility practices.

@mirka
Copy link
Member

mirka commented May 2, 2024

I'm ok with moving forward with a lint rule if need be. Before that though, if this is mostly about focus loss in cases when a button is dynamically disabled, can we also consider the alternative solution, which is to automatically apply focusable disabled when a button becomes disabled while it's the focused element?

I'd prefer trying that first, since it will benefit all consumers of Button and not just projects with the lint rule.

@afercia
Copy link
Contributor

afercia commented May 2, 2024

can we also consider the alternative solution, which is to automatically apply focusable disabled when a button becomes disabled while it's the focused element?

I'm not sure that would cover all the cases of a focus loss triggered by disabling a button (or other interactive, focusable control). For example, a control may not have the current focus but it could be the candidate to receive focus after some action. E.g.

  • Open a modal dialog.
  • Close the modal dialog.
  • Focus is expected to be programmatically moved back to the toggle button that opened the modal.
  • However, the toggle button received a disabled attribute in the meantime so that it's no longer focusable.

If I remember correctly, there have been a couple cases like the one described above. The point is that may be other scenarios besides the 'button becomes disabled while it's the focused element' one.

@scruffian
Copy link
Contributor Author

Happy for someone else to pick this up and merge it if they want to

@alexstine
Copy link
Contributor

@mirka Please see my PR here as a good example of the point made by @afercia .

#59622

Because the disabled attribute was added to the dialog trigger, focus was lost because the dialog closed and focus had nowhere to go before disabled was removed. Might have been able to avoid this had the selectors not been so slow but disabled would have to be removed before the UI disappeared. This is how developers are going to continue running into trouble with single page application technologies. Voiding the callback with aria-disabled is full proof, adding disabled is not.

@mirka
Copy link
Member

mirka commented May 28, 2024

I proposed an alternative #62080 way to approach this lint rule that I think would be a bit more measured to start with, but can still scale out as necessary.

@tyxla
Copy link
Member

tyxla commented May 31, 2024

Thanks, @mirka, I think this one can be closed in favor of #62080.

@mirka mirka closed this May 31, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
[Focus] Accessibility (a11y) Changes that impact accessibility and need corresponding review (e.g. markup changes). [Type] Code Quality Issues or PRs that relate to code quality
Projects
None yet
Development

Successfully merging this pull request may close these issues.

9 participants