diff --git a/packages/main/package.json b/packages/main/package.json
index f0a5536e414..7e7170a6016 100644
--- a/packages/main/package.json
+++ b/packages/main/package.json
@@ -55,6 +55,10 @@
"types": "./dist/components/FilterBar/index.d.ts",
"default": "./dist/components/FilterBar/index.js"
},
+ "./FilterBarSearchIcon": {
+ "types": "./dist/components/FilterBarSearchIcon/index.d.ts",
+ "default": "./dist/components/FilterBarSearchIcon/index.js"
+ },
"./FilterGroupItem": {
"types": "./dist/components/FilterGroupItem/index.d.ts",
"default": "./dist/components/FilterGroupItem/index.js"
diff --git a/packages/main/src/components/FilterBar/FilterBar.mdx b/packages/main/src/components/FilterBar/FilterBar.mdx
index 50950bcae7b..02e0a6bc1f0 100644
--- a/packages/main/src/components/FilterBar/FilterBar.mdx
+++ b/packages/main/src/components/FilterBar/FilterBar.mdx
@@ -1,12 +1,13 @@
import { ArgTypesWithNote, ControlsWithNote, DocsHeader, Footer } from '@sb/components';
import SubcomponentsSection from '@sb/docs/SubcomponentsSection.md?raw';
import { Canvas, Description, Markdown, Meta } from '@storybook/addon-docs/blocks';
+import { FilterBarSearchIcon } from '../FilterBarSearchIcon';
import { FilterGroupItem } from '../FilterGroupItem';
import * as ComponentStories from './FilterBar.stories';
-
+
@@ -407,6 +408,14 @@ const handleInput = (event) => {
+## Trigger the search via the search icon
+
+By default, the search icon of the `search` input is decorative. To let users trigger the search by activating the search icon (in addition to pressing Enter in the input), pass the `FilterBarSearchIcon` subcomponent to the `icon` prop of the search input and wire its `onClick` handler.
+
+This is recommended when the "Go" button is displayed (`showGoOnFB`). The `FilterBarSearchIcon` is pre-controlled — you decide what "trigger search" means in its `onClick` handler.
+
+
+
{SubcomponentsSection}
## FilterGroupItem
@@ -414,4 +423,9 @@ const handleInput = (event) => {
+## FilterBarSearchIcon
+
+
+
+
diff --git a/packages/main/src/components/FilterBar/FilterBar.stories.tsx b/packages/main/src/components/FilterBar/FilterBar.stories.tsx
index 5e75849a3a2..225c3f8ae3b 100644
--- a/packages/main/src/components/FilterBar/FilterBar.stories.tsx
+++ b/packages/main/src/components/FilterBar/FilterBar.stories.tsx
@@ -3,6 +3,8 @@ import TitleLevel from '@ui5/webcomponents/dist/types/TitleLevel.js';
import { useId, useReducer, useRef, useState } from 'react';
import { fn } from 'storybook/test';
import { FlexBoxDirection } from '../../enums/index.js';
+import type { ComboBoxDomRef } from '../../webComponents/ComboBox/index.js';
+import type { DatePickerDomRef } from '../../webComponents/DatePicker/index.js';
import {
ComboBox,
ComboBoxItem,
@@ -24,7 +26,9 @@ import {
Title,
Token,
} from '../../webComponents/index.js';
+import type { InputDomRef } from '../../webComponents/Input/index.js';
import { Text } from '../../webComponents/Text/index.js';
+import { FilterBarSearchIcon } from '../FilterBarSearchIcon/index.js';
import { FilterGroupItem } from '../FilterGroupItem/index.js';
import { FlexBox } from '../FlexBox/index.js';
import { VariantItem } from '../VariantItem/index.js';
@@ -623,3 +627,90 @@ export const IdentifyInputEventOrigin: Story = {
);
},
};
+
+interface SearchSubmission {
+ searchTerm: string;
+ date: string;
+ category: string;
+}
+
+const initialSubmission: SearchSubmission = { searchTerm: '', date: '', category: '' };
+
+function submissionReducer(state: SearchSubmission, action: { type: 'submit'; payload: SearchSubmission }) {
+ switch (action.type) {
+ case 'submit':
+ return action.payload;
+ default:
+ return state;
+ }
+}
+
+export const WithInteractiveSearchIcon: Story = {
+ name: 'with interactive search icon',
+ args: {
+ showGoOnFB: true,
+ },
+ render(args) {
+ const searchRef = useRef(null);
+ const dateRef = useRef(null);
+ const categoryRef = useRef(null);
+ const [submission, dispatch] = useReducer(submissionReducer, initialSubmission);
+ // pre-controlled: the consumer decides what "trigger search" means
+ const triggerSearch = () => {
+ dispatch({
+ type: 'submit',
+ payload: {
+ searchTerm: searchRef.current?.value ?? '',
+ date: dateRef.current?.value ?? '',
+ category: categoryRef.current?.value ?? '',
+ },
+ });
+ };
+ return (
+ <>
+ }
+ />
+ }
+ >
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {submission.searchTerm}
+
+
+
+ {submission.date}
+
+
+
+ {submission.category}
+
+
+ >
+ );
+ },
+};
diff --git a/packages/main/src/components/FilterBar/index.tsx b/packages/main/src/components/FilterBar/index.tsx
index 4444708b5f8..1e4efae3075 100644
--- a/packages/main/src/components/FilterBar/index.tsx
+++ b/packages/main/src/components/FilterBar/index.tsx
@@ -393,7 +393,7 @@ const FilterBar = forwardRef((props, ref) =>
noTypeahead: search.props.noTypeahead ?? true,
showClearIcon: true,
type: InputType.Search,
- icon: ,
+ icon: search.props.icon ?? ,
})}
diff --git a/packages/main/src/components/FilterBar/types.ts b/packages/main/src/components/FilterBar/types.ts
index 66e5c650878..b7bb0e17a6e 100644
--- a/packages/main/src/components/FilterBar/types.ts
+++ b/packages/main/src/components/FilterBar/types.ts
@@ -84,7 +84,9 @@ export interface FilterBarPropTypes extends CommonProps {
/**
* Defines the search field rendered as first filter item.
*
- * __Note:__ By default, `placeholder`, `icon`, `noTypeahead`, `showClearIcon`, and `type` are applied to the search input. Only `placeholder` and `noTypeahead` can be overridden.
+ * __Note:__
+ * - By default, `placeholder`, `icon`, `noTypeahead`, `showClearIcon`, and `type` are applied to the search input. Only `placeholder`, `noTypeahead`, and `icon` can be overridden.
+ * - By default, the search icon is decorative. If the "Go" button is displayed (`showGoOnFB`), pass the `FilterBarSearchIcon` subcomponent to the `icon` prop of the search input to render an interactive search icon that can trigger the search.
*
* __Note:__ The field is only available in the FilterBar not inside the filter configuration dialog.
*/
diff --git a/packages/main/src/components/FilterBarSearchIcon/index.tsx b/packages/main/src/components/FilterBarSearchIcon/index.tsx
new file mode 100644
index 00000000000..c82ac53e293
--- /dev/null
+++ b/packages/main/src/components/FilterBarSearchIcon/index.tsx
@@ -0,0 +1,37 @@
+'use client';
+
+import searchIcon from '@ui5/webcomponents-icons/dist/search.js';
+import { useI18nBundle } from '@ui5/webcomponents-react-base';
+import { forwardRef } from 'react';
+import { SEARCH } from '../../i18n/i18n-defaults.js';
+import type { InputIconDomRef, InputIconPropTypes } from '../../webComponents/InputIcon/index.js';
+import { InputIcon } from '../../webComponents/InputIcon/index.js';
+
+export interface FilterBarSearchIconPropTypes extends Omit {
+ /**
+ * Defines the accessible name of the icon.
+ *
+ * **Note:** This property is used for accessibility purposes and will be announced by screen readers.
+ * When set, it is also rendered as a native `title` tooltip.
+ * @default the translated "Search" text
+ */
+ accessibleName?: InputIconPropTypes['accessibleName'];
+}
+
+/**
+ * The `FilterBarSearchIcon` is an interactive search icon intended to be passed to the `icon` prop of the `FilterBar`'s `search` input.
+ *
+ * Unlike the default decorative search icon, it offers button-like behavior, which allows the search to be triggered by activating the icon. This is required when the "Go" button is displayed.
+ */
+const FilterBarSearchIcon = forwardRef((props, ref) => {
+ const { accessibleName, ...rest } = props;
+ const i18nBundle = useI18nBundle('@ui5/webcomponents-react');
+
+ return (
+
+ );
+});
+
+FilterBarSearchIcon.displayName = 'FilterBarSearchIcon';
+
+export { FilterBarSearchIcon };
diff --git a/packages/main/src/components/FilterBarSearchIcon/test/FilterBarSearchIcon.gallery.tsx b/packages/main/src/components/FilterBarSearchIcon/test/FilterBarSearchIcon.gallery.tsx
new file mode 100644
index 00000000000..12306cec704
--- /dev/null
+++ b/packages/main/src/components/FilterBarSearchIcon/test/FilterBarSearchIcon.gallery.tsx
@@ -0,0 +1,28 @@
+import { useRef, useState } from 'react';
+import type { InputDomRef } from '../../../webComponents/Input/index.js';
+import { Input } from '../../../webComponents/Input/index.js';
+import { FilterBar } from '../../FilterBar/index.js';
+import { FilterGroupItem } from '../../FilterGroupItem/index.js';
+import { FilterBarSearchIcon } from '../index.js';
+
+export const FilterBarSearchIconTestComp = () => {
+ const inputRef = useRef(null);
+ const [clickCount, setClickCount] = useState(0);
+ const [submittedTerm, setSubmittedTerm] = useState('');
+ // pre-controlled: the consumer decides what "trigger search" means
+ const triggerSearch = () => {
+ setClickCount((prev) => prev + 1);
+ setSubmittedTerm(inputRef.current?.value ?? '');
+ };
+ return (
+ <>
+ } />}>
+
+
+
+
+ {clickCount}
+ {submittedTerm}
+ >
+ );
+};
diff --git a/packages/main/src/components/FilterBarSearchIcon/test/FilterBarSearchIcon.spec.tsx b/packages/main/src/components/FilterBarSearchIcon/test/FilterBarSearchIcon.spec.tsx
new file mode 100644
index 00000000000..703485fe639
--- /dev/null
+++ b/packages/main/src/components/FilterBarSearchIcon/test/FilterBarSearchIcon.spec.tsx
@@ -0,0 +1,18 @@
+import { expect, test } from '../../../../../../playwright/fixtures/gallery-fixtures.js';
+
+test.describe('FilterBarSearchIcon', () => {
+ test('triggers the search handler when the icon is activated', async ({ mount, page, ui5wc }) => {
+ await mount('FilterBarSearchIcon/FilterBarSearchIconTestComp');
+
+ const searchInput = page.locator('[ui5-input]').first();
+ await expect(searchInput).toBeVisible();
+ await ui5wc.typeIntoInput(searchInput, 'quarterly report');
+
+ await expect(page.getByTestId('search-click-count')).toHaveText('0');
+
+ await page.locator('[ui5-input-icon][slot="icon"]').click();
+
+ await expect(page.getByTestId('search-click-count')).toHaveText('1');
+ await expect(page.getByTestId('submitted-term')).toHaveText('quarterly report');
+ });
+});
diff --git a/packages/main/src/index.ts b/packages/main/src/index.ts
index 09af9552b51..bb2a1f83f3f 100644
--- a/packages/main/src/index.ts
+++ b/packages/main/src/index.ts
@@ -10,6 +10,7 @@ export type { ObjectPageHeaderPropTypes } from './components/ObjectPageHeader/in
export { ObjectPageTitle } from './components/ObjectPageTitle/index.js';
export type { ObjectPageTitlePropTypes } from './components/ObjectPageTitle/index.js';
export * from './components/FilterBar/index.js';
+export * from './components/FilterBarSearchIcon/index.js';
export * from './components/FilterGroupItem/index.js';
export * from './components/FlexBox/index.js';
export * from './components/Grid/index.js';
diff --git a/packages/mcp-server/src/utils/component-config.ts b/packages/mcp-server/src/utils/component-config.ts
index 41d28acefb5..3968a2c98cc 100644
--- a/packages/mcp-server/src/utils/component-config.ts
+++ b/packages/mcp-server/src/utils/component-config.ts
@@ -25,7 +25,7 @@ export const REACT_COMPONENT_CATEGORIES = {
'ThemeProvider',
'FilterBar',
],
- Inputs: ['FilterGroupItem', 'VariantManagement', 'VariantItem', 'MessageViewButton'],
+ Inputs: ['FilterGroupItem', 'FilterBarSearchIcon', 'VariantManagement', 'VariantItem', 'MessageViewButton'],
'Modals & Popovers': ['MessageBox', 'ActionSheet', 'SelectDialog'],
'User Feedback': ['MessageView', 'MessageItem', 'Modals'],
};
diff --git a/playwright/gallery/vite.config.ts b/playwright/gallery/vite.config.ts
index fabf72dc80e..b203716cc7e 100644
--- a/playwright/gallery/vite.config.ts
+++ b/playwright/gallery/vite.config.ts
@@ -21,6 +21,7 @@ export default defineConfig({
withCoverage &&
IstanbulPlugin({
include: [
+ 'packages/main/src/components/FilterBarSearchIcon/**/*',
'packages/main/src/components/SelectDialog/**/*',
'packages/main/src/components/Splitter*/**/*',
'packages/charts/src/**/*',