Skip to content
This repository was archived by the owner on Sep 11, 2024. It is now read-only.

Commit 99ac9e5

Browse files
authored
Ensure tooltip contents is linked via aria to the target element (#10729)
* Ensure tooltip contents is linked via aria to the target element * Iterate * Fix tests * Fix tests * Update snapshot * Fix missing aria labels for more tooltips * Iterate * Update snapshots
1 parent 8e962f6 commit 99ac9e5

File tree

22 files changed

+133
-43
lines changed

22 files changed

+133
-43
lines changed

res/css/views/right_panel/_UserInfo.pcss

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -163,6 +163,8 @@ limitations under the License.
163163
line-height: $font-25px;
164164
flex: 1;
165165
justify-content: center;
166+
// We reverse things here so for accessible technologies the name comes before the e2e shield
167+
flex-direction: row-reverse;
166168

167169
span {
168170
/* limit to 2 lines, show an ellipsis if it overflows */

src/components/structures/auth/forgot-password/CheckEmail.tsx

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ See the License for the specific language governing permissions and
1414
limitations under the License.
1515
*/
1616

17-
import React, { ReactNode } from "react";
17+
import React, { ReactNode, useRef } from "react";
1818

1919
import AccessibleButton from "../../../views/elements/AccessibleButton";
2020
import { Icon as EMailPromptIcon } from "../../../../../res/img/element-icons/email-prompt.svg";
@@ -42,6 +42,7 @@ export const CheckEmail: React.FC<CheckEmailProps> = ({
4242
onSubmitForm,
4343
onResendClick,
4444
}) => {
45+
const tooltipId = useRef(`mx_CheckEmail_${Math.random()}`).current;
4546
const { toggle: toggleTooltipVisible, value: tooltipVisible } = useTimeoutToggle(false, 2500);
4647

4748
const onResendClickFn = async (): Promise<void> => {
@@ -68,10 +69,16 @@ export const CheckEmail: React.FC<CheckEmailProps> = ({
6869
<input onClick={onSubmitForm} type="button" className="mx_Login_submit" value={_t("Next")} />
6970
<div className="mx_AuthBody_did-not-receive">
7071
<span className="mx_VerifyEMailDialog_text-light">{_t("Did not receive it?")}</span>
71-
<AccessibleButton className="mx_AuthBody_resend-button" kind="link" onClick={onResendClickFn}>
72+
<AccessibleButton
73+
className="mx_AuthBody_resend-button"
74+
kind="link"
75+
onClick={onResendClickFn}
76+
aria-describedby={tooltipVisible ? tooltipId : undefined}
77+
>
7278
<RetryIcon className="mx_Icon mx_Icon_16" />
7379
{_t("Resend")}
7480
<Tooltip
81+
id={tooltipId}
7582
label={_t("Verification link email resent!")}
7683
alignment={Alignment.Top}
7784
visible={tooltipVisible}

src/components/structures/auth/forgot-password/VerifyEmailModal.tsx

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ See the License for the specific language governing permissions and
1414
limitations under the License.
1515
*/
1616

17-
import React, { ReactNode } from "react";
17+
import React, { ReactNode, useRef } from "react";
1818

1919
import { _t } from "../../../../languageHandler";
2020
import AccessibleButton from "../../../views/elements/AccessibleButton";
@@ -40,6 +40,7 @@ export const VerifyEmailModal: React.FC<Props> = ({
4040
onReEnterEmailClick,
4141
onResendClick,
4242
}) => {
43+
const tooltipId = useRef(`mx_VerifyEmailModal_${Math.random()}`).current;
4344
const { toggle: toggleTooltipVisible, value: tooltipVisible } = useTimeoutToggle(false, 2500);
4445

4546
const onResendClickFn = async (): Promise<void> => {
@@ -66,10 +67,16 @@ export const VerifyEmailModal: React.FC<Props> = ({
6667

6768
<div className="mx_AuthBody_did-not-receive">
6869
<span className="mx_VerifyEMailDialog_text-light">{_t("Did not receive it?")}</span>
69-
<AccessibleButton className="mx_AuthBody_resend-button" kind="link" onClick={onResendClickFn}>
70+
<AccessibleButton
71+
className="mx_AuthBody_resend-button"
72+
kind="link"
73+
onClick={onResendClickFn}
74+
aria-describedby={tooltipVisible ? tooltipId : undefined}
75+
>
7076
<RetryIcon className="mx_Icon mx_Icon_16" />
7177
{_t("Resend")}
7278
<Tooltip
79+
id={tooltipId}
7380
label={_t("Verification link email resent!")}
7481
alignment={Alignment.Top}
7582
visible={tooltipVisible}

src/components/views/dialogs/UntrustedDeviceDialog.tsx

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -31,8 +31,8 @@ interface IProps {
3131
}
3232

3333
const UntrustedDeviceDialog: React.FC<IProps> = ({ device, user, onFinished }) => {
34-
let askToVerifyText;
35-
let newSessionText;
34+
let askToVerifyText: string;
35+
let newSessionText: string;
3636

3737
if (MatrixClientPeg.get().getUserId() === user.userId) {
3838
newSessionText = _t("You signed in to a new session without verifying it:");
@@ -51,7 +51,7 @@ const UntrustedDeviceDialog: React.FC<IProps> = ({ device, user, onFinished }) =
5151
className="mx_UntrustedDeviceDialog"
5252
title={
5353
<>
54-
<E2EIcon status={E2EState.Warning} size={24} hideTooltip={true} />
54+
<E2EIcon status={E2EState.Warning} isUser size={24} hideTooltip={true} />
5555
{_t("Not Trusted")}
5656
</>
5757
}

src/components/views/elements/LinkWithTooltip.tsx

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,9 @@ import React from "react";
1818

1919
import TextWithTooltip from "./TextWithTooltip";
2020

21-
interface IProps extends Omit<React.ComponentProps<typeof TextWithTooltip>, "tabIndex" | "onClick"> {}
21+
interface IProps extends Omit<React.ComponentProps<typeof TextWithTooltip>, "tabIndex" | "onClick" | "tooltip"> {
22+
tooltip: string;
23+
}
2224

2325
export default class LinkWithTooltip extends React.Component<IProps> {
2426
public constructor(props: IProps) {

src/components/views/elements/Pill.tsx

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ See the License for the specific language governing permissions and
1414
limitations under the License.
1515
*/
1616

17-
import React, { ReactElement, useState } from "react";
17+
import React, { ReactElement, useRef, useState } from "react";
1818
import classNames from "classnames";
1919
import { Room } from "matrix-js-sdk/src/models/room";
2020
import { RoomMember } from "matrix-js-sdk/src/matrix";
@@ -89,6 +89,7 @@ export interface PillProps {
8989
}
9090

9191
export const Pill: React.FC<PillProps> = ({ type: propType, url, inMessage, room, shouldShowPillAvatar = true }) => {
92+
const tooltipId = useRef(`mx_Pill_${Math.random()}`).current;
9293
const [hover, setHover] = useState(false);
9394
const { event, member, onClick, resourceId, targetRoom, text, type } = usePermalink({
9495
room,
@@ -117,7 +118,7 @@ export const Pill: React.FC<PillProps> = ({ type: propType, url, inMessage, room
117118
setHover(false);
118119
};
119120

120-
const tip = hover && resourceId ? <Tooltip label={resourceId} alignment={Alignment.Right} /> : null;
121+
const tip = hover && resourceId ? <Tooltip id={tooltipId} label={resourceId} alignment={Alignment.Right} /> : null;
121122
let avatar: ReactElement | null = null;
122123
let pillText: string | null = text;
123124

@@ -165,13 +166,19 @@ export const Pill: React.FC<PillProps> = ({ type: propType, url, inMessage, room
165166
onClick={onClick}
166167
onMouseOver={onMouseOver}
167168
onMouseLeave={onMouseLeave}
169+
aria-describedby={tooltipId}
168170
>
169171
{avatar}
170172
<span className="mx_Pill_text">{pillText}</span>
171173
{tip}
172174
</a>
173175
) : (
174-
<span className={classes} onMouseOver={onMouseOver} onMouseLeave={onMouseLeave}>
176+
<span
177+
className={classes}
178+
onMouseOver={onMouseOver}
179+
onMouseLeave={onMouseLeave}
180+
aria-describedby={tooltipId}
181+
>
175182
{avatar}
176183
<span className="mx_Pill_text">{pillText}</span>
177184
{tip}

src/components/views/elements/TextWithTooltip.tsx

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,10 @@ export default class TextWithTooltip extends React.Component<IProps> {
3535
public render(): React.ReactNode {
3636
const { class: className, children, tooltip, tooltipClass, tooltipProps, ...props } = this.props;
3737

38+
if (typeof tooltip === "string") {
39+
props["aria-label"] = tooltip;
40+
}
41+
3842
return (
3943
<TooltipTarget
4044
onClick={this.props.onClick}

src/components/views/elements/Tooltip.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -188,7 +188,7 @@ export default class Tooltip extends React.PureComponent<ITooltipProps, State> {
188188
style.display = this.props.visible ? "block" : "none";
189189

190190
const tooltip = (
191-
<div role={this.props.role || "tooltip"} className={tooltipClasses} style={style}>
191+
<div id={this.props.id} role={this.props.role || "tooltip"} className={tooltipClasses} style={style}>
192192
<div className="mx_Tooltip_chevron" />
193193
{this.props.label}
194194
</div>

src/components/views/messages/ReactionsRowButton.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -92,7 +92,7 @@ export default class ReactionsRowButton extends React.PureComponent<IProps, ISta
9292
mx_ReactionsRowButton_selected: !!myReactionEvent,
9393
});
9494

95-
let tooltip;
95+
let tooltip: JSX.Element | undefined;
9696
if (this.state.tooltipRendered) {
9797
tooltip = (
9898
<ReactionsRowButtonTooltip

src/components/views/messages/ReactionsRowButtonTooltip.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ export default class ReactionsRowButtonTooltip extends React.PureComponent<IProp
4040
const { content, reactionEvents, mxEvent, visible } = this.props;
4141

4242
const room = this.context.getRoom(mxEvent.getRoomId());
43-
let tooltipLabel;
43+
let tooltipLabel: JSX.Element | undefined;
4444
if (room) {
4545
const senders: string[] = [];
4646
for (const reactionEvent of reactionEvents) {
@@ -72,7 +72,7 @@ export default class ReactionsRowButtonTooltip extends React.PureComponent<IProp
7272
);
7373
}
7474

75-
let tooltip;
75+
let tooltip: JSX.Element | undefined;
7676
if (tooltipLabel) {
7777
tooltip = <Tooltip visible={visible} label={tooltipLabel} />;
7878
}

0 commit comments

Comments
 (0)