This is an automated email from the ASF dual-hosted git repository.

rusackas pushed a commit to branch chore/enable-click-events-have-key-events
in repository https://gitbox.apache.org/repos/asf/superset.git

commit 926013ab4121aea0f26954360093fd843c3dda6a
Author: Evan Rusackas <[email protected]>
AuthorDate: Mon Jul 13 12:23:23 2026 -0700

    chore(a11y): enable jsx-a11y/click-events-have-key-events as error
    
    Adds a small, tested `handleKeyboardActivation` helper to @superset-ui/core
    that maps Enter/Space to a click handler, then applies it across the 80
    violations (41 files) so every clickable non-interactive element is operable
    from the keyboard. Turns the rule on as "error".
    
    - New util `handleKeyboardActivation(callback)` returns an onKeyDown handler
      that fires the callback on Enter/Space (with preventDefault). Unit-tested,
      plus an ActionButton test covering the click and keyboard paths.
    - Elements that already had role="button"/tabIndex get a mirrored onKeyDown.
      Bare clickable divs (e.g. AgGrid CustomHeader menu items) also get
      role="button" + tabIndex so the handler is actually reachable.
    - Pure event-boundary wrappers (onClick only stops propagation) get a
      matching onKeyDown that stops propagation, rather than a no-op activation.
    - ModalTrigger's div trigger gains tabIndex so the new handler is focusable.
    
    This completes the keyboard-operability follow-up promised while enabling
    interactive-supports-focus in #42006.
    
    Co-Authored-By: Claude Opus 4.8 <[email protected]>
---
 superset-frontend/oxlint.json                      |  2 +-
 .../components/ActionButton/ActionButton.test.tsx  | 14 +++++-
 .../src/components/ActionButton/index.tsx          |  2 +
 .../src/components/ModalTrigger/index.tsx          |  9 +++-
 .../src/components/PopoverSection/index.tsx        |  2 +
 .../src/utils/handleKeyboardActivation.test.ts     | 52 ++++++++++++++++++++++
 .../src/utils/handleKeyboardActivation.ts          | 43 ++++++++++++++++++
 .../packages/superset-ui-core/src/utils/index.ts   |  1 +
 .../src/AgGridTable/components/CustomHeader.tsx    | 33 ++++++++++++--
 .../src/react-pivottable/TableRenderers.tsx        |  6 ++-
 superset-frontend/spec/helpers/shim.tsx            |  2 +-
 .../TableExploreTree/TreeNodeRenderer.tsx          | 11 +++++
 superset-frontend/src/components/Chart/Chart.tsx   |  8 +++-
 .../src/components/Chart/DrillBy/DrillByModal.tsx  |  2 +
 .../components/Chart/DrillBy/DrillBySubmenu.tsx    |  1 +
 .../DatasourceEditor/DatasourceEditor.tsx          |  2 +
 .../src/components/ErrorMessage/ErrorAlert.tsx     |  9 +++-
 .../src/components/ListView/ListView.tsx           |  9 ++++
 .../components/URLShortLinkButton/index.tsx        |  1 +
 .../components/gridComponents/Tab/Tab.tsx          |  4 ++
 .../FilterBar/FilterConfigurationLink/index.tsx    |  2 +
 .../FiltersConfigModal/FilterTitleContainer.tsx    |  2 +
 .../FiltersConfigModal/ItemTitleContainer.tsx      |  2 +
 .../src/explore/components/ControlHeader.tsx       |  2 +
 .../components/DataTablesPane/DataTablesPane.tsx   | 12 ++++-
 .../explore/components/DatasourcePanel/index.tsx   | 10 ++++-
 .../explore/components/ExploreChartPanel/index.tsx | 11 ++++-
 .../components/ExploreViewContainer/index.tsx      |  3 ++
 .../ColumnConfigControl/ColumnConfigControl.tsx    |  4 ++
 .../DndColumnSelectControl/ColumnSelectPopover.tsx | 10 +++++
 .../DndColumnSelectPopoverTitle.tsx                |  2 +
 .../controls/LayerConfigsControl/LayerTreeItem.tsx |  3 ++
 .../MetricControl/AdhocMetricEditPopover/index.tsx | 11 ++++-
 .../MetricControl/AdhocMetricEditPopoverTitle.tsx  |  2 +
 .../components/controls/VizTypeControl/index.tsx   | 12 ++++-
 .../alerts/components/NotificationMethod.tsx       |  6 +++
 .../src/features/charts/ChartCard.tsx              | 11 ++++-
 .../src/features/dashboards/DashboardCard.tsx      | 13 +++++-
 .../AddDataset/DatasetPanel/DatasetPanel.tsx       |  6 +++
 superset-frontend/src/pages/ChartList/index.tsx    |  4 ++
 .../src/pages/DashboardList/index.tsx              |  4 ++
 superset-frontend/src/pages/DatabaseList/index.tsx | 11 +++++
 superset-frontend/src/pages/DatasetList/index.tsx  | 15 +++++++
 .../src/pages/RowLevelSecurityList/index.tsx       |  4 +-
 superset-frontend/src/pages/Tags/index.tsx         |  8 +++-
 superset-frontend/src/pages/TaskList/index.tsx     |  4 ++
 46 files changed, 366 insertions(+), 21 deletions(-)

diff --git a/superset-frontend/oxlint.json b/superset-frontend/oxlint.json
index 1516d96689c..876a0d9cab8 100644
--- a/superset-frontend/oxlint.json
+++ b/superset-frontend/oxlint.json
@@ -201,7 +201,7 @@
     "jsx-a11y/aria-role": ["error", { "ignoreNonDOM": false }],
     "jsx-a11y/aria-unsupported-elements": "error",
     "jsx-a11y/autocomplete-valid": "error",
-    "jsx-a11y/click-events-have-key-events": "off",
+    "jsx-a11y/click-events-have-key-events": "error",
     "jsx-a11y/control-has-associated-label": "error",
     "jsx-a11y/heading-has-content": "error",
     "jsx-a11y/html-has-lang": "error",
diff --git 
a/superset-frontend/packages/superset-ui-core/src/components/ActionButton/ActionButton.test.tsx
 
b/superset-frontend/packages/superset-ui-core/src/components/ActionButton/ActionButton.test.tsx
index 123d5349505..06c6584d592 100644
--- 
a/superset-frontend/packages/superset-ui-core/src/components/ActionButton/ActionButton.test.tsx
+++ 
b/superset-frontend/packages/superset-ui-core/src/components/ActionButton/ActionButton.test.tsx
@@ -16,7 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-import { render, screen, userEvent } from '@superset-ui/core/spec';
+import { render, screen, userEvent, fireEvent } from '@superset-ui/core/spec';
 import { Icons } from '@superset-ui/core/components/Icons';
 import { ActionButton } from '.';
 
@@ -45,6 +45,18 @@ test('calls onClick when clicked', async () => {
   expect(onClick).toHaveBeenCalledTimes(1);
 });
 
+test('calls onClick when activated with the keyboard', () => {
+  const onClick = jest.fn();
+  render(<ActionButton {...defaultProps} onClick={onClick} />);
+
+  const button = screen.getByRole('button');
+  fireEvent.keyDown(button, { key: 'Enter' });
+  expect(onClick).toHaveBeenCalledTimes(1);
+
+  fireEvent.keyDown(button, { key: ' ' });
+  expect(onClick).toHaveBeenCalledTimes(2);
+});
+
 test('renders with tooltip when tooltip prop is provided', async () => {
   const tooltipText = 'This is a tooltip';
   render(<ActionButton {...defaultProps} tooltip={tooltipText} />);
diff --git 
a/superset-frontend/packages/superset-ui-core/src/components/ActionButton/index.tsx
 
b/superset-frontend/packages/superset-ui-core/src/components/ActionButton/index.tsx
index 336b8ca3d48..3e56efbc265 100644
--- 
a/superset-frontend/packages/superset-ui-core/src/components/ActionButton/index.tsx
+++ 
b/superset-frontend/packages/superset-ui-core/src/components/ActionButton/index.tsx
@@ -17,6 +17,7 @@
  * under the License.
  */
 
+import { handleKeyboardActivation } from '../../utils';
 import type { ReactElement, ReactNode } from 'react';
 import { Tooltip, type TooltipPlacement } from '@superset-ui/core/components';
 import { css, useTheme } from '@apache-superset/core/theme';
@@ -55,6 +56,7 @@ export const ActionButton = ({
       className="action-button"
       data-test={label}
       onClick={onClick}
+      onKeyDown={onClick ? handleKeyboardActivation(onClick) : undefined}
     >
       {icon}
     </span>
diff --git 
a/superset-frontend/packages/superset-ui-core/src/components/ModalTrigger/index.tsx
 
b/superset-frontend/packages/superset-ui-core/src/components/ModalTrigger/index.tsx
index 4f477437027..e3762d1e5ad 100644
--- 
a/superset-frontend/packages/superset-ui-core/src/components/ModalTrigger/index.tsx
+++ 
b/superset-frontend/packages/superset-ui-core/src/components/ModalTrigger/index.tsx
@@ -16,6 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+import { handleKeyboardActivation } from '../../utils';
 import {
   forwardRef,
   ForwardedRef,
@@ -126,7 +127,13 @@ export const ModalTrigger = forwardRef(
           </Button>
         )}
         {!isButton && (
-          <div data-test="span-modal-trigger" onClick={open} role="button">
+          <div
+            data-test="span-modal-trigger"
+            onClick={open}
+            onKeyDown={handleKeyboardActivation(open)}
+            role="button"
+            tabIndex={0}
+          >
             {triggerNode}
           </div>
         )}
diff --git 
a/superset-frontend/packages/superset-ui-core/src/components/PopoverSection/index.tsx
 
b/superset-frontend/packages/superset-ui-core/src/components/PopoverSection/index.tsx
index 39009eba76a..902f7378b67 100644
--- 
a/superset-frontend/packages/superset-ui-core/src/components/PopoverSection/index.tsx
+++ 
b/superset-frontend/packages/superset-ui-core/src/components/PopoverSection/index.tsx
@@ -16,6 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+import { handleKeyboardActivation } from '../../utils';
 import { MouseEventHandler, ReactNode } from 'react';
 import { css, useTheme } from '@apache-superset/core/theme';
 import { Icons } from '@superset-ui/core/components/Icons';
@@ -48,6 +49,7 @@ export default function PopoverSection({
         role="button"
         tabIndex={0}
         onClick={onSelect}
+        onKeyDown={onSelect ? handleKeyboardActivation(onSelect) : undefined}
         css={css`
           display: flex;
           align-items: center;
diff --git 
a/superset-frontend/packages/superset-ui-core/src/utils/handleKeyboardActivation.test.ts
 
b/superset-frontend/packages/superset-ui-core/src/utils/handleKeyboardActivation.test.ts
new file mode 100644
index 00000000000..9fb42d4b252
--- /dev/null
+++ 
b/superset-frontend/packages/superset-ui-core/src/utils/handleKeyboardActivation.test.ts
@@ -0,0 +1,52 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+import { KeyboardEvent } from 'react';
+import { handleKeyboardActivation } from './handleKeyboardActivation';
+
+const makeEvent = (key: string) => {
+  const preventDefault = jest.fn();
+  return {
+    event: { key, preventDefault } as unknown as KeyboardEvent,
+    preventDefault,
+  };
+};
+
+test('invokes the callback and prevents default on Enter', () => {
+  const callback = jest.fn();
+  const { event, preventDefault } = makeEvent('Enter');
+  handleKeyboardActivation(callback)(event);
+  expect(callback).toHaveBeenCalledWith(event);
+  expect(preventDefault).toHaveBeenCalled();
+});
+
+test('invokes the callback and prevents default on Space', () => {
+  const callback = jest.fn();
+  const { event, preventDefault } = makeEvent(' ');
+  handleKeyboardActivation(callback)(event);
+  expect(callback).toHaveBeenCalledWith(event);
+  expect(preventDefault).toHaveBeenCalled();
+});
+
+test('ignores other keys', () => {
+  const callback = jest.fn();
+  const { event, preventDefault } = makeEvent('a');
+  handleKeyboardActivation(callback)(event);
+  expect(callback).not.toHaveBeenCalled();
+  expect(preventDefault).not.toHaveBeenCalled();
+});
diff --git 
a/superset-frontend/packages/superset-ui-core/src/utils/handleKeyboardActivation.ts
 
b/superset-frontend/packages/superset-ui-core/src/utils/handleKeyboardActivation.ts
new file mode 100644
index 00000000000..b5470bfeecb
--- /dev/null
+++ 
b/superset-frontend/packages/superset-ui-core/src/utils/handleKeyboardActivation.ts
@@ -0,0 +1,43 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+import { KeyboardEvent } from 'react';
+
+/**
+ * Builds an `onKeyDown` handler that invokes `callback` when the user presses
+ * Enter or Space, mirroring a click for keyboard users. Pair it with an
+ * element's `onClick` so `role="button"` (or similar) controls are operable
+ * from the keyboard, satisfying `jsx-a11y/click-events-have-key-events`.
+ *
+ *   <div role="button" onClick={handleClick}
+ *        onKeyDown={handleKeyboardActivation(handleClick)} />
+ */
+export function handleKeyboardActivation(
+  callback: (event: KeyboardEvent) => void,
+) {
+  return (event: KeyboardEvent) => {
+    if (event.key === 'Enter' || event.key === ' ') {
+      // Prevent the page from scrolling on Space and stop any duplicate
+      // default activation on Enter.
+      event.preventDefault();
+      callback(event);
+    }
+  };
+}
+
+export default handleKeyboardActivation;
diff --git a/superset-frontend/packages/superset-ui-core/src/utils/index.ts 
b/superset-frontend/packages/superset-ui-core/src/utils/index.ts
index f947bdfd57e..797c7ab561f 100644
--- a/superset-frontend/packages/superset-ui-core/src/utils/index.ts
+++ b/superset-frontend/packages/superset-ui-core/src/utils/index.ts
@@ -27,6 +27,7 @@ export { default as makeSingleton } from './makeSingleton';
 export { default as promiseTimeout } from './promiseTimeout';
 export { default as removeDuplicates } from './removeDuplicates';
 export { default as withLabel } from './withLabel';
+export { handleKeyboardActivation } from './handleKeyboardActivation';
 export { lruCache } from './lruCache';
 export { getSelectedText } from './getSelectedText';
 export * from './featureFlags';
diff --git 
a/superset-frontend/plugins/plugin-chart-ag-grid-table/src/AgGridTable/components/CustomHeader.tsx
 
b/superset-frontend/plugins/plugin-chart-ag-grid-table/src/AgGridTable/components/CustomHeader.tsx
index cb6e58e5491..024129ddb1d 100644
--- 
a/superset-frontend/plugins/plugin-chart-ag-grid-table/src/AgGridTable/components/CustomHeader.tsx
+++ 
b/superset-frontend/plugins/plugin-chart-ag-grid-table/src/AgGridTable/components/CustomHeader.tsx
@@ -19,6 +19,7 @@
  * under the License.
  */
 
+import { handleKeyboardActivation } from '@superset-ui/core';
 import { useRef, useState, useEffect } from 'react';
 import { t } from '@apache-superset/core/translation';
 import { ArrowDownOutlined, ArrowUpOutlined } from '@ant-design/icons';
@@ -201,17 +202,35 @@ const CustomHeader: React.FC<CustomHeaderParams> = ({
   const menuContent = (
     <MenuContainer>
       {shouldShowAsc && (
-        <div onClick={() => applySort('asc')} className="menu-item">
+        <div
+          role="button"
+          tabIndex={0}
+          onClick={() => applySort('asc')}
+          onKeyDown={handleKeyboardActivation(() => applySort('asc'))}
+          className="menu-item"
+        >
           <ArrowUpOutlined /> {t('Sort Ascending')}
         </div>
       )}
       {shouldShowDesc && (
-        <div onClick={() => applySort('desc')} className="menu-item">
+        <div
+          role="button"
+          tabIndex={0}
+          onClick={() => applySort('desc')}
+          onKeyDown={handleKeyboardActivation(() => applySort('desc'))}
+          className="menu-item"
+        >
           <ArrowDownOutlined /> {t('Sort Descending')}
         </div>
       )}
       {currentSort && currentSort?.colId === colId && (
-        <div onClick={clearSort} className="menu-item">
+        <div
+          role="button"
+          tabIndex={0}
+          onClick={clearSort}
+          onKeyDown={handleKeyboardActivation(clearSort)}
+          className="menu-item"
+        >
           <span style={{ fontSize: 16 }}>↻</span> {t('Clear Sort')}
         </div>
       )}
@@ -247,7 +266,13 @@ const CustomHeader: React.FC<CustomHeaderParams> = ({
           isOpen={isMenuVisible}
           onClose={() => setMenuVisible(false)}
         >
-          <div className="three-dots-menu" onClick={handleMenuClick}>
+          <div
+            role="button"
+            tabIndex={0}
+            className="three-dots-menu"
+            onClick={handleMenuClick}
+            onKeyDown={handleKeyboardActivation(handleMenuClick)}
+          >
             <KebabMenu />
           </div>
         </CustomPopover>
diff --git 
a/superset-frontend/plugins/plugin-chart-pivot-table/src/react-pivottable/TableRenderers.tsx
 
b/superset-frontend/plugins/plugin-chart-pivot-table/src/react-pivottable/TableRenderers.tsx
index d3e58763827..ccef0bc509a 100644
--- 
a/superset-frontend/plugins/plugin-chart-pivot-table/src/react-pivottable/TableRenderers.tsx
+++ 
b/superset-frontend/plugins/plugin-chart-pivot-table/src/react-pivottable/TableRenderers.tsx
@@ -26,7 +26,7 @@ import {
   useMemo,
   useEffect,
 } from 'react';
-import { safeHtmlSpan } from '@superset-ui/core';
+import { safeHtmlSpan, handleKeyboardActivation } from '@superset-ui/core';
 import { t } from '@apache-superset/core/translation';
 import { supersetTheme } from '@apache-superset/core/theme';
 import PropTypes from 'prop-types';
@@ -172,6 +172,9 @@ function displayHeaderCell(
         tabIndex={0}
         className="toggle"
         onClick={onArrowClick || undefined}
+        onKeyDown={
+          onArrowClick ? handleKeyboardActivation(onArrowClick) : undefined
+        }
       >
         {ArrowIcon}
       </span>
@@ -1046,6 +1049,7 @@ export function TableRenderer(props: TableRendererProps) {
                 onClick={e => {
                   e.stopPropagation();
                 }}
+                onKeyDown={e => e.stopPropagation()}
                 aria-label={
                   activeSortColumn === i
                     ? `Sorted by ${columnName} ${sortingOrder[i] === 'asc' ? 
'ascending' : 'descending'}`
diff --git a/superset-frontend/spec/helpers/shim.tsx 
b/superset-frontend/spec/helpers/shim.tsx
index 0bff723e4ca..b1c243357b9 100644
--- a/superset-frontend/spec/helpers/shim.tsx
+++ b/superset-frontend/spec/helpers/shim.tsx
@@ -119,7 +119,7 @@ jest.mock('@superset-ui/core/components/Icons/AsyncIcon', 
() => ({
       const label =
         ariaLabel || fileName?.replace(/_/g, '-').toLowerCase() || '';
       return (
-        // eslint-disable-next-line jsx-a11y/no-static-element-interactions
+        // eslint-disable-next-line jsx-a11y/no-static-element-interactions, 
jsx-a11y/click-events-have-key-events
         <span
           ref={ref}
           role={role || (onClick ? 'button' : 'img')}
diff --git 
a/superset-frontend/src/SqlLab/components/TableExploreTree/TreeNodeRenderer.tsx 
b/superset-frontend/src/SqlLab/components/TableExploreTree/TreeNodeRenderer.tsx
index dc3e83eaefe..af423f12b5f 100644
--- 
a/superset-frontend/src/SqlLab/components/TableExploreTree/TreeNodeRenderer.tsx
+++ 
b/superset-frontend/src/SqlLab/components/TableExploreTree/TreeNodeRenderer.tsx
@@ -16,6 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+import { handleKeyboardActivation } from '@superset-ui/core';
 import { css, styled, useTheme } from '@apache-superset/core/theme';
 import { t } from '@apache-superset/core/translation';
 import type { NodeRendererProps } from 'react-arborist';
@@ -186,6 +187,7 @@ const TreeNodeRenderer: React.FC<TreeNodeRendererProps> = ({
             <span
               className="col-copy-action"
               onClick={e => e.stopPropagation()}
+              onKeyDown={e => e.stopPropagation()}
             >
               <ActionButton
                 label={`copy-col-${data.name}`}
@@ -215,6 +217,13 @@ const TreeNodeRenderer: React.FC<TreeNodeRendererProps> = 
({
           node.toggle();
         }
       }}
+      onKeyDown={handleKeyboardActivation(() => {
+        if (node.isLeaf) {
+          node.select();
+        } else {
+          node.toggle();
+        }
+      })}
     >
       <span
         className="tree-node-icon"
@@ -239,6 +248,7 @@ const TreeNodeRenderer: React.FC<TreeNodeRendererProps> = ({
         <div
           className="side-action-container"
           onClick={e => e.stopPropagation()}
+          onKeyDown={e => e.stopPropagation()}
         >
           {pinnedSchemas.has(schema) && (
             <div className="action-static">
@@ -306,6 +316,7 @@ const TreeNodeRenderer: React.FC<TreeNodeRendererProps> = ({
             <div
               className="side-action-container"
               onClick={e => e.stopPropagation()}
+              onKeyDown={e => e.stopPropagation()}
             >
               {isPinned && (
                 <div className="action-static">
diff --git a/superset-frontend/src/components/Chart/Chart.tsx 
b/superset-frontend/src/components/Chart/Chart.tsx
index 1519837c747..4cc5b08502b 100644
--- a/superset-frontend/src/components/Chart/Chart.tsx
+++ b/superset-frontend/src/components/Chart/Chart.tsx
@@ -30,6 +30,7 @@ import {
   type FilterState,
   type JsonObject,
   type AgGridChartState,
+  handleKeyboardActivation,
 } from '@superset-ui/core';
 import { styled } from '@apache-superset/core/theme';
 import type { ChartState, Datasource, ChartStatus } from 'src/explore/types';
@@ -465,7 +466,12 @@ function Chart({
             {t(
               'Click on "Create chart" button in the control panel on the left 
to preview a visualization or',
             )}{' '}
-            <span role="button" tabIndex={0} onClick={onQuery}>
+            <span
+              role="button"
+              tabIndex={0}
+              onClick={onQuery}
+              onKeyDown={handleKeyboardActivation(onQuery)}
+            >
               {t('click here')}
             </span>
             .
diff --git a/superset-frontend/src/components/Chart/DrillBy/DrillByModal.tsx 
b/superset-frontend/src/components/Chart/DrillBy/DrillByModal.tsx
index 57149ee55e0..2e5cc764237 100644
--- a/superset-frontend/src/components/Chart/DrillBy/DrillByModal.tsx
+++ b/superset-frontend/src/components/Chart/DrillBy/DrillByModal.tsx
@@ -28,6 +28,7 @@ import {
   isDefined,
   ContextMenuFilters,
   AdhocFilter,
+  handleKeyboardActivation,
 } from '@superset-ui/core';
 import { Alert } from '@apache-superset/core/components';
 import { css, useTheme } from '@apache-superset/core/theme';
@@ -565,6 +566,7 @@ export default function DrillByModal({
                 role="button"
                 tabIndex={0}
                 onClick={route.onClick}
+                onKeyDown={handleKeyboardActivation(route.onClick)}
                 css={css`
                   cursor: pointer;
                 `}
diff --git a/superset-frontend/src/components/Chart/DrillBy/DrillBySubmenu.tsx 
b/superset-frontend/src/components/Chart/DrillBy/DrillBySubmenu.tsx
index d8053a8d600..d331cf528e0 100644
--- a/superset-frontend/src/components/Chart/DrillBy/DrillBySubmenu.tsx
+++ b/superset-frontend/src/components/Chart/DrillBy/DrillBySubmenu.tsx
@@ -217,6 +217,7 @@ export const DrillBySubmenu = ({
       role="menu"
       tabIndex={0}
       data-test="drill-by-submenu"
+      onKeyDown={e => e.stopPropagation()}
       css={css`
         width: 220px;
         max-width: 220px;
diff --git 
a/superset-frontend/src/components/Datasource/components/DatasourceEditor/DatasourceEditor.tsx
 
b/superset-frontend/src/components/Datasource/components/DatasourceEditor/DatasourceEditor.tsx
index d5a9034a023..ddb0f6d45dd 100644
--- 
a/superset-frontend/src/components/Datasource/components/DatasourceEditor/DatasourceEditor.tsx
+++ 
b/superset-frontend/src/components/Datasource/components/DatasourceEditor/DatasourceEditor.tsx
@@ -36,6 +36,7 @@ import {
   SupersetClient,
   getClientErrorObject,
   getExtensionsRegistry,
+  handleKeyboardActivation,
 } from '@superset-ui/core';
 import { GenericDataType } from '@apache-superset/core/common';
 import { t } from '@apache-superset/core/translation';
@@ -1760,6 +1761,7 @@ function DatasourceEditor({
             role="button"
             tabIndex={0}
             onClick={onChangeEditMode}
+            onKeyDown={handleKeyboardActivation(onChangeEditMode)}
           >
             {isEditMode ? (
               <Icons.UnlockOutlined
diff --git a/superset-frontend/src/components/ErrorMessage/ErrorAlert.tsx 
b/superset-frontend/src/components/ErrorMessage/ErrorAlert.tsx
index 4eae54c6ad2..2965137df1d 100644
--- a/superset-frontend/src/components/ErrorMessage/ErrorAlert.tsx
+++ b/superset-frontend/src/components/ErrorMessage/ErrorAlert.tsx
@@ -16,6 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+import { handleKeyboardActivation } from '@superset-ui/core';
 import { useState } from 'react';
 import { t } from '@apache-superset/core/translation';
 import { Alert } from '@apache-superset/core/components';
@@ -103,6 +104,7 @@ export const ErrorAlert: React.FC<ErrorAlertProps> = ({
             role="button"
             tabIndex={0}
             onClick={toggleDescription}
+            onKeyDown={handleKeyboardActivation(toggleDescription)}
             style={{ textDecoration: 'underline', cursor: 'pointer' }}
           >
             {isDescriptionVisible ? t('See less') : t('See more')}
@@ -127,7 +129,12 @@ export const ErrorAlert: React.FC<ErrorAlertProps> = ({
     return (
       <>
         <Tooltip title={`${errorType}: ${message}`}>
-          <span role="button" onClick={() => setShowModal(true)} tabIndex={0}>
+          <span
+            role="button"
+            onClick={() => setShowModal(true)}
+            onKeyDown={handleKeyboardActivation(() => setShowModal(true))}
+            tabIndex={0}
+          >
             {renderTrigger()}
           </span>
         </Tooltip>
diff --git a/superset-frontend/src/components/ListView/ListView.tsx 
b/superset-frontend/src/components/ListView/ListView.tsx
index a88b2ebb736..f8129b50009 100644
--- a/superset-frontend/src/components/ListView/ListView.tsx
+++ b/superset-frontend/src/components/ListView/ListView.tsx
@@ -16,6 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+import { handleKeyboardActivation } from '@superset-ui/core';
 import { t } from '@apache-superset/core/translation';
 import { Alert } from '@apache-superset/core/components';
 import { styled } from '@apache-superset/core/theme';
@@ -255,6 +256,7 @@ const ViewModeToggle = ({
           e.currentTarget.blur();
           setMode('card');
         }}
+        onKeyDown={handleKeyboardActivation(() => setMode('card'))}
         className={cx('toggle-button', { active: mode === 'card' })}
       >
         <Icons.AppstoreOutlined iconSize="xl" />
@@ -269,6 +271,7 @@ const ViewModeToggle = ({
           e.currentTarget.blur();
           setMode('table');
         }}
+        onKeyDown={handleKeyboardActivation(() => setMode('table'))}
         className={cx('toggle-button', { active: mode === 'table' })}
       >
         <Icons.UnorderedListOutlined iconSize="xl" />
@@ -509,6 +512,9 @@ export function ListView<T extends object = any>({
                         tabIndex={0}
                         className="deselect-all"
                         onClick={() => toggleAllRowsSelected(false)}
+                        onKeyDown={handleKeyboardActivation(() =>
+                          toggleAllRowsSelected(false),
+                        )}
                       >
                         {t('Deselect all')}
                       </span>
@@ -544,6 +550,9 @@ export function ListView<T extends object = any>({
                           tabIndex={0}
                           className="tag-btn"
                           onClick={() => setShowBulkTagModal(true)}
+                          onKeyDown={handleKeyboardActivation(() =>
+                            setShowBulkTagModal(true),
+                          )}
                         >
                           {t('Add Tag')}
                         </span>
diff --git 
a/superset-frontend/src/dashboard/components/URLShortLinkButton/index.tsx 
b/superset-frontend/src/dashboard/components/URLShortLinkButton/index.tsx
index 136c44425b9..6574bb69386 100644
--- a/superset-frontend/src/dashboard/components/URLShortLinkButton/index.tsx
+++ b/superset-frontend/src/dashboard/components/URLShortLinkButton/index.tsx
@@ -106,6 +106,7 @@ export default function URLShortLinkButton({
           onClick={e => {
             e.stopPropagation();
           }}
+          onKeyDown={e => e.stopPropagation()}
         >
           <CopyToClipboard
             text={shortUrl}
diff --git 
a/superset-frontend/src/dashboard/components/gridComponents/Tab/Tab.tsx 
b/superset-frontend/src/dashboard/components/gridComponents/Tab/Tab.tsx
index 9bdbf9221c2..6f6621c7282 100644
--- a/superset-frontend/src/dashboard/components/gridComponents/Tab/Tab.tsx
+++ b/superset-frontend/src/dashboard/components/gridComponents/Tab/Tab.tsx
@@ -16,6 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+import { handleKeyboardActivation } from '@superset-ui/core';
 import {
   Fragment,
   useCallback,
@@ -351,6 +352,9 @@ const Tab = (props: TabProps): ReactElement => {
                           role="button"
                           tabIndex={0}
                           onClick={() => dispatch(setEditMode(true))}
+                          onKeyDown={handleKeyboardActivation(() =>
+                            dispatch(setEditMode(true)),
+                          )}
                         >
                           {t('edit mode')}
                         </span>
diff --git 
a/superset-frontend/src/dashboard/components/nativeFilters/FilterBar/FilterConfigurationLink/index.tsx
 
b/superset-frontend/src/dashboard/components/nativeFilters/FilterBar/FilterConfigurationLink/index.tsx
index 367072fbab9..76573405681 100644
--- 
a/superset-frontend/src/dashboard/components/nativeFilters/FilterBar/FilterConfigurationLink/index.tsx
+++ 
b/superset-frontend/src/dashboard/components/nativeFilters/FilterBar/FilterConfigurationLink/index.tsx
@@ -16,6 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+import { handleKeyboardActivation } from '@superset-ui/core';
 import { ReactNode, FC, memo } from 'react';
 
 import { getFilterBarTestId } from '../utils';
@@ -32,6 +33,7 @@ export const FilterConfigurationLink: FC<FCBProps> = ({
   <div
     {...getFilterBarTestId('create-filter')}
     onClick={onClick}
+    onKeyDown={handleKeyboardActivation(onClick)}
     role="button"
     tabIndex={0}
   >
diff --git 
a/superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FilterTitleContainer.tsx
 
b/superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FilterTitleContainer.tsx
index e5420ad1b63..c3026f18efe 100644
--- 
a/superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FilterTitleContainer.tsx
+++ 
b/superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/FilterTitleContainer.tsx
@@ -16,6 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+import { handleKeyboardActivation } from '@superset-ui/core';
 import { forwardRef, useCallback, useState } from 'react';
 
 import { t } from '@apache-superset/core/translation';
@@ -199,6 +200,7 @@ const FilterTitleContainer = forwardRef<HTMLDivElement, 
Props>(
                   e.preventDefault();
                   restoreFilter(id);
                 }}
+                onKeyDown={handleKeyboardActivation(() => restoreFilter(id))}
               >
                 {t('Undo?')}
               </span>
diff --git 
a/superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/ItemTitleContainer.tsx
 
b/superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/ItemTitleContainer.tsx
index 388421b5ac1..7904835fc4c 100644
--- 
a/superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/ItemTitleContainer.tsx
+++ 
b/superset-frontend/src/dashboard/components/nativeFilters/FiltersConfigModal/ItemTitleContainer.tsx
@@ -16,6 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+import { handleKeyboardActivation } from '@superset-ui/core';
 import { forwardRef, useState } from 'react';
 
 import { t } from '@apache-superset/core/translation';
@@ -167,6 +168,7 @@ const ItemTitleContainer = forwardRef<HTMLDivElement, 
Props>(
                   e.preventDefault();
                   restoreItem(id);
                 }}
+                onKeyDown={handleKeyboardActivation(() => restoreItem(id))}
               >
                 {t('Undo?')}
               </span>
diff --git a/superset-frontend/src/explore/components/ControlHeader.tsx 
b/superset-frontend/src/explore/components/ControlHeader.tsx
index a2bbf047c31..fd62cbaf739 100644
--- a/superset-frontend/src/explore/components/ControlHeader.tsx
+++ b/superset-frontend/src/explore/components/ControlHeader.tsx
@@ -16,6 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+import { handleKeyboardActivation } from '@superset-ui/core';
 import { FC, ReactNode } from 'react';
 import { t } from '@apache-superset/core/translation';
 import { css, useTheme, SupersetTheme } from '@apache-superset/core/theme';
@@ -139,6 +140,7 @@ const ControlHeader: FC<ControlHeaderProps> = ({
             role="button"
             tabIndex={0}
             onClick={onClick}
+            onKeyDown={onClick ? handleKeyboardActivation(onClick) : undefined}
             style={{ cursor: onClick ? 'pointer' : '' }}
           >
             {label}
diff --git 
a/superset-frontend/src/explore/components/DataTablesPane/DataTablesPane.tsx 
b/superset-frontend/src/explore/components/DataTablesPane/DataTablesPane.tsx
index 55994e58d82..6c40bba70d9 100644
--- a/superset-frontend/src/explore/components/DataTablesPane/DataTablesPane.tsx
+++ b/superset-frontend/src/explore/components/DataTablesPane/DataTablesPane.tsx
@@ -18,7 +18,11 @@
  */
 import { useCallback, useEffect, useMemo, useState, MouseEvent } from 'react';
 import { t } from '@apache-superset/core/translation';
-import { isFeatureEnabled, FeatureFlag } from '@superset-ui/core';
+import {
+  isFeatureEnabled,
+  FeatureFlag,
+  handleKeyboardActivation,
+} from '@superset-ui/core';
 import { styled } from '@apache-superset/core/theme';
 import { Icons } from '@superset-ui/core/components/Icons';
 import Tabs from '@superset-ui/core/components/Tabs';
@@ -187,6 +191,9 @@ export const DataTablesPane = ({
             role="button"
             tabIndex={0}
             onClick={() => handleCollapseChange(false)}
+            onKeyDown={handleKeyboardActivation(() =>
+              handleCollapseChange(false),
+            )}
           >
             {caretIcon}
           </span>
@@ -195,6 +202,9 @@ export const DataTablesPane = ({
             role="button"
             tabIndex={0}
             onClick={() => handleCollapseChange(true)}
+            onKeyDown={handleKeyboardActivation(() =>
+              handleCollapseChange(true),
+            )}
           >
             {caretIcon}
           </span>
diff --git a/superset-frontend/src/explore/components/DatasourcePanel/index.tsx 
b/superset-frontend/src/explore/components/DatasourcePanel/index.tsx
index 7e9d5244130..c72efc8c5fd 100644
--- a/superset-frontend/src/explore/components/DatasourcePanel/index.tsx
+++ b/superset-frontend/src/explore/components/DatasourcePanel/index.tsx
@@ -18,7 +18,12 @@
  */
 import { useContext, useDeferredValue, useMemo, useState } from 'react';
 import { t } from '@apache-superset/core/translation';
-import { DatasourceType, Metric, QueryFormData } from '@superset-ui/core';
+import {
+  DatasourceType,
+  Metric,
+  QueryFormData,
+  handleKeyboardActivation,
+} from '@superset-ui/core';
 import { Alert } from '@apache-superset/core/components';
 import { css, styled, useTheme } from '@apache-superset/core/theme';
 
@@ -290,6 +295,9 @@ export default function DataSourcePanel({
                       role="button"
                       tabIndex={0}
                       onClick={() => setShowSaveDatasetModal(true)}
+                      onKeyDown={handleKeyboardActivation(() =>
+                        setShowSaveDatasetModal(true),
+                      )}
                       className="add-dataset-alert-description"
                     >
                       {t('Create a dataset')}
diff --git 
a/superset-frontend/src/explore/components/ExploreChartPanel/index.tsx 
b/superset-frontend/src/explore/components/ExploreChartPanel/index.tsx
index 3145bda73a2..e90f9e708ea 100644
--- a/superset-frontend/src/explore/components/ExploreChartPanel/index.tsx
+++ b/superset-frontend/src/explore/components/ExploreChartPanel/index.tsx
@@ -30,6 +30,7 @@ import {
   QueryFormData,
   JsonObject,
   getExtensionsRegistry,
+  handleKeyboardActivation,
 } from '@superset-ui/core';
 import { Alert } from '@apache-superset/core/components';
 import { css, styled, useTheme } from '@apache-superset/core/theme';
@@ -396,6 +397,9 @@ const ExploreChartPanel = ({
                   role="button"
                   tabIndex={0}
                   onClick={() => setShowDatasetModal(true)}
+                  onKeyDown={handleKeyboardActivation(() =>
+                    setShowDatasetModal(true),
+                  )}
                   css={{ textDecoration: 'underline' }}
                 >
                   {t('Create a dataset')}
@@ -420,7 +424,12 @@ const ExploreChartPanel = ({
                   {t(
                     'You updated the values in the control panel, but the 
chart was not updated automatically. Run the query by clicking on the "Update 
chart" button or',
                   )}{' '}
-                  <span role="button" tabIndex={0} onClick={onQuery}>
+                  <span
+                    role="button"
+                    tabIndex={0}
+                    onClick={onQuery}
+                    onKeyDown={handleKeyboardActivation(onQuery)}
+                  >
                     {t('click here')}
                   </span>
                   .
diff --git 
a/superset-frontend/src/explore/components/ExploreViewContainer/index.tsx 
b/superset-frontend/src/explore/components/ExploreViewContainer/index.tsx
index aebaa64da17..b0ca4ac0868 100644
--- a/superset-frontend/src/explore/components/ExploreViewContainer/index.tsx
+++ b/superset-frontend/src/explore/components/ExploreViewContainer/index.tsx
@@ -37,6 +37,7 @@ import {
   MatrixifyFormData,
   DatasourceType,
   ensureIsArray,
+  handleKeyboardActivation,
 } from '@superset-ui/core';
 import {
   ControlStateMapping,
@@ -998,6 +999,7 @@ function ExploreViewContainer(props: 
ExploreViewContainerProps) {
               tabIndex={0}
               className="action-button"
               onClick={toggleCollapse}
+              onKeyDown={handleKeyboardActivation(toggleCollapse)}
             >
               <Icons.VerticalAlignTopOutlined
                 iconSize="xl"
@@ -1023,6 +1025,7 @@ function ExploreViewContainer(props: 
ExploreViewContainerProps) {
           <div
             className="sidebar"
             onClick={toggleCollapse}
+            onKeyDown={handleKeyboardActivation(toggleCollapse)}
             data-test="open-datasource-tab"
             role="button"
             tabIndex={0}
diff --git 
a/superset-frontend/src/explore/components/controls/ColumnConfigControl/ColumnConfigControl.tsx
 
b/superset-frontend/src/explore/components/controls/ColumnConfigControl/ColumnConfigControl.tsx
index 239deefaac7..201a90f3f23 100644
--- 
a/superset-frontend/src/explore/components/controls/ColumnConfigControl/ColumnConfigControl.tsx
+++ 
b/superset-frontend/src/explore/components/controls/ColumnConfigControl/ColumnConfigControl.tsx
@@ -16,6 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+import { handleKeyboardActivation } from '@superset-ui/core';
 import { useMemo, useState } from 'react';
 import { t } from '@apache-superset/core/translation';
 import { useTheme } from '@apache-superset/core/theme';
@@ -180,6 +181,9 @@ export default function ColumnConfigControl<T extends 
ColumnConfig>({
               },
             }}
             onClick={() => setShowAllColumns(!showAllColumns)}
+            onKeyDown={handleKeyboardActivation(() =>
+              setShowAllColumns(!showAllColumns),
+            )}
           >
             {showAllColumns ? (
               <>
diff --git 
a/superset-frontend/src/explore/components/controls/DndColumnSelectControl/ColumnSelectPopover.tsx
 
b/superset-frontend/src/explore/components/controls/DndColumnSelectControl/ColumnSelectPopover.tsx
index 1e69be2c45e..16d0aa344cc 100644
--- 
a/superset-frontend/src/explore/components/controls/DndColumnSelectControl/ColumnSelectPopover.tsx
+++ 
b/superset-frontend/src/explore/components/controls/DndColumnSelectControl/ColumnSelectPopover.tsx
@@ -35,6 +35,7 @@ import {
   DatasourceType,
   Metric,
   QueryFormMetric,
+  handleKeyboardActivation,
 } from '@superset-ui/core';
 import { styled, css } from '@apache-superset/core/theme';
 import { ColumnMeta, isSavedExpression } from '@superset-ui/chart-controls';
@@ -476,6 +477,9 @@ const ColumnSelectPopover = ({
                                   role="button"
                                   tabIndex={0}
                                   onClick={setDatasetAndClose}
+                                  onKeyDown={handleKeyboardActivation(
+                                    setDatasetAndClose,
+                                  )}
                                 >
                                   {t('Create a dataset')}
                                 </span>{' '}
@@ -487,6 +491,9 @@ const ColumnSelectPopover = ({
                                   role="button"
                                   tabIndex={0}
                                   onClick={setDatasetAndClose}
+                                  onKeyDown={handleKeyboardActivation(
+                                    setDatasetAndClose,
+                                  )}
                                 >
                                   {t('Create a dataset')}
                                 </span>{' '}
@@ -521,6 +528,9 @@ const ColumnSelectPopover = ({
                             role="button"
                             tabIndex={0}
                             onClick={setDatasetAndClose}
+                            onKeyDown={handleKeyboardActivation(
+                              setDatasetAndClose,
+                            )}
                           >
                             {t('Create a dataset')}
                           </span>{' '}
diff --git 
a/superset-frontend/src/explore/components/controls/DndColumnSelectControl/DndColumnSelectPopoverTitle.tsx
 
b/superset-frontend/src/explore/components/controls/DndColumnSelectControl/DndColumnSelectPopoverTitle.tsx
index 05c3cd3744c..38b3a47a73d 100644
--- 
a/superset-frontend/src/explore/components/controls/DndColumnSelectControl/DndColumnSelectPopoverTitle.tsx
+++ 
b/superset-frontend/src/explore/components/controls/DndColumnSelectControl/DndColumnSelectPopoverTitle.tsx
@@ -16,6 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+import { handleKeyboardActivation } from '@superset-ui/core';
 import { ChangeEvent, useCallback, useState } from 'react';
 import { t } from '@apache-superset/core/translation';
 import { styled, useTheme } from '@apache-superset/core/theme';
@@ -96,6 +97,7 @@ export const DndColumnSelectPopoverTitle = ({
         onMouseOut={onMouseOut}
         onFocus={onMouseOver}
         onClick={onClick}
+        onKeyDown={onClick ? handleKeyboardActivation(onClick) : undefined}
         onBlur={onBlur}
         role="button"
         tabIndex={0}
diff --git 
a/superset-frontend/src/explore/components/controls/LayerConfigsControl/LayerTreeItem.tsx
 
b/superset-frontend/src/explore/components/controls/LayerConfigsControl/LayerTreeItem.tsx
index 72f519ff7d8..ce99c88acd3 100644
--- 
a/superset-frontend/src/explore/components/controls/LayerConfigsControl/LayerTreeItem.tsx
+++ 
b/superset-frontend/src/explore/components/controls/LayerConfigsControl/LayerTreeItem.tsx
@@ -16,6 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+import { handleKeyboardActivation } from '@superset-ui/core';
 import { Icons } from '@superset-ui/core/components/Icons';
 import { Button } from '@superset-ui/core/components';
 import { Tag } from 'src/components';
@@ -47,6 +48,7 @@ export const LayerTreeItem: FC<LayerTreeItemProps> = ({
       <span
         className="layer-tree-item-type"
         onClick={onEditTag}
+        onKeyDown={handleKeyboardActivation(onEditTag)}
         role="button"
         tabIndex={0}
       >
@@ -55,6 +57,7 @@ export const LayerTreeItem: FC<LayerTreeItemProps> = ({
       <span
         className="layer-tree-item-title"
         onClick={onEditTag}
+        onKeyDown={handleKeyboardActivation(onEditTag)}
         role="button"
         tabIndex={0}
       >
diff --git 
a/superset-frontend/src/explore/components/controls/MetricControl/AdhocMetricEditPopover/index.tsx
 
b/superset-frontend/src/explore/components/controls/MetricControl/AdhocMetricEditPopover/index.tsx
index ccbd3a2deab..ce0fea1968b 100644
--- 
a/superset-frontend/src/explore/components/controls/MetricControl/AdhocMetricEditPopover/index.tsx
+++ 
b/superset-frontend/src/explore/components/controls/MetricControl/AdhocMetricEditPopover/index.tsx
@@ -19,7 +19,12 @@
 /* eslint-disable camelcase */
 import { memo, useCallback, useEffect, useMemo, useRef, useState } from 
'react';
 import { useSelector } from 'react-redux';
-import { isDefined, ensureIsArray, DatasourceType } from '@superset-ui/core';
+import {
+  isDefined,
+  ensureIsArray,
+  DatasourceType,
+  handleKeyboardActivation,
+} from '@superset-ui/core';
 import { t } from '@apache-superset/core/translation';
 import type { editors } from '@apache-superset/core';
 import { styled } from '@apache-superset/core/theme';
@@ -498,6 +503,10 @@ function AdhocMetricEditPopover({
                           handleDatasetModal?.(true);
                           onClose();
                         }}
+                        onKeyDown={handleKeyboardActivation(() => {
+                          handleDatasetModal?.(true);
+                          onClose();
+                        })}
                       >
                         {t('Create a dataset')}
                       </span>
diff --git 
a/superset-frontend/src/explore/components/controls/MetricControl/AdhocMetricEditPopoverTitle.tsx
 
b/superset-frontend/src/explore/components/controls/MetricControl/AdhocMetricEditPopoverTitle.tsx
index 57d5ed8e3c2..e9cc283f458 100644
--- 
a/superset-frontend/src/explore/components/controls/MetricControl/AdhocMetricEditPopoverTitle.tsx
+++ 
b/superset-frontend/src/explore/components/controls/MetricControl/AdhocMetricEditPopoverTitle.tsx
@@ -16,6 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+import { handleKeyboardActivation } from '@superset-ui/core';
 import {
   ChangeEventHandler,
   FocusEvent,
@@ -120,6 +121,7 @@ const AdhocMetricEditPopoverTitle: 
FC<AdhocMetricEditPopoverTitleProps> = ({
         onMouseOut={handleMouseOut}
         onFocus={handleMouseOver}
         onClick={handleClick}
+        onKeyDown={handleKeyboardActivation(handleClick)}
         onBlur={handleBlur}
         role="button"
         tabIndex={0}
diff --git 
a/superset-frontend/src/explore/components/controls/VizTypeControl/index.tsx 
b/superset-frontend/src/explore/components/controls/VizTypeControl/index.tsx
index ad11bd73da9..10c9fceff3f 100644
--- a/superset-frontend/src/explore/components/controls/VizTypeControl/index.tsx
+++ b/superset-frontend/src/explore/components/controls/VizTypeControl/index.tsx
@@ -18,7 +18,10 @@
  */
 import { useCallback, useState } from 'react';
 import { t } from '@apache-superset/core/translation';
-import { getChartMetadataRegistry } from '@superset-ui/core';
+import {
+  getChartMetadataRegistry,
+  handleKeyboardActivation,
+} from '@superset-ui/core';
 import { css, styled, SupersetTheme } from '@apache-superset/core/theme';
 import { usePluginContext } from 'src/components';
 import { Icons, Modal } from '@superset-ui/core/components';
@@ -112,7 +115,12 @@ const VizTypeControl = ({
           color: ${theme.colorTextTertiary};
         `}
       >
-        <span role="button" tabIndex={0} onClick={openModal}>
+        <span
+          role="button"
+          tabIndex={0}
+          onClick={openModal}
+          onKeyDown={handleKeyboardActivation(openModal)}
+        >
           {t('View all charts')}
         </span>
       </div>
diff --git 
a/superset-frontend/src/features/alerts/components/NotificationMethod.tsx 
b/superset-frontend/src/features/alerts/components/NotificationMethod.tsx
index 1a5df776491..6699ed02b67 100644
--- a/superset-frontend/src/features/alerts/components/NotificationMethod.tsx
+++ b/superset-frontend/src/features/alerts/components/NotificationMethod.tsx
@@ -31,6 +31,7 @@ import {
   JsonResponse,
   SupersetClient,
   isFeatureEnabled,
+  handleKeyboardActivation,
 } from '@superset-ui/core';
 import { styled, useTheme } from '@apache-superset/core/theme';
 import { Icons } from '@superset-ui/core/components/Icons';
@@ -574,6 +575,7 @@ export const NotificationMethod: 
FunctionComponent<NotificationMethodProps> = ({
                 tabIndex={0}
                 className="delete-button"
                 onClick={() => onRemove(index)}
+                onKeyDown={handleKeyboardActivation(() => onRemove(index))}
                 aria-label={t('Remove notification method')}
               >
                 <Icons.DeleteOutlined iconSize="l" />
@@ -773,6 +775,7 @@ export const NotificationMethod: 
FunctionComponent<NotificationMethodProps> = ({
                   role="button"
                   tabIndex={0}
                   onClick={() => setCcVisible(true)}
+                  onKeyDown={handleKeyboardActivation(() => 
setCcVisible(true))}
                   style={{ display: ccVisible ? 'none' : 'inline-flex' }}
                 >
                   <Icons.MailOutlined iconSize="xs" className="icon" />
@@ -783,6 +786,9 @@ export const NotificationMethod: 
FunctionComponent<NotificationMethodProps> = ({
                   role="button"
                   tabIndex={0}
                   onClick={() => setBccVisible(true)}
+                  onKeyDown={handleKeyboardActivation(() =>
+                    setBccVisible(true),
+                  )}
                   style={{ display: bccVisible ? 'none' : 'inline-flex' }}
                 >
                   <Icons.MailOutlined iconSize="xs" className="icon" />
diff --git a/superset-frontend/src/features/charts/ChartCard.tsx 
b/superset-frontend/src/features/charts/ChartCard.tsx
index 9a7c0569ed2..b55904f7144 100644
--- a/superset-frontend/src/features/charts/ChartCard.tsx
+++ b/superset-frontend/src/features/charts/ChartCard.tsx
@@ -17,7 +17,11 @@
  * under the License.
  */
 import { t } from '@apache-superset/core/translation';
-import { isFeatureEnabled, FeatureFlag } from '@superset-ui/core';
+import {
+  isFeatureEnabled,
+  FeatureFlag,
+  handleKeyboardActivation,
+} from '@superset-ui/core';
 import { css } from '@apache-superset/core/theme';
 import { Link, useHistory } from 'react-router-dom';
 import {
@@ -86,6 +90,7 @@ export default function ChartCard({
           role="button"
           tabIndex={0}
           onClick={() => openChartEditModal(chart)}
+          onKeyDown={handleKeyboardActivation(() => openChartEditModal(chart))}
         >
           <Icons.EditOutlined
             iconSize="l"
@@ -107,6 +112,9 @@ export default function ChartCard({
           role="button"
           tabIndex={0}
           onClick={() => handleBulkChartExport([chart])}
+          onKeyDown={handleKeyboardActivation(() =>
+            handleBulkChartExport([chart]),
+          )}
         >
           <Icons.UploadOutlined
             iconSize="l"
@@ -150,6 +158,7 @@ export default function ChartCard({
               tabIndex={0}
               className="action-button"
               onClick={confirmDelete}
+              onKeyDown={handleKeyboardActivation(confirmDelete)}
             >
               <Icons.DeleteOutlined
                 iconSize="l"
diff --git a/superset-frontend/src/features/dashboards/DashboardCard.tsx 
b/superset-frontend/src/features/dashboards/DashboardCard.tsx
index 6b45288641a..1b1096a24dc 100644
--- a/superset-frontend/src/features/dashboards/DashboardCard.tsx
+++ b/superset-frontend/src/features/dashboards/DashboardCard.tsx
@@ -18,7 +18,11 @@
  */
 import { Link, useHistory } from 'react-router-dom';
 import { t } from '@apache-superset/core/translation';
-import { isFeatureEnabled, FeatureFlag } from '@superset-ui/core';
+import {
+  isFeatureEnabled,
+  FeatureFlag,
+  handleKeyboardActivation,
+} from '@superset-ui/core';
 import { CardStyles } from 'src/views/CRUD/utils';
 import {
   FaveStar,
@@ -80,6 +84,9 @@ function DashboardCard({
           tabIndex={0}
           className="action-button"
           onClick={() => openDashboardEditModal(dashboard)}
+          onKeyDown={handleKeyboardActivation(() =>
+            openDashboardEditModal(dashboard),
+          )}
           data-test="dashboard-card-option-edit-button"
         >
           <Icons.EditOutlined iconSize="l" data-test="edit-alt" /> {t('Edit')}
@@ -96,6 +103,9 @@ function DashboardCard({
           role="button"
           tabIndex={0}
           onClick={() => handleBulkDashboardExport([dashboard])}
+          onKeyDown={handleKeyboardActivation(() =>
+            handleBulkDashboardExport([dashboard]),
+          )}
           className="action-button"
           data-test="dashboard-card-option-export-button"
         >
@@ -114,6 +124,7 @@ function DashboardCard({
           tabIndex={0}
           className="action-button"
           onClick={() => onDelete(dashboard)}
+          onKeyDown={handleKeyboardActivation(() => onDelete(dashboard))}
           data-test="dashboard-card-option-delete-button"
         >
           <Icons.DeleteOutlined iconSize="l" /> {t('Delete')}
diff --git 
a/superset-frontend/src/features/datasets/AddDataset/DatasetPanel/DatasetPanel.tsx
 
b/superset-frontend/src/features/datasets/AddDataset/DatasetPanel/DatasetPanel.tsx
index 6bf357a1f3b..ad29c510699 100644
--- 
a/superset-frontend/src/features/datasets/AddDataset/DatasetPanel/DatasetPanel.tsx
+++ 
b/superset-frontend/src/features/datasets/AddDataset/DatasetPanel/DatasetPanel.tsx
@@ -16,6 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+import { handleKeyboardActivation } from '@superset-ui/core';
 import { t } from '@apache-superset/core/translation';
 import { Alert } from '@apache-superset/core/components';
 import { styled } from '@apache-superset/core/theme';
@@ -235,6 +236,11 @@ const renderExistingDatasetAlert = (dataset?: 
DatasetObject) => (
               openInNewTab(stripAppRoot(dataset.explore_url));
             }
           }}
+          onKeyDown={handleKeyboardActivation(() => {
+            if (dataset?.explore_url) {
+              openInNewTab(stripAppRoot(dataset.explore_url));
+            }
+          })}
           tabIndex={0}
           className="view-dataset-button"
         >
diff --git a/superset-frontend/src/pages/ChartList/index.tsx 
b/superset-frontend/src/pages/ChartList/index.tsx
index 45e65370170..00ea34af07e 100644
--- a/superset-frontend/src/pages/ChartList/index.tsx
+++ b/superset-frontend/src/pages/ChartList/index.tsx
@@ -25,6 +25,7 @@ import {
   JsonResponse,
   SupersetClient,
   isMatrixifyEnabled,
+  handleKeyboardActivation,
 } from '@superset-ui/core';
 import { css, styled } from '@apache-superset/core/theme';
 import { useState, useMemo, useCallback } from 'react';
@@ -544,6 +545,7 @@ function ChartList(props: ChartListProps) {
                     tabIndex={0}
                     className="action-button"
                     onClick={openEditModal}
+                    onKeyDown={handleKeyboardActivation(openEditModal)}
                   >
                     <Icons.EditOutlined data-test="edit-alt" iconSize="l" />
                   </span>
@@ -561,6 +563,7 @@ function ChartList(props: ChartListProps) {
                     tabIndex={0}
                     className="action-button"
                     onClick={handleExport}
+                    onKeyDown={handleKeyboardActivation(handleExport)}
                   >
                     <Icons.UploadOutlined iconSize="l" />
                   </span>
@@ -589,6 +592,7 @@ function ChartList(props: ChartListProps) {
                         tabIndex={0}
                         className="action-button"
                         onClick={confirmDelete}
+                        onKeyDown={handleKeyboardActivation(confirmDelete)}
                       >
                         <Icons.DeleteOutlined iconSize="l" />
                       </span>
diff --git a/superset-frontend/src/pages/DashboardList/index.tsx 
b/superset-frontend/src/pages/DashboardList/index.tsx
index 100669050bb..91d3ef3bc80 100644
--- a/superset-frontend/src/pages/DashboardList/index.tsx
+++ b/superset-frontend/src/pages/DashboardList/index.tsx
@@ -21,6 +21,7 @@ import {
   isFeatureEnabled,
   FeatureFlag,
   SupersetClient,
+  handleKeyboardActivation,
 } from '@superset-ui/core';
 import { styled } from '@apache-superset/core/theme';
 import { useSelector } from 'react-redux';
@@ -503,6 +504,7 @@ function DashboardList(props: DashboardListProps) {
                     tabIndex={0}
                     className="action-button"
                     onClick={handleEdit}
+                    onKeyDown={handleKeyboardActivation(handleEdit)}
                   >
                     <Icons.EditOutlined data-test="edit-alt" iconSize="l" />
                   </span>
@@ -520,6 +522,7 @@ function DashboardList(props: DashboardListProps) {
                     tabIndex={0}
                     className="action-button"
                     onClick={handleExport}
+                    onKeyDown={handleKeyboardActivation(handleExport)}
                   >
                     <Icons.UploadOutlined iconSize="l" />
                   </span>
@@ -548,6 +551,7 @@ function DashboardList(props: DashboardListProps) {
                         tabIndex={0}
                         className="action-button"
                         onClick={confirmDelete}
+                        onKeyDown={handleKeyboardActivation(confirmDelete)}
                       >
                         <Icons.DeleteOutlined
                           iconSize="l"
diff --git a/superset-frontend/src/pages/DatabaseList/index.tsx 
b/superset-frontend/src/pages/DatabaseList/index.tsx
index aa284e26095..e36c3f38819 100644
--- a/superset-frontend/src/pages/DatabaseList/index.tsx
+++ b/superset-frontend/src/pages/DatabaseList/index.tsx
@@ -22,6 +22,7 @@ import {
   SupersetClient,
   isFeatureEnabled,
   FeatureFlag,
+  handleKeyboardActivation,
 } from '@superset-ui/core';
 import { css, styled, useTheme } from '@apache-superset/core/theme';
 import { useState, useMemo, useEffect, useCallback } from 'react';
@@ -697,6 +698,9 @@ function DatabaseList({
                       tabIndex={0}
                       className="action-button"
                       onClick={() => setSlCurrentlyDeleting(original)}
+                      onKeyDown={handleKeyboardActivation(() =>
+                        setSlCurrentlyDeleting(original),
+                      )}
                     >
                       <Icons.DeleteOutlined iconSize="l" />
                     </span>
@@ -715,6 +719,9 @@ function DatabaseList({
                       onClick={() =>
                         setSlCurrentlyEditing(original.uuid ?? null)
                       }
+                      onKeyDown={handleKeyboardActivation(() =>
+                        setSlCurrentlyEditing(original.uuid ?? null),
+                      )}
                     >
                       <Icons.EditOutlined iconSize="l" />
                     </span>
@@ -746,6 +753,7 @@ function DatabaseList({
                     tabIndex={0}
                     className="action-button"
                     onClick={handleEdit}
+                    onKeyDown={handleKeyboardActivation(handleEdit)}
                   >
                     <Icons.EditOutlined data-test="edit-alt" iconSize="l" />
                   </span>
@@ -762,6 +770,7 @@ function DatabaseList({
                     tabIndex={0}
                     className="action-button"
                     onClick={handleExport}
+                    onKeyDown={handleKeyboardActivation(handleExport)}
                   >
                     <Icons.UploadOutlined iconSize="l" />
                   </span>
@@ -779,6 +788,7 @@ function DatabaseList({
                     tabIndex={0}
                     className="action-button"
                     onClick={handleSync}
+                    onKeyDown={handleKeyboardActivation(handleSync)}
                   >
                     <Icons.SyncOutlined iconSize="l" />
                   </span>
@@ -791,6 +801,7 @@ function DatabaseList({
                   className="action-button"
                   data-test="database-delete"
                   onClick={handleDelete}
+                  onKeyDown={handleKeyboardActivation(handleDelete)}
                 >
                   <Tooltip
                     id="delete-action-tooltip"
diff --git a/superset-frontend/src/pages/DatasetList/index.tsx 
b/superset-frontend/src/pages/DatasetList/index.tsx
index 4c89289077e..84c4d306d2d 100644
--- a/superset-frontend/src/pages/DatasetList/index.tsx
+++ b/superset-frontend/src/pages/DatasetList/index.tsx
@@ -22,6 +22,7 @@ import {
   SupersetClient,
   isFeatureEnabled,
   FeatureFlag,
+  handleKeyboardActivation,
 } from '@superset-ui/core';
 import { styled, useTheme, css } from '@apache-superset/core/theme';
 import {
@@ -869,6 +870,9 @@ const DatasetList: FunctionComponent<DatasetListProps> = ({
                       tabIndex={0}
                       className="action-button"
                       onClick={() => handleSemanticViewDelete(original)}
+                      onKeyDown={handleKeyboardActivation(() =>
+                        handleSemanticViewDelete(original),
+                      )}
                     >
                       <Icons.DeleteOutlined iconSize="l" />
                     </span>
@@ -886,6 +890,9 @@ const DatasetList: FunctionComponent<DatasetListProps> = ({
                       tabIndex={0}
                       className="action-button"
                       onClick={() => setSvCurrentlyEditing(original)}
+                      onKeyDown={handleKeyboardActivation(() =>
+                        setSvCurrentlyEditing(original),
+                      )}
                     >
                       <Icons.EditOutlined iconSize="l" />
                     </span>
@@ -932,6 +939,11 @@ const DatasetList: FunctionComponent<DatasetListProps> = ({
                     tabIndex={0}
                     className={`action-button ${allowEdit ? '' : 'disabled'}`}
                     onClick={allowEdit ? handleEdit : undefined}
+                    onKeyDown={
+                      allowEdit
+                        ? handleKeyboardActivation(handleEdit)
+                        : undefined
+                    }
                   >
                     <Icons.EditOutlined iconSize="l" />
                   </span>
@@ -949,6 +961,7 @@ const DatasetList: FunctionComponent<DatasetListProps> = ({
                     tabIndex={0}
                     className="action-button"
                     onClick={handleExport}
+                    onKeyDown={handleKeyboardActivation(handleExport)}
                   >
                     <Icons.UploadOutlined iconSize="l" />
                   </span>
@@ -966,6 +979,7 @@ const DatasetList: FunctionComponent<DatasetListProps> = ({
                     tabIndex={0}
                     className="action-button"
                     onClick={handleDuplicate}
+                    onKeyDown={handleKeyboardActivation(handleDuplicate)}
                   >
                     <Icons.CopyOutlined iconSize="l" />
                   </span>
@@ -983,6 +997,7 @@ const DatasetList: FunctionComponent<DatasetListProps> = ({
                     tabIndex={0}
                     className="action-button"
                     onClick={handleDelete}
+                    onKeyDown={handleKeyboardActivation(handleDelete)}
                   >
                     <Icons.DeleteOutlined iconSize="l" />
                   </span>
diff --git a/superset-frontend/src/pages/RowLevelSecurityList/index.tsx 
b/superset-frontend/src/pages/RowLevelSecurityList/index.tsx
index 4d77911ba1d..689c493e49e 100644
--- a/superset-frontend/src/pages/RowLevelSecurityList/index.tsx
+++ b/superset-frontend/src/pages/RowLevelSecurityList/index.tsx
@@ -17,7 +17,7 @@
  * under the License.
  */
 import { t } from '@apache-superset/core/translation';
-import { SupersetClient } from '@superset-ui/core';
+import { SupersetClient, handleKeyboardActivation } from '@superset-ui/core';
 import { useCallback, useMemo, useState } from 'react';
 import { ConfirmStatusChange, Tooltip } from '@superset-ui/core/components';
 import {
@@ -209,6 +209,7 @@ function RowLevelSecurityList(props: RLSProps) {
                     tabIndex={0}
                     className="action-button"
                     onClick={handleEdit}
+                    onKeyDown={handleKeyboardActivation(handleEdit)}
                   >
                     <Icons.EditOutlined data-test="edit-alt" iconSize="l" />
                   </span>
@@ -236,6 +237,7 @@ function RowLevelSecurityList(props: RLSProps) {
                         tabIndex={0}
                         className="action-button"
                         onClick={confirmDelete}
+                        onKeyDown={handleKeyboardActivation(confirmDelete)}
                       >
                         <Icons.DeleteOutlined
                           data-test="rls-list-trash-icon"
diff --git a/superset-frontend/src/pages/Tags/index.tsx 
b/superset-frontend/src/pages/Tags/index.tsx
index ffd7bd591cc..00cfbe6c400 100644
--- a/superset-frontend/src/pages/Tags/index.tsx
+++ b/superset-frontend/src/pages/Tags/index.tsx
@@ -18,7 +18,11 @@
  */
 import { useMemo, useState } from 'react';
 import { t } from '@apache-superset/core/translation';
-import { isFeatureEnabled, FeatureFlag } from '@superset-ui/core';
+import {
+  isFeatureEnabled,
+  FeatureFlag,
+  handleKeyboardActivation,
+} from '@superset-ui/core';
 import {
   Actions,
   createErrorHandler,
@@ -219,6 +223,7 @@ function TagList(props: TagListProps) {
                         tabIndex={0}
                         className="action-button"
                         onClick={confirmDelete}
+                        onKeyDown={handleKeyboardActivation(confirmDelete)}
                       >
                         <Icons.DeleteOutlined
                           data-test="dashboard-list-trash-icon"
@@ -240,6 +245,7 @@ function TagList(props: TagListProps) {
                     tabIndex={0}
                     className="action-button"
                     onClick={handleEdit}
+                    onKeyDown={handleKeyboardActivation(handleEdit)}
                   >
                     <Icons.EditOutlined data-test="edit-alt" iconSize="l" />
                   </span>
diff --git a/superset-frontend/src/pages/TaskList/index.tsx 
b/superset-frontend/src/pages/TaskList/index.tsx
index 41b25d65602..3acac2d5177 100644
--- a/superset-frontend/src/pages/TaskList/index.tsx
+++ b/superset-frontend/src/pages/TaskList/index.tsx
@@ -21,6 +21,7 @@ import {
   FeatureFlag,
   isFeatureEnabled,
   SupersetClient,
+  handleKeyboardActivation,
 } from '@superset-ui/core';
 import { useTheme } from '@apache-superset/core/theme';
 import { t } from '@apache-superset/core/translation';
@@ -519,6 +520,9 @@ function TaskList({ addDangerToast, addSuccessToast, user 
}: TaskListProps) {
                     tabIndex={0}
                     className="action-button"
                     onClick={() => openCancelModal(original)}
+                    onKeyDown={handleKeyboardActivation(() =>
+                      openCancelModal(original),
+                    )}
                   >
                     <Icons.StopOutlined iconSize="l" />
                   </span>

Reply via email to