Commit e3ed1ca9b79 for woocommerce
commit e3ed1ca9b7986d09c37cdd0bf77275412e4df7d5
Author: Tom Cafferkey <tjcafferkey@gmail.com>
Date: Wed Sep 30 11:55:04 2026 +0100
Fix keyboard support in the add tax modal (#68215)
* Fix tabing through each radio item via keyboard
* Retain selected option between page transitions
* Fix pagination keyboard navigation
* Retain selected tax
* Add changelog entries for tax modal accessibility
* Fix tax settings button in modal
* Guard the disabled Add button in the modal Enter handler.
diff --git a/plugins/woocommerce/changelog/fix-tax-modal-accessibility b/plugins/woocommerce/changelog/fix-tax-modal-accessibility
new file mode 100644
index 00000000000..e268d3ee956
--- /dev/null
+++ b/plugins/woocommerce/changelog/fix-tax-modal-accessibility
@@ -0,0 +1,4 @@
+Significance: patch
+Type: fix
+
+Improve keyboard support in the Add tax modal on the admin order screen, including page navigation and keeping the selected tax visible when moving through results.
diff --git a/plugins/woocommerce/client/legacy/js/admin/backbone-modal.js b/plugins/woocommerce/client/legacy/js/admin/backbone-modal.js
index 8663680cb8d..6c3e5496965 100644
--- a/plugins/woocommerce/client/legacy/js/admin/backbone-modal.js
+++ b/plugins/woocommerce/client/legacy/js/admin/backbone-modal.js
@@ -170,8 +170,11 @@
).length > 0;
if ( ! isFormField && ! inEnhancedSelect ) {
- if ( $( '#btn-ok' ).length ) {
- this.addButton( e );
+ var $okButton = this.$( '#btn-ok' );
+ if ( $okButton.length ) {
+ if ( ! $okButton.prop( 'disabled' ) ) {
+ this.addButton( e );
+ }
} else if ( $( '#btn-next' ).length ) {
this.nextButton( e );
}
diff --git a/plugins/woocommerce/client/legacy/js/admin/meta-boxes-order.js b/plugins/woocommerce/client/legacy/js/admin/meta-boxes-order.js
index efa582ca46f..c730ff4e815 100644
--- a/plugins/woocommerce/client/legacy/js/admin/meta-boxes-order.js
+++ b/plugins/woocommerce/client/legacy/js/admin/meta-boxes-order.js
@@ -1314,6 +1314,14 @@ jQuery( function ( $ ) {
pagination = modal.find( '[data-wc-tax-rate-pagination]' ),
load_tax_rates;
+ modal.data( 'wc-existing-tax-rate-ids', $( '.order-tax-id' ).map( function() {
+ return String( $( this ).val() );
+ } ).get() );
+
+ if ( ! modal.data( 'wc-selected-tax-rate-id' ) ) {
+ modal.data( 'wc-selected-tax-rate-id', modal.data( 'wc-existing-tax-rate-ids' )[ 0 ] || '' );
+ }
+
// The modal template is filterable, so only wire the controls up when the
// elements this code depends on are actually present.
if ( ! form.length || ! search.length || ! results.length || ! pagination.length ) {
@@ -1346,6 +1354,16 @@ jQuery( function ( $ ) {
load_tax_rates( 1 );
} );
+ pagination.on( 'keydown', '.first-page, .prev-page, .next-page, .last-page', function( event ) {
+ if ( 13 !== event.which ) {
+ return;
+ }
+
+ event.preventDefault();
+ event.stopPropagation();
+ $( this ).trigger( 'click' );
+ } );
+
pagination.on( 'click', '.prev-page', function() {
var current_page = parseInt( pagination.data( 'page' ), 10 ) || 1;
load_tax_rates( Math.max( 1, current_page - 1 ) );
@@ -1376,12 +1394,47 @@ jQuery( function ( $ ) {
// Rows are re-rendered on every search, so delegate from the results table.
results.on( 'change', 'input[type="radio"][name="add_order_tax"]', function() {
+ modal.data( 'wc-selected-tax-rate-id', $( this ).val() );
wc_meta_boxes_order_items.backbone.update_tax_rate_add_button( modal );
} );
+ results.on( 'keydown', 'input[type="radio"][name="add_order_tax"]', function( event ) {
+ wc_meta_boxes_order_items.backbone.handle_tax_rate_result_tab_navigation( modal, event );
+ } );
+
+ results.on( 'keydown', '[data-wc-tax-rate-settings]', function( event ) {
+ if ( 13 !== event.which && 32 !== event.which ) {
+ return;
+ }
+
+ event.stopPropagation();
+
+ if ( 32 === event.which ) {
+ event.preventDefault();
+ this.click();
+ }
+ } );
+
load_tax_rates( 1 );
},
+ handle_tax_rate_result_tab_navigation: function( modal, event ) {
+ if ( 9 !== event.which || event.altKey || event.ctrlKey || event.metaKey ) {
+ return;
+ }
+
+ var radios = modal[ 0 ].querySelectorAll( 'input[type="radio"][name="add_order_tax"]' ),
+ current_index = Array.prototype.indexOf.call( radios, event.target ),
+ next_index = current_index + ( event.shiftKey ? -1 : 1 );
+
+ if ( -1 === current_index || next_index < 0 || next_index >= radios.length ) {
+ return;
+ }
+
+ event.preventDefault();
+ radios[ next_index ].focus();
+ },
+
search_tax_rates: function( modal, page, is_search ) {
var table = modal.find( '[data-wc-tax-rate-results]' ),
table_body = table.find( 'tbody' ),
@@ -1396,8 +1449,8 @@ jQuery( function ( $ ) {
modal.data( 'wc-tax-rate-request-id', request_id );
table_body.css( 'height', table_body.height() );
- // Replacing the rows drops any selected rate, so re-evaluate the Add button
- // before the request starts rather than leaving it enabled with no selection.
+ // Replacing the rows drops any visible selection, so re-evaluate the Add button
+ // before the request starts rather than leaving it enabled with no checked input.
table_body.html( wc_meta_boxes_order_items.backbone.tax_rate_status_row( status ) );
wc_meta_boxes_order_items.backbone.update_tax_rate_add_button( modal );
pagination.find( '.button, .current-page' ).prop( 'disabled', true );
@@ -1448,9 +1501,12 @@ jQuery( function ( $ ) {
},
update_tax_rate_add_button: function( modal ) {
+ var checked_rate_id = modal.find( 'input[name="add_order_tax"]:checked' ).val(),
+ existing_tax_rate_ids = modal.data( 'wc-existing-tax-rate-ids' ) || [];
+
modal.find( '#btn-ok' ).prop(
'disabled',
- ! modal.find( 'input[name="add_order_tax"]:checked' ).length
+ ! checked_rate_id || -1 !== $.inArray( String( checked_rate_id ), existing_tax_rate_ids )
);
},
@@ -1480,7 +1536,8 @@ jQuery( function ( $ ) {
$( '<p class="wc-tax-rate-empty-action"></p>' ).append(
$( '<a></a>', {
class: 'woocommerce-BlankState-cta button',
- href: wc_enhanced_select_params.tax_rates_settings_url
+ href: wc_enhanced_select_params.tax_rates_settings_url,
+ 'data-wc-tax-rate-settings': true
} ).text( wc_enhanced_select_params.i18n_tax_settings )
)
)
@@ -1494,13 +1551,13 @@ jQuery( function ( $ ) {
.replace( '%1$s', rate.tax_class || '' )
.replace( '%2$s', rate.rate_code || '' )
.replace( '%3$s', rate.rate_percent || '' ),
- radio = $( '<input />', {
- type: 'radio',
- id: input_id,
- name: 'add_order_tax',
- value: rate.id,
- 'aria-describedby': description_id
- } );
+ radio = $( '<input />', {
+ type: 'radio',
+ id: input_id,
+ name: 'add_order_tax',
+ value: rate.id,
+ 'aria-describedby': description_id
+ } );
return $( '<tr></tr>' ).append(
$( '<td></td>' ).append(
@@ -1517,6 +1574,22 @@ jQuery( function ( $ ) {
);
},
+ restore_selected_tax_rate: function( modal ) {
+ var selected_rate_id = modal.data( 'wc-selected-tax-rate-id' ),
+ selected_input;
+
+ if ( ! selected_rate_id ) {
+ return;
+ }
+
+ selected_input = modal.find( 'input[name="add_order_tax"][value="' + selected_rate_id + '"]' );
+
+ if ( selected_input.length ) {
+ selected_input.prop( 'checked', true );
+ wc_meta_boxes_order_items.backbone.update_tax_rate_add_button( modal );
+ }
+ },
+
update_tax_rate_search_summary: function( modal, search_term ) {
var summary = modal.find( '[data-wc-tax-rate-search-summary]' );
@@ -1578,6 +1651,7 @@ jQuery( function ( $ ) {
$.each( results, function( index, rate ) {
table_body.append( wc_meta_boxes_order_items.backbone.tax_rate_result_row( rate ) );
} );
+ wc_meta_boxes_order_items.backbone.restore_selected_tax_rate( modal );
announcement = meta.displaying_num || '';
}