[ObsUX] [A11y] Fix focus on metadata table content (#216628)

Closes https://github.com/elastic/kibana/issues/195014

### Summary

Host Detail page has a Metadata tab with expandable table rows. These
rows add content to the page in an unexpected reading order. Content
should be expanded underneath the show more / less trigger. Focus should
stay on the toggle.

Before


https://github.com/user-attachments/assets/13a0f7a2-2f24-4304-a6ad-cc46e3bbfc1c

After


https://github.com/user-attachments/assets/7993abdc-b693-4c0f-a161-8533cf6b2e3b
This commit is contained in:
Miriam 2025-04-02 10:25:05 +01:00 committed by GitHub
parent 420512a53a
commit 7b1d7bf08a
No known key found for this signature in database
GPG key ID: B5690EEEBB952194

View file

@ -8,7 +8,7 @@
import { EuiFlexGroup, EuiFlexItem, EuiLink, EuiToolTip } from '@elastic/eui';
import { i18n } from '@kbn/i18n';
import React from 'react';
import React, { useEffect, useRef } from 'react';
import { FormattedMessage } from '@kbn/i18n-react';
import useToggle from 'react-use/lib/useToggle';
import type { Field } from '../tabs/metadata/utils';
@ -19,24 +19,39 @@ interface ExpandableContentProps {
export const ExpandableContent = (props: ExpandableContentProps) => {
const { values } = props;
const [isExpanded, toggle] = useToggle(false);
const showLessRef = useRef<HTMLAnchorElement | null>(null);
const showMoreRef = useRef<HTMLAnchorElement | null>(null);
const list = Array.isArray(values) ? values : [values];
const [first, ...others] = list;
const hasOthers = others.length > 0;
const shouldShowMore = hasOthers && !isExpanded;
const hasInteracted = useRef(false);
const handleToggle = () => {
hasInteracted.current = true;
toggle();
};
useEffect(() => {
if (!hasInteracted.current) return;
if (isExpanded) {
showLessRef.current?.focus();
} else {
showMoreRef.current?.focus();
}
}, [isExpanded]);
return (
<EuiFlexGroup gutterSize="xs" responsive={false} alignItems="baseline" wrap direction="column">
<EuiFlexItem className="eui-textTruncate">
<EuiToolTip delay="long" content={first}>
<p className="eui-textTruncate">{first}</p>
</EuiToolTip>
{shouldShowMore && (
<>
{' ... '}
<EuiLink
data-test-subj="infraAssetDetailsExpandableContentCountMoreLink"
onClick={toggle}
onClick={handleToggle}
ref={showMoreRef}
>
<FormattedMessage
id="xpack.infra.assetDetails.tabs.metadata.seeMore"
@ -48,17 +63,24 @@ export const ExpandableContent = (props: ExpandableContentProps) => {
</EuiLink>
</>
)}
{hasOthers && isExpanded && (
<EuiFlexItem>
<EuiLink
data-test-subj="infraExpandableContentShowLessLink"
onClick={handleToggle}
ref={showLessRef}
>
{i18n.translate('xpack.infra.assetDetails.tabs.metadata.seeLess', {
defaultMessage: 'Show less',
})}
</EuiLink>
</EuiFlexItem>
)}
<EuiToolTip delay="long" content={first}>
<p className="eui-textTruncate">{first}</p>
</EuiToolTip>
</EuiFlexItem>
{isExpanded && others.map((item, index) => <EuiFlexItem key={index}>{item}</EuiFlexItem>)}
{hasOthers && isExpanded && (
<EuiFlexItem>
<EuiLink data-test-subj="infraExpandableContentShowLessLink" onClick={toggle}>
{i18n.translate('xpack.infra.assetDetails.tabs.metadata.seeLess', {
defaultMessage: 'Show less',
})}
</EuiLink>
</EuiFlexItem>
)}
</EuiFlexGroup>
);
};