diff --git a/packages/module/src/DataViewTextFilter/DataViewTextFilter.test.tsx b/packages/module/src/DataViewTextFilter/DataViewTextFilter.test.tsx
index 3457d9a2..665d480c 100644
--- a/packages/module/src/DataViewTextFilter/DataViewTextFilter.test.tsx
+++ b/packages/module/src/DataViewTextFilter/DataViewTextFilter.test.tsx
@@ -1,4 +1,5 @@
-import { render } from '@testing-library/react';
+import { render, fireEvent } from '@testing-library/react';
+import '@testing-library/jest-dom';
import DataViewTextFilter, { DataViewTextFilterProps } from './DataViewTextFilter';
import DataViewToolbar from '../DataViewToolbar';
@@ -20,4 +21,87 @@ describe('DataViewTextFilter component', () => {
/>);
expect(container).toMatchSnapshot();
});
+
+ it('should focus the search input when "/" key is pressed and filter is visible', () => {
+ const { container } = render(
+ }
+ />);
+
+ const input = document.getElementById('test-filter') as HTMLInputElement;
+ expect(input).toBeInTheDocument();
+
+ // Simulate pressing "/" key by creating and dispatching a KeyboardEvent
+ const keyEvent = new KeyboardEvent('keydown', {
+ key: '/',
+ code: 'Slash',
+ bubbles: true,
+ cancelable: true,
+ });
+ window.dispatchEvent(keyEvent);
+
+ // Check that the input has focus
+ expect(document.activeElement).toBe(input);
+ });
+
+ it('should not focus the search input when "/" key is pressed if filter is not visible', () => {
+ const { container } = render(
+ }
+ />);
+
+ const input = document.getElementById('test-filter') as HTMLInputElement;
+
+ // Simulate pressing "/" key
+ const keyEvent = new KeyboardEvent('keydown', {
+ key: '/',
+ code: 'Slash',
+ bubbles: true,
+ cancelable: true,
+ });
+ window.dispatchEvent(keyEvent);
+
+ if (input) {
+ expect(document.activeElement).not.toBe(input);
+ }
+ });
+
+ it('should not focus the search input when "/" key is pressed while typing in another input', () => {
+ const { container } = render(
+
+
+
+ }
+ />
+
+ );
+
+ const otherInput = container.querySelector('[data-testid="other-input"]') as HTMLInputElement;
+ const searchInput = document.getElementById('test-filter') as HTMLInputElement;
+
+ // Focus the other input first
+ otherInput.focus();
+ expect(document.activeElement).toBe(otherInput);
+
+ // Simulate pressing "/" key while focused on the other input
+ // The event target should be the input element
+ const keyEvent = new KeyboardEvent('keydown', {
+ key: '/',
+ code: 'Slash',
+ bubbles: true,
+ cancelable: true,
+ });
+ Object.defineProperty(keyEvent, 'target', {
+ value: otherInput,
+ enumerable: true,
+ });
+ window.dispatchEvent(keyEvent);
+
+ // The search input should not be focused since we're already in an input field
+ expect(document.activeElement).toBe(otherInput);
+ });
});
diff --git a/packages/module/src/DataViewTextFilter/DataViewTextFilter.tsx b/packages/module/src/DataViewTextFilter/DataViewTextFilter.tsx
index 9d30ff31..2e1696cd 100644
--- a/packages/module/src/DataViewTextFilter/DataViewTextFilter.tsx
+++ b/packages/module/src/DataViewTextFilter/DataViewTextFilter.tsx
@@ -1,4 +1,4 @@
-import { FC } from 'react';
+import { FC, useEffect } from 'react';
import { SearchInput, SearchInputProps, ToolbarFilter, ToolbarFilterProps } from '@patternfly/react-core';
/** extends SearchInputProps */
@@ -29,26 +29,55 @@ export const DataViewTextFilter: FC = ({
trimValue = true,
ouiaId = 'DataViewTextFilter',
...props
-}: DataViewTextFilterProps) => (
- 0 ? [ { key: title, node: value } ] : []}
- deleteLabel={() => onChange?.(undefined, '')}
- categoryName={title}
- showToolbarItem={showToolbarItem}
- >
- onChange?.(e, trimValue ? inputValue.trim() : inputValue)}
- onClear={onClear}
- placeholder={`Filter by ${title}`}
- aria-label={`${title ?? filterId} filter`}
- data-ouia-component-id={`${ouiaId}-input`}
- {...props}
- />
-
-);
+}: DataViewTextFilterProps) => {
+ useEffect(() => {
+ const handleKeyDown = (event: KeyboardEvent) => {
+ // Only handle "/" key when not typing in an input, textarea, or contenteditable element
+ if (event.key === '/' && !event.ctrlKey && !event.metaKey && !event.altKey) {
+ const target = event.target as HTMLElement;
+ const isInputElement = target.tagName === 'INPUT' ||
+ target.tagName === 'TEXTAREA' ||
+ target.isContentEditable;
+
+ // Only focus if the filter is visible and we're not already in an input field
+ if (showToolbarItem && !isInputElement) {
+ // Find the input element by its ID (searchInputId prop)
+ const inputElement = document.getElementById(filterId) as HTMLInputElement;
+ if (inputElement) {
+ event.preventDefault();
+ inputElement.focus();
+ }
+ }
+ }
+ };
+
+ window.addEventListener('keydown', handleKeyDown);
+ return () => {
+ window.removeEventListener('keydown', handleKeyDown);
+ };
+ }, [showToolbarItem, filterId]);
+
+ return (
+ 0 ? [ { key: title, node: value } ] : []}
+ deleteLabel={() => onChange?.(undefined, '')}
+ categoryName={title}
+ showToolbarItem={showToolbarItem}
+ >
+ onChange?.(e, trimValue ? inputValue.trim() : inputValue)}
+ onClear={onClear}
+ placeholder={`Filter by ${title}`}
+ aria-label={`${title ?? filterId} filter`}
+ data-ouia-component-id={`${ouiaId}-input`}
+ {...props}
+ />
+
+ );
+};
export default DataViewTextFilter;