From 6a4803296137edc32a3184712b272ddf7830c586 Mon Sep 17 00:00:00 2001 From: Leilei332 Date: Fri, 28 Nov 2025 21:33:29 +0800 Subject: [PATCH 1/7] Add Aria support to edittext widget --- core/modules/editor/engines/simple.js | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/core/modules/editor/engines/simple.js b/core/modules/editor/engines/simple.js index 93f021522..c1425c310 100644 --- a/core/modules/editor/engines/simple.js +++ b/core/modules/editor/engines/simple.js @@ -55,6 +55,15 @@ function SimpleEngine(options) { if(this.widget.isDisabled === "yes") { this.domNode.setAttribute("disabled",true); } + if(this.widget.role) { + this.domNode.setAttribute("role",this.widget.role); + } + if(this.widget["aria-autocomplete"]) { + this.domNode.setAttribute("aria-autocomplete",this.widget["aria-autocomplete"]); + } + if(this.widget["aria-controls"]) { + this.domNode.setAttribute("aria-autocomplete",this.widget["aria-controls"]); + } // Add an input event handler $tw.utils.addEventListeners(this.domNode,[ {name: "focus", handlerObject: this, handlerMethod: "handleFocusEvent"}, From 58ada3dc4556f9aeda90439a684e08aab9652018 Mon Sep 17 00:00:00 2001 From: Leilei332 Date: Fri, 28 Nov 2025 21:41:40 +0800 Subject: [PATCH 2/7] Add aria version of keyboard-driven-input --- core/wiki/macros/keyboard-driven-input.tid | 29 ++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/core/wiki/macros/keyboard-driven-input.tid b/core/wiki/macros/keyboard-driven-input.tid index a514f4c13..0a5867bae 100644 --- a/core/wiki/macros/keyboard-driven-input.tid +++ b/core/wiki/macros/keyboard-driven-input.tid @@ -145,3 +145,32 @@ tags: $:/tags/Macro /> \end keyboard-driven-input + +\procedure keyboard-driven-input-aria(tiddler,storeTitle,field:"text",index:"",tag:"input",type,focus:"",inputAcceptActions,inputAcceptVariantActions,inputCancelActions,placeholder:"",default:"",class,focusPopup,rows,minHeight,tabindex,size,autoHeight,filterMinLength:"0",refreshTitle,selectionStateTitle,cancelPopups:"",configTiddlerFilter,firstSearchFilterField:"first-search-filter",secondSearchFilterField:"second-search-filter",role,ariaAutocomplete,ariaControls) +\whitespace trim +\procedure keyboard-driven-input-actions() +<%if [match[((input-accept))]] %> +<> +<%elseif [match[((input-accept-variant))]] %> +<> +<%elseif [match[((input-up))]] %> +<> +<%elseif [match[((input-down))]] %> +<> +<%elseif [match[((input-cancel))]] %> +<> +<%endif%> +\end keyboard-driven-input-actions + +<$keyboard key="((input-accept)) ((input-accept-variant)) ((input-up)) ((input-down)) ((input-cancel))" actions=<>> + <$edit-text + tiddler=<> field=<> index=<> + inputActions=<> tag=<> class=<> + placeholder=<> default=<> focusPopup=<> + focus=<> type=<> rows=<> minHeight=<> + tabindex=<> size=<> autoHeight=<> + refreshTitle=<> cancelPopups=<> + role=<> aria-autocomplete=<> aria-controls=<> + /> + +\end keyboard-driven-input-aria \ No newline at end of file From 48d7a30470e7b5c58a704b49237b3d99510046d6 Mon Sep 17 00:00:00 2001 From: Leilei332 Date: Fri, 28 Nov 2025 21:42:21 +0800 Subject: [PATCH 3/7] Improve aria support for type dropdown --- core/ui/EditTemplate/type.tid | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/core/ui/EditTemplate/type.tid b/core/ui/EditTemplate/type.tid index eae2ebfee..67056d001 100644 --- a/core/ui/EditTemplate/type.tid +++ b/core/ui/EditTemplate/type.tid @@ -10,22 +10,24 @@ first-search-filter: [all[shadows+tiddlers]prefix[$:/language/Docs/Types/]sort[d <>
<$fieldmangler> -<$transclude $variable="keyboard-driven-input" tiddler=<> storeTitle=<> refreshTitle=<> selectionStateTitle=<> field="type" tag="input" default="" placeholder={{$:/language/EditTemplate/Type/Placeholder}} focusPopup=<> class="tc-edit-typeeditor tc-edit-texteditor tc-popup-handle tc-keep-focus" tabindex={{$:/config/EditTabIndex}} focus={{{ [{$:/config/AutoFocus}match[type]then[true]] :else[[false]] }}} cancelPopups="yes" configTiddlerFilter="[[$:/core/ui/EditTemplate/type]]" inputCancelActions=<>/><$button popup=<> class="tc-btn-invisible tc-btn-dropdown tc-small-gap" tooltip={{$:/language/EditTemplate/Type/Dropdown/Hint}} aria-label={{$:/language/EditTemplate/Type/Dropdown/Caption}}>{{$:/core/images/down-arrow}}<$button message="tm-remove-field" param="type" class="tc-btn-invisible tc-btn-icon" tooltip={{$:/language/EditTemplate/Type/Delete/Hint}} aria-label={{$:/language/EditTemplate/Type/Delete/Caption}}>{{$:/core/images/delete-button}}<$action-deletetiddler $filter="[] [] [] []"/> +<$transclude $variable="keyboard-driven-input-aria" tiddler=<> storeTitle=<> refreshTitle=<> selectionStateTitle=<> field="type" tag="input" default="" placeholder={{$:/language/EditTemplate/Type/Placeholder}} focusPopup=<> class="tc-edit-typeeditor tc-edit-texteditor tc-popup-handle tc-keep-focus" tabindex={{$:/config/EditTabIndex}} focus={{{ [{$:/config/AutoFocus}match[type]then[true]] :else[[false]] }}} cancelPopups="yes" configTiddlerFilter="[[$:/core/ui/EditTemplate/type]]" inputCancelActions=<> role="combobox" aria-autocomplete="list" aria-controls=<>/><$button popup=<> class="tc-btn-invisible tc-btn-dropdown tc-small-gap" tooltip={{$:/language/EditTemplate/Type/Dropdown/Hint}} aria-controls=<> aria-label={{$:/language/EditTemplate/Type/Dropdown/Caption}}>{{$:/core/images/down-arrow}}<$button message="tm-remove-field" param="type" class="tc-btn-invisible tc-btn-icon" tooltip={{$:/language/EditTemplate/Type/Delete/Hint}} aria-label={{$:/language/EditTemplate/Type/Delete/Caption}}>{{$:/core/images/delete-button}}<$action-deletetiddler $filter="[] [] [] []"/>
<$set name="tv-show-missing-links" value="yes"> <$reveal state=<> type="nomatch" text="" default=""> -
+
>> <$linkcatcher to="!!type"> <$list filter='[all[shadows+tiddlers]prefix[$:/language/Docs/Types/]each[group]sort[group-sort]]'> -
+ +
<$set name="userInput" value={{{ [get[text]] }}}> -<$list filter="[all[shadows+tiddlers]prefix[$:/language/Docs/Types/]group{!!group}] :and[sort[description]] :and[removeprefix[$:/language/Docs/Types/]] :and[search]">addsuffix[-primaryList]] :except[get[text]] :and[then[]else[tc-list-item-selected]] }}}><$link to={{{ [addprefix[$:/language/Docs/Types/]get[name]] }}}><$view tiddler={{{ [addprefix[$:/language/Docs/Types/]] }}} field="description"/><$text text=" "/>(<$view tiddler={{{ [addprefix[$:/language/Docs/Types/]] }}} field="name"/>) +<$list filter="[all[shadows+tiddlers]prefix[$:/language/Docs/Types/]group{!!group}] :and[sort[description]] :and[removeprefix[$:/language/Docs/Types/]] :and[search]">addsuffix[-primaryList]] :except[get[text]] :and[then[]else[tc-list-item-selected]] }}}><$link role="option" to={{{ [addprefix[$:/language/Docs/Types/]get[name]] }}}><$view tiddler={{{ [addprefix[$:/language/Docs/Types/]] }}} field="description"/><$text text=" "/>(<$view tiddler={{{ [addprefix[$:/language/Docs/Types/]] }}} field="name"/>) +
From b287502383d12958007fdb36fb4cc62f77f1af89 Mon Sep 17 00:00:00 2001 From: Leilei332 Date: Sat, 29 Nov 2025 08:42:18 +0800 Subject: [PATCH 4/7] Fix attributes not applied --- core/modules/editor/engines/simple.js | 10 ++++------ core/modules/editor/factory.js | 1 + 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/core/modules/editor/engines/simple.js b/core/modules/editor/engines/simple.js index c1425c310..8c2b24fb4 100644 --- a/core/modules/editor/engines/simple.js +++ b/core/modules/editor/engines/simple.js @@ -58,12 +58,10 @@ function SimpleEngine(options) { if(this.widget.role) { this.domNode.setAttribute("role",this.widget.role); } - if(this.widget["aria-autocomplete"]) { - this.domNode.setAttribute("aria-autocomplete",this.widget["aria-autocomplete"]); - } - if(this.widget["aria-controls"]) { - this.domNode.setAttribute("aria-autocomplete",this.widget["aria-controls"]); - } + this.widget.assignAttributes(this.domNode,{ + sourcePrefix: "aria-", + destPrefix: "aria-" + }); // Add an input event handler $tw.utils.addEventListeners(this.domNode,[ {name: "focus", handlerObject: this, handlerMethod: "handleFocusEvent"}, diff --git a/core/modules/editor/factory.js b/core/modules/editor/factory.js index 2fd323c0b..8db2f714b 100644 --- a/core/modules/editor/factory.js +++ b/core/modules/editor/factory.js @@ -184,6 +184,7 @@ function editTextWidgetFactory(toolbarEngine,nonToolbarEngine) { this.editInputActions = this.getAttribute("inputActions"); this.editRefreshTitle = this.getAttribute("refreshTitle"); this.editAutoComplete = this.getAttribute("autocomplete"); + this.role = this.getAttribute("role"); this.isDisabled = this.getAttribute("disabled","no"); this.isFileDropEnabled = this.getAttribute("fileDrop","no") === "yes"; // Get the default editor element tag and type From d1b051a01eff19d5264bd92ba7511f3cfb82e10e Mon Sep 17 00:00:00 2001 From: Leilei332 Date: Sat, 29 Nov 2025 08:42:32 +0800 Subject: [PATCH 5/7] Fix wrong parameter --- core/ui/EditTemplate/type.tid | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/ui/EditTemplate/type.tid b/core/ui/EditTemplate/type.tid index 67056d001..f9caea4af 100644 --- a/core/ui/EditTemplate/type.tid +++ b/core/ui/EditTemplate/type.tid @@ -10,7 +10,7 @@ first-search-filter: [all[shadows+tiddlers]prefix[$:/language/Docs/Types/]sort[d <>
<$fieldmangler> -<$transclude $variable="keyboard-driven-input-aria" tiddler=<> storeTitle=<> refreshTitle=<> selectionStateTitle=<> field="type" tag="input" default="" placeholder={{$:/language/EditTemplate/Type/Placeholder}} focusPopup=<> class="tc-edit-typeeditor tc-edit-texteditor tc-popup-handle tc-keep-focus" tabindex={{$:/config/EditTabIndex}} focus={{{ [{$:/config/AutoFocus}match[type]then[true]] :else[[false]] }}} cancelPopups="yes" configTiddlerFilter="[[$:/core/ui/EditTemplate/type]]" inputCancelActions=<> role="combobox" aria-autocomplete="list" aria-controls=<>/><$button popup=<> class="tc-btn-invisible tc-btn-dropdown tc-small-gap" tooltip={{$:/language/EditTemplate/Type/Dropdown/Hint}} aria-controls=<> aria-label={{$:/language/EditTemplate/Type/Dropdown/Caption}}>{{$:/core/images/down-arrow}}<$button message="tm-remove-field" param="type" class="tc-btn-invisible tc-btn-icon" tooltip={{$:/language/EditTemplate/Type/Delete/Hint}} aria-label={{$:/language/EditTemplate/Type/Delete/Caption}}>{{$:/core/images/delete-button}}<$action-deletetiddler $filter="[] [] [] []"/> +<$transclude $variable="keyboard-driven-input-aria" tiddler=<> storeTitle=<> refreshTitle=<> selectionStateTitle=<> field="type" tag="input" default="" placeholder={{$:/language/EditTemplate/Type/Placeholder}} focusPopup=<> class="tc-edit-typeeditor tc-edit-texteditor tc-popup-handle tc-keep-focus" tabindex={{$:/config/EditTabIndex}} focus={{{ [{$:/config/AutoFocus}match[type]then[true]] :else[[false]] }}} cancelPopups="yes" configTiddlerFilter="[[$:/core/ui/EditTemplate/type]]" inputCancelActions=<> role="combobox" ariaAutocomplete="list" ariaControls=<>/><$button popup=<> class="tc-btn-invisible tc-btn-dropdown tc-small-gap" tooltip={{$:/language/EditTemplate/Type/Dropdown/Hint}} aria-controls=<> aria-label={{$:/language/EditTemplate/Type/Dropdown/Caption}}>{{$:/core/images/down-arrow}}<$button message="tm-remove-field" param="type" class="tc-btn-invisible tc-btn-icon" tooltip={{$:/language/EditTemplate/Type/Delete/Hint}} aria-label={{$:/language/EditTemplate/Type/Delete/Caption}}>{{$:/core/images/delete-button}}<$action-deletetiddler $filter="[] [] [] []"/>
From 1ced25c794fbf4be878a8d9dded20c36a91b9312 Mon Sep 17 00:00:00 2001 From: Leilei332 Date: Sat, 29 Nov 2025 08:47:13 +0800 Subject: [PATCH 6/7] keyboard-driven-macro-aria use combobox role by default --- core/ui/EditTemplate/type.tid | 2 +- core/wiki/macros/keyboard-driven-input.tid | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/core/ui/EditTemplate/type.tid b/core/ui/EditTemplate/type.tid index f9caea4af..3946d23f5 100644 --- a/core/ui/EditTemplate/type.tid +++ b/core/ui/EditTemplate/type.tid @@ -10,7 +10,7 @@ first-search-filter: [all[shadows+tiddlers]prefix[$:/language/Docs/Types/]sort[d <>
<$fieldmangler> -<$transclude $variable="keyboard-driven-input-aria" tiddler=<> storeTitle=<> refreshTitle=<> selectionStateTitle=<> field="type" tag="input" default="" placeholder={{$:/language/EditTemplate/Type/Placeholder}} focusPopup=<> class="tc-edit-typeeditor tc-edit-texteditor tc-popup-handle tc-keep-focus" tabindex={{$:/config/EditTabIndex}} focus={{{ [{$:/config/AutoFocus}match[type]then[true]] :else[[false]] }}} cancelPopups="yes" configTiddlerFilter="[[$:/core/ui/EditTemplate/type]]" inputCancelActions=<> role="combobox" ariaAutocomplete="list" ariaControls=<>/><$button popup=<> class="tc-btn-invisible tc-btn-dropdown tc-small-gap" tooltip={{$:/language/EditTemplate/Type/Dropdown/Hint}} aria-controls=<> aria-label={{$:/language/EditTemplate/Type/Dropdown/Caption}}>{{$:/core/images/down-arrow}}<$button message="tm-remove-field" param="type" class="tc-btn-invisible tc-btn-icon" tooltip={{$:/language/EditTemplate/Type/Delete/Hint}} aria-label={{$:/language/EditTemplate/Type/Delete/Caption}}>{{$:/core/images/delete-button}}<$action-deletetiddler $filter="[] [] [] []"/> +<$transclude $variable="keyboard-driven-input-aria" tiddler=<> storeTitle=<> refreshTitle=<> selectionStateTitle=<> field="type" tag="input" default="" placeholder={{$:/language/EditTemplate/Type/Placeholder}} focusPopup=<> class="tc-edit-typeeditor tc-edit-texteditor tc-popup-handle tc-keep-focus" tabindex={{$:/config/EditTabIndex}} focus={{{ [{$:/config/AutoFocus}match[type]then[true]] :else[[false]] }}} cancelPopups="yes" configTiddlerFilter="[[$:/core/ui/EditTemplate/type]]" inputCancelActions=<> ariaAutocomplete="list" ariaControls=<>/><$button popup=<> class="tc-btn-invisible tc-btn-dropdown tc-small-gap" tooltip={{$:/language/EditTemplate/Type/Dropdown/Hint}} aria-controls=<> aria-label={{$:/language/EditTemplate/Type/Dropdown/Caption}}>{{$:/core/images/down-arrow}}<$button message="tm-remove-field" param="type" class="tc-btn-invisible tc-btn-icon" tooltip={{$:/language/EditTemplate/Type/Delete/Hint}} aria-label={{$:/language/EditTemplate/Type/Delete/Caption}}>{{$:/core/images/delete-button}}<$action-deletetiddler $filter="[] [] [] []"/>
diff --git a/core/wiki/macros/keyboard-driven-input.tid b/core/wiki/macros/keyboard-driven-input.tid index 0a5867bae..9893a60c3 100644 --- a/core/wiki/macros/keyboard-driven-input.tid +++ b/core/wiki/macros/keyboard-driven-input.tid @@ -146,7 +146,7 @@ tags: $:/tags/Macro \end keyboard-driven-input -\procedure keyboard-driven-input-aria(tiddler,storeTitle,field:"text",index:"",tag:"input",type,focus:"",inputAcceptActions,inputAcceptVariantActions,inputCancelActions,placeholder:"",default:"",class,focusPopup,rows,minHeight,tabindex,size,autoHeight,filterMinLength:"0",refreshTitle,selectionStateTitle,cancelPopups:"",configTiddlerFilter,firstSearchFilterField:"first-search-filter",secondSearchFilterField:"second-search-filter",role,ariaAutocomplete,ariaControls) +\procedure keyboard-driven-input-aria(tiddler,storeTitle,field:"text",index:"",tag:"input",type,focus:"",inputAcceptActions,inputAcceptVariantActions,inputCancelActions,placeholder:"",default:"",class,focusPopup,rows,minHeight,tabindex,size,autoHeight,filterMinLength:"0",refreshTitle,selectionStateTitle,cancelPopups:"",configTiddlerFilter,firstSearchFilterField:"first-search-filter",secondSearchFilterField:"second-search-filter",role:"combobox",ariaAutocomplete,ariaControls) \whitespace trim \procedure keyboard-driven-input-actions() <%if [match[((input-accept))]] %> From db666b3f1170373b549e3a1b1e7662f34e62766b Mon Sep 17 00:00:00 2001 From: Leilei332 Date: Sat, 29 Nov 2025 08:49:17 +0800 Subject: [PATCH 7/7] Update change note --- .../releasenotes/5.4.0/leilei332-combobox-a11y.tid | 9 +++++++++ 1 file changed, 9 insertions(+) create mode 100644 editions/tw5.com/tiddlers/releasenotes/5.4.0/leilei332-combobox-a11y.tid diff --git a/editions/tw5.com/tiddlers/releasenotes/5.4.0/leilei332-combobox-a11y.tid b/editions/tw5.com/tiddlers/releasenotes/5.4.0/leilei332-combobox-a11y.tid new file mode 100644 index 000000000..5be44b44e --- /dev/null +++ b/editions/tw5.com/tiddlers/releasenotes/5.4.0/leilei332-combobox-a11y.tid @@ -0,0 +1,9 @@ +title: $:/changenotes/5.4.0/#9468 +description: Improve combobox accessibility +release: 5.4.0 +tags: $:/tags/ChangeNote +change-type: enhancement +change-category: usability +github-links: https://github.com/TiddlyWiki/TiddlyWiki5/pull/9468 +github-contributors: Leilei332 +