diff --git a/docusaurus/docs/React/custom-code-examples/channel-search.mdx b/docusaurus/docs/React/custom-code-examples/channel-search.mdx
index 7490bdf8b7..6d47b9b865 100644
--- a/docusaurus/docs/React/custom-code-examples/channel-search.mdx
+++ b/docusaurus/docs/React/custom-code-examples/channel-search.mdx
@@ -339,3 +339,92 @@ const customSearchFunction = async (props: ChannelSearchFunctionParams, event: {
additionalChannelSearchProps={{searchFunction: customSearchFunction}}
/>
```
+
+### Adding menu
+
+As of the version 10.0.0, users can add app menu into the `SearchBar`. In case you would like to display menu button next to the search input, you can do that by adding [`AppMenu` component](../utility-components/channel-search.mdx/#appmenu) to the `ChannelSearch` props. The display of `AppMenu` is then toggled by clicking on the menu button. `AppMenu` can be rendered as a drop-down or even a modal. In our example we will render a drop-down menu.
+
+:::caution
+The SDK does not provide any default `AppMenu` component and so you will have to write your CSS for it to be styled correctly.
+:::
+
+```tsx
+import React, { useCallback } from 'react';
+import type { AppMenuProps } from 'stream-chat-react';
+
+import './AppMenu.scss';
+
+export const AppMenu = ({close}: AppMenuProps) => {
+
+ const handleSelect = useCallback(() => {
+ // custom logic...
+ close?.();
+ }, [close]);
+
+ return (
+
+
+ - Profile
+ - New Group
+ - Sign Out
+
+
+ );
+}
+```
+
+```scss
+.str-chat__channel-search-bar-button.str-chat__channel-search-bar-button--menu {
+ position: relative;
+}
+
+.app-menu {
+ &__container {
+ position: absolute;
+ top: 50px;
+ left: 10px;
+ background-color: white;
+ border-radius: 5px;
+ box-shadow: 0 0 8px var(--str-chat__box-shadow-color);
+ }
+
+ &__item-list {
+ list-style: none;
+ margin: 0;
+ padding: 0;
+ }
+
+ &__item {
+ list-style: none;
+ margin: 0;
+ padding: .5rem 1rem;
+
+ &:hover {
+ background-color: lightgrey;
+ cursor: pointer;
+ }
+ }
+}
+```
+
+```jsx
+import { AppMenu } from './components/AppMenu';
+
+const App = () => (
+
+
+
+
+
+
+
+
+
+
+
+);
+```
diff --git a/docusaurus/docs/React/utility-components/channel-search.mdx b/docusaurus/docs/React/utility-components/channel-search.mdx
index 2e635f4be8..19ecef47d3 100644
--- a/docusaurus/docs/React/utility-components/channel-search.mdx
+++ b/docusaurus/docs/React/utility-components/channel-search.mdx
@@ -158,11 +158,11 @@ The `ChannelSearch` offers possibility to keep the search results open meanwhile
### AppMenu
-Application menu / drop-down to be displayed when clicked on [`MenuIcon`](./#menuicon). Prop is consumed only by the [`SearchBar` component](./#searchbar). The `SearchBar` component is rendered with `themeVersion` `'2'` only. No default component provided by the SDK. The library does not provide any CSS for `AppMenu`.
+Application menu / drop-down to be displayed when clicked on [`MenuIcon`](./#menuicon). Prop is consumed only by the [`SearchBar` component](./#searchbar). The `SearchBar` component is only available with the use of the [theming v2](../theming/introduction.mdx). No default component is provided by the SDK. The library does not provide any CSS for `AppMenu`. Consult the customization tutorial on how to [add AppMenu to your application](../custom-code-examples/channel-search.mdx/#adding-menu). The component is passed a prop `close`, which is a function that can be called to hide the app menu (e.g. on menu item selection).
-| Type | Default |
-| ------------------- | ------------ |
-| `React.ComponentType` | `undefined` |
+| Type | Default |
+|-----------------------|-------------|
+| `React.ComponentType` | `undefined` |
### channelType
diff --git a/src/components/ChannelSearch/SearchBar.tsx b/src/components/ChannelSearch/SearchBar.tsx
index 83d679767f..40aa584900 100644
--- a/src/components/ChannelSearch/SearchBar.tsx
+++ b/src/components/ChannelSearch/SearchBar.tsx
@@ -16,6 +16,10 @@ import {
} from './icons';
import { SearchInput as DefaultSearchInput, SearchInputProps } from './SearchInput';
+export type AppMenuProps = {
+ close?: () => void;
+};
+
type SearchBarButtonProps = {
className?: string;
onClick?: MouseEventHandler;
@@ -48,7 +52,7 @@ export type SearchBarController = {
export type AdditionalSearchBarProps = {
/** Application menu to be displayed when clicked on MenuIcon */
- AppMenu?: React.ComponentType;
+ AppMenu?: React.ComponentType;
/** Custom icon component used to clear the input value on click. Displayed within the search input wrapper. */
ClearInputIcon?: React.ComponentType;
/** Custom icon component used to terminate the search UI session on click. */
@@ -133,6 +137,8 @@ export const SearchBar = (props: SearchBarProps) => {
inputProps.inputRef.current?.focus();
}, []);
+ const closeAppMenu = useCallback(() => setMenuIsOpen(false), []);
+
return (
{inputIsFocused ? (
@@ -172,7 +178,7 @@ export const SearchBar = (props: SearchBarProps) => {
{menuIsOpen && AppMenu && (
)}
diff --git a/src/components/ChannelSearch/__tests__/SearchBar.test.js b/src/components/ChannelSearch/__tests__/SearchBar.test.js
index 977b4deea5..9632443b14 100644
--- a/src/components/ChannelSearch/__tests__/SearchBar.test.js
+++ b/src/components/ChannelSearch/__tests__/SearchBar.test.js
@@ -22,7 +22,12 @@ jest.spyOn(window, 'getComputedStyle').mockReturnValue({
let client;
const inputText = new Date().getTime().toString();
-const AppMenu = () => AppMenu
;
+const AppMenu = ({ close }) => (
+
+);
const ClearInputIcon = () => CustomClearInputIcon
;
const MenuIcon = () => CustomMenuIcon
;
const SearchInputIcon = () => CustomSearchInputIcon
;
@@ -301,6 +306,30 @@ describe('SearchBar', () => {
});
});
+ it('should close the app menu on menu item click', async () => {
+ await act(() => {
+ renderComponent({
+ client,
+ props: { AppMenu },
+ searchParams: { disabled: false },
+ });
+ });
+ const menuIcon = screen.queryByTestId('menu-icon');
+ await act(() => {
+ fireEvent.click(menuIcon);
+ });
+
+ const menuItem = screen.queryByTestId('menu-item');
+
+ await act(() => {
+ fireEvent.click(menuItem);
+ });
+
+ await waitFor(() => {
+ expect(screen.queryByText('AppMenu')).not.toBeInTheDocument();
+ });
+ });
+
it.each([
[
'on click outside',
diff --git a/src/components/ChannelSearch/index.ts b/src/components/ChannelSearch/index.ts
index e8561aae22..ee626c4f79 100644
--- a/src/components/ChannelSearch/index.ts
+++ b/src/components/ChannelSearch/index.ts
@@ -1,4 +1,5 @@
export * from './ChannelSearch';
+export * from './SearchBar';
export * from './SearchInput';
export * from './SearchResults';
export * from './utils';