diff --git a/packages/main/src/components/MessageView/MessageView.cy.tsx b/packages/main/src/components/MessageView/MessageView.cy.tsx
index 9060fedc806..6f5c2a906ff 100644
--- a/packages/main/src/components/MessageView/MessageView.cy.tsx
+++ b/packages/main/src/components/MessageView/MessageView.cy.tsx
@@ -234,4 +234,20 @@ describe('MessageView', () => {
cy.get('@select').should('have.been.calledTwice');
cy.get('[name="slim-arrow-left"]').should('not.exist');
});
+
+ it('listAccessibleDescription & listAccessibleDescriptionRef', () => {
+ cy.mount(
+ <>
+ External description
+
+
+ Error
+
+
+ >,
+ );
+ cy.get('[ui5-list]')
+ .should('have.attr', 'accessible-description', 'Inline description')
+ .and('have.attr', 'accessible-description-ref', 'desc');
+ });
});
diff --git a/packages/main/src/components/MessageView/MessageView.mdx b/packages/main/src/components/MessageView/MessageView.mdx
index 4d18db23517..870f096bdb6 100644
--- a/packages/main/src/components/MessageView/MessageView.mdx
+++ b/packages/main/src/components/MessageView/MessageView.mdx
@@ -25,21 +25,32 @@ This component exposes public methods. You can invoke them directly on the insta
| ------------------ | ---------- | --------------------------------------------------------------------------- |
| **`navigateBack`** | — | Navigates back to the list view if you are in the details view of a message |
-## Usage Notes
+## More Examples
-The `MessageView` can be used in several scenarios, but most likely in Dialogs or Popovers.
+### MessageView with Interactive Links
-If used in a Popover it is recommended that the `MessageViewButton` is used as an opener.
-The `type` of the button should always reflect the highest severity (Error -> Warning -> Success -> Information).
+When `MessageItem` components contain `Link`s, make sure to set the `listAccessibleDescription` or `listAccessibleDescriptionRef` prop to inform screen reader users about interactive content and how to access it (F2 key).
-If the `MessageView` is used in a standalone way, you can set the prop `showDetailsPageHeader` to `true`.
-This will add a bar to the details page where a back button is contained.
+
-When used in a `Dialog` or a `Popover`, we recommend not setting the `showDetailsPageHeader` prop but rather listen
-to the `onItemSelect` event and add a back button to your Dialog or Popover header and use the `navigateBack()` method
-to get back to the list view.
+#### Reusing i18n texts from @ui5/webcomponents-react
-## More Examples
+You can reuse the built-in translation texts with the `useI18nBundle` hook:
+
+```tsx
+import { useI18nBundle } from '@ui5/webcomponents-react-base/hooks';
+
+function MyComponent() {
+ const i18nBundle = useI18nBundle('@ui5/webcomponents-react');
+ const listAccessibleDescription = `${i18nBundle.getText({ key: 'LIST_INTERACTIVE_ITEMS', defaultText: 'List with interactive items.' })} ${i18nBundle.getText({ key: 'MOVE_TO_CONTENT_F2', defaultText: 'To move to the content press F2.' })}`;
+
+ return (
+
+ {/* MessageItems with Links */}
+
+ );
+}
+```
### MessageView in a Dialog
diff --git a/packages/main/src/components/MessageView/MessageView.stories.tsx b/packages/main/src/components/MessageView/MessageView.stories.tsx
index 457ed414ee7..6d199b36add 100644
--- a/packages/main/src/components/MessageView/MessageView.stories.tsx
+++ b/packages/main/src/components/MessageView/MessageView.stories.tsx
@@ -5,6 +5,7 @@ import TitleLevel from '@ui5/webcomponents/dist/types/TitleLevel.js';
import WrappingType from '@ui5/webcomponents/dist/types/WrappingType.js';
import ValueState from '@ui5/webcomponents-base/dist/types/ValueState.js';
import arrowLeftIcon from '@ui5/webcomponents-icons/dist/slim-arrow-left.js';
+import { useI18nBundle } from '@ui5/webcomponents-react-base/hooks';
import { useRef, useState } from 'react';
import { FlexBoxAlignItems, FlexBoxJustifyContent } from '../../enums/index.js';
import { Bar } from '../../webComponents/Bar/index.js';
@@ -22,16 +23,6 @@ import { MessageView } from './index.js';
const meta = {
title: 'User Feedback / MessageView',
component: MessageView,
- argTypes: {
- showDetailsPageHeader: { description: 'Defines whether the header of the details page will be shown.' },
- groupItems: { description: 'Defines whether the messages are grouped or not.' },
- onItemSelect: { description: 'Event is fired when the details of a message are shown.', action: 'onItemSelect' },
- children: {
- description: `A list with message items. If only one item is provided, the initial page will be the details page for the item.\n\n
-**Note:** Although this prop accepts all HTML Elements, it is strongly recommended that you only use \`Message\` in order to preserve the intended design.`,
- control: { disable: true },
- },
- },
args: {
showDetailsPageHeader: true,
groupItems: false,
@@ -76,23 +67,6 @@ const meta = {
Informative message
,
,
- {
- e.stopPropagation();
- }}
- >
- Long Error Message Type without children/details including a Link as `titleText` which has
- wrappingType="None" applied. - The details view is only available if the `titleText` is not fully visible.
- It is NOT recommended to use long titles!
-
- }
- type={ValueState.Negative}
- counter={3}
- />,
],
},
tags: ['package:@ui5/webcomponents-react'],
@@ -270,3 +244,67 @@ export const WithMessageViewButton: Story = {
);
},
};
+
+export const WithLinks: Story = {
+ name: 'with Links',
+ render(args) {
+ const i18nBundle = useI18nBundle('@ui5/webcomponents-react');
+ const listAccessibleDescription = `${i18nBundle.getText({ key: 'LIST_INTERACTIVE_ITEMS', defaultText: 'List with interactive items.' })} ${i18nBundle.getText({ key: 'MOVE_TO_CONTENT_F2', defaultText: 'To move to the content press F2.' })}`;
+
+ return (
+
+ {
+ e.stopPropagation();
+ alert('Link pressed!');
+ }}
+ >
+ Error message
+
+ }
+ subtitleText="This message contains a link"
+ type={ValueState.Negative}
+ />
+ {
+ e.stopPropagation();
+ alert('Link pressed!');
+ }}
+ >
+ Click here to view the error log.
+
+ }
+ type={ValueState.Negative}
+ />
+ {
+ e.stopPropagation();
+ alert('Link pressed!');
+ }}
+ >
+ Long Error Message Type without children/details including a Link as `titleText` which has
+ wrappingType="None" applied. - The details view is only available if the `titleText` is not fully visible.
+ It is NOT recommended to use long titles!
+
+ }
+ type={ValueState.Negative}
+ counter={3}
+ />
+
+
+ );
+ },
+};
diff --git a/packages/main/src/components/MessageView/index.tsx b/packages/main/src/components/MessageView/index.tsx
index bb09fc5838f..ee4e0439387 100644
--- a/packages/main/src/components/MessageView/index.tsx
+++ b/packages/main/src/components/MessageView/index.tsx
@@ -59,6 +59,24 @@ export interface MessageViewPropTypes extends CommonProps {
*/
children: ReactNode | ReactNode[];
+ /**
+ * Defines the accessible description of the `List` (`ui5-list`).
+ *
+ * __Note:__ It is recommended to set this prop when `MessageItem` components contain `Link`s, to inform screen reader users about the interactive content and how to access it (F2 key).
+ *
+ * @since 2.20.0
+ */
+ listAccessibleDescription?: ListPropTypes['accessibleDescription'];
+
+ /**
+ * Defines the IDs of the elements that describe the `List` (`ui5-list`).
+ *
+ * __Note:__ It is recommended to set this prop when `MessageItem` components contain `Link`s, to inform screen reader users about the interactive content and how to access it (F2 key).
+ *
+ * @since 2.20.0
+ */
+ listAccessibleDescriptionRef?: ListPropTypes['accessibleDescriptionRef'];
+
/**
* Event is fired when the details of a message are shown.
*/
@@ -67,7 +85,7 @@ export interface MessageViewPropTypes extends CommonProps {
const withAnimation = getAnimationMode() !== 'none';
-export const resolveMessageTypes = (children: ReactElement[]) => {
+export const resolveMessageTypes = (children: ReactElement[]): Record => {
return (children ?? [])
.map((message) => message?.props?.type)
.reduce(
@@ -83,7 +101,7 @@ export const resolveMessageTypes = (children: ReactElement
[ValueState.Critical]: 0,
[ValueState.Positive]: 0,
[ValueState.Information]: 0,
- },
+ } as Record,
);
};
@@ -111,9 +129,32 @@ export const resolveMessageGroups = (children: ReactElement Warning -> Success -> Information).
+ *
+ * If the `MessageView` is used in a standalone way, you can set the prop `showDetailsPageHeader` to `true`.
+ * This will add a bar to the details page where a back button is contained.
+ *
+ * When used in a `Dialog` or a `Popover`, we recommend not setting the `showDetailsPageHeader` prop but rather listen
+ * to the `onItemSelect` event and add a back button to your Dialog or Popover header and use the `navigateBack()` method
+ * to get back to the list view.
*/
const MessageView = forwardRef((props, ref) => {
- const { children, groupItems, showDetailsPageHeader, className, onItemSelect, ...rest } = props;
+ const {
+ children,
+ groupItems,
+ showDetailsPageHeader,
+ className,
+ onItemSelect,
+ listAccessibleDescriptionRef,
+ listAccessibleDescription,
+ ...rest
+ } = props;
const navBtnRef = useRef(null);
const listRef = useRef(null);
const transitionTrigger = useRef<'btn' | 'list' | null>(null);
@@ -224,8 +265,7 @@ const MessageView = forwardRef((props,
{i18nBundle.getText(ALL)}
- {/* @ts-expect-error: The key can't be typed, it's always `string`, but since the `ValueState` enum only contains strings it's fine to use here*/}
- {Object.entries(messageTypes).map(([valueState, count]: [ValueState, number]) => {
+ {(Object.entries(messageTypes) as [ValueState, number][]).map(([valueState, count]) => {
if (count === 0) {
return null;
}
@@ -252,6 +292,8 @@ const MessageView = forwardRef((props,
onItemClick={handleListItemClick}
noDataText={i18nBundle.getText(LIST_NO_DATA)}
separators={ListSeparator.Inner}
+ accessibleDescriptionRef={listAccessibleDescriptionRef}
+ accessibleDescription={listAccessibleDescription}
>
{groupItems
? groupedMessages.map(([groupName, items]) => {
diff --git a/packages/main/src/i18n/messagebundle.properties b/packages/main/src/i18n/messagebundle.properties
index 39c64c0d918..956ee6d4fd1 100644
--- a/packages/main/src/i18n/messagebundle.properties
+++ b/packages/main/src/i18n/messagebundle.properties
@@ -398,3 +398,9 @@ SELECTED_ITEMS=Selected Items {0}
#XACT: Screen reader announcement for table cell that includes interactive element/s. The placeholder is the name of the element (e.g. "Input").
INCLUDES_X=Includes {0}
+
+#XACT: Screen reader announcement for a list containing interactive elements.
+LIST_INTERACTIVE_ITEMS=List with interactive items.
+
+#XACT: Keyboard navigation instruction for focusing interactive content in a list.
+MOVE_TO_CONTENT_F2=To move to the content press F2.