@samitouri / QOS-React / commits / 67415c8c4a

[DevTools] Stop using native `title` for buttons/icons (#34379)

Sebastian "Sebbie" Silbermann committed Sep 11, 2025 at 18:49 UTC 67415c8c4a3380ec96f710bbffc3d215076360f0
10 files changed +43 -47
packages/react-devtools-shared/src/devtools/views/Components/Badge.js
+11 -2
@@ -14,8 +14,17 @@ import styles from './Badge.css';
14 type Props = {
15 className?: string,
16 children: React$Node,
17 + ...
18 };
19
19 -export default function Badge({className = '', children}: Props): React.Node {
20 - return <div className={`${styles.Badge} ${className}`}>{children}</div>;
20 +export default function Badge({
21 + className = '',
22 + children,
23 + ...props
24 +}: Props): React.Node {
25 + return (
26 + <div {...props} className={`${styles.Badge} ${className}`}>
27 + {children}
28 + </div>
29 + );
30 }
packages/react-devtools-shared/src/devtools/views/Components/Element.js
+11 -9
@@ -24,6 +24,7 @@ import type {Element as ElementType} from 'react-devtools-shared/src/frontend/ty
24 import styles from './Element.css';
25 import Icon from '../Icon';
26 import {useChangeOwnerAction} from './OwnersListContext';
27 +import Tooltip from './reach-ui/tooltip';
28
29 type Props = {
30 data: ItemData,
@@ -231,15 +232,16 @@ export default function Element({data, index, style}: Props): React.Node {
232 />
233 )}
234 {showStrictModeBadge && (
234 - <Icon
235 - className={
236 - isSelected && treeFocused
237 - ? styles.StrictModeContrast
238 - : styles.StrictMode
239 - }
240 - title="This component is not running in StrictMode."
241 - type="strict-mode-non-compliant"
242 - />
235 + <Tooltip label="This component is not running in StrictMode.">
236 + <Icon
237 + className={
238 + isSelected && treeFocused
239 + ? styles.StrictModeContrast
240 + : styles.StrictMode
241 + }
242 + type="strict-mode-non-compliant"
243 + />
244 + </Tooltip>
245 )}
246 </div>
247 </div>
packages/react-devtools-shared/src/devtools/views/Components/ForgetBadge.css
-8
@@ -11,11 +11,3 @@
11 position: absolute;
12 right: 0.25em;
13 }
14 -
15 -.ForgetToggle {
16 - display: flex;
17 -}
18 -
19 -.ForgetToggle > span { /* targets .ToggleContent */
20 - padding: 0;
21 -}
packages/react-devtools-shared/src/devtools/views/Components/ForgetBadge.js
+3 -4
@@ -11,7 +11,7 @@ import * as React from 'react';
11
12 import Badge from './Badge';
13 import IndexableDisplayName from './IndexableDisplayName';
14 -import Toggle from '../Toggle';
14 +import Tooltip from './reach-ui/tooltip';
15
16 import styles from './ForgetBadge.css';
17
@@ -40,12 +40,11 @@ export default function ForgetBadge(props: Props): React.Node {
40 'Memo'
41 );
42
43 - const onChange = () => {};
43 const title =
44 '✨ This component has been auto-memoized by the React Compiler.';
45 return (
47 - <Toggle onChange={onChange} className={styles.ForgetToggle} title={title}>
46 + <Tooltip label={title}>
47 <Badge className={`${styles.Root} ${className}`}>{innerView}</Badge>
49 - </Toggle>
48 + </Tooltip>
49 );
50 }
packages/react-devtools-shared/src/devtools/views/Components/InspectedElement.js
+10 -8
@@ -29,6 +29,7 @@ import InspectedElementViewSourceButton from './InspectedElementViewSourceButton
29 import useEditorURL from '../useEditorURL';
30
31 import styles from './InspectedElement.css';
32 +import Tooltip from './reach-ui/tooltip';
33
34 export type Props = {};
35
@@ -192,14 +193,15 @@ export default function InspectedElementWrapper(_: Props): React.Node {
193 let strictModeBadge = null;
194 if (element.isStrictModeNonCompliant) {
195 strictModeBadge = (
195 - <a
196 - className={styles.StrictModeNonCompliant}
197 - href="https://react.dev/reference/react/StrictMode"
198 - rel="noopener noreferrer"
199 - target="_blank"
200 - title="This component is not running in StrictMode. Click to learn more.">
201 - <Icon type="strict-mode-non-compliant" />
202 - </a>
196 + <Tooltip label="This component is not running in StrictMode. Click to learn more.">
197 + <a
198 + className={styles.StrictModeNonCompliant}
199 + href="https://react.dev/reference/react/StrictMode"
200 + rel="noopener noreferrer"
201 + target="_blank">
202 + <Icon type="strict-mode-non-compliant" />
203 + </a>
204 + </Tooltip>
205 );
206 }
207
packages/react-devtools-shared/src/devtools/views/Components/NativeTagBadge.css
-8
@@ -1,11 +1,3 @@
1 -.Toggle {
2 - display: flex;
3 -}
4 -
5 -.Toggle > span { /* targets .ToggleContent */
6 - padding: 0;
7 -}
8 -
1 .Badge {
2 cursor: help;
3 }
packages/react-devtools-shared/src/devtools/views/Components/NativeTagBadge.js
+3 -4
@@ -10,7 +10,7 @@
10 import * as React from 'react';
11
12 import Badge from './Badge';
13 -import Toggle from '../Toggle';
13 +import Tooltip from './reach-ui/tooltip';
14
15 import styles from './NativeTagBadge.css';
16
@@ -18,14 +18,13 @@ type Props = {
18 nativeTag: number,
19 };
20
21 -const noop = () => {};
21 const title =
22 'Unique identifier for the corresponding native component. React Native only.';
23
24 export default function NativeTagBadge({nativeTag}: Props): React.Node {
25 return (
27 - <Toggle onChange={noop} className={styles.Toggle} title={title}>
26 + <Tooltip label={title}>
27 <Badge className={styles.Badge}>Tag {nativeTag}</Badge>
29 - </Toggle>
28 + </Tooltip>
29 );
30 }
packages/react-devtools-shared/src/devtools/views/ErrorBoundary/ReportNewIssue.js
+1 -2
@@ -63,8 +63,7 @@ export default function ReportNewIssue({
63 className={styles.ReportLink}
64 href={bugURL}
65 rel="noopener noreferrer"
66 - target="_blank"
67 - title="Report bug">
66 + target="_blank">
67 Report this issue
68 </a>
69 <div className={styles.ReproSteps}>
packages/react-devtools-shared/src/devtools/views/ErrorBoundary/WorkplaceGroup.js
+1 -2
@@ -25,8 +25,7 @@ export default function WorkplaceGroup(): React.Node {
25 className={styles.ReportLink}
26 href={REACT_DEVTOOLS_WORKPLACE_URL}
27 rel="noopener noreferrer"
28 - target="_blank"
29 - title="Report bug">
28 + target="_blank">
29 Report this on Workplace
30 </a>
31 <div className={styles.FacebookOnly}>(Facebook employees only.)</div>
packages/react-devtools-shared/src/devtools/views/Icon.js
+3
@@ -33,12 +33,14 @@ type Props = {
33 className?: string,
34 title?: string,
35 type: IconType,
36 + ...
37 };
38
39 export default function Icon({
40 className = '',
41 title = '',
42 type,
43 + ...props
44 }: Props): React.Node {
45 let pathData = null;
46 let viewBox = '0 0 24 24';
@@ -102,6 +104,7 @@ export default function Icon({
104
105 return (
106 <svg
107 + {...props}
108 xmlns="http://www.w3.org/2000/svg"
109 className={`${styles.Icon} ${className}`}
110 width="24"