Skip to content

feat(react-headless-components-preview): add Tooltip component#36079

Open
dmytrokirpa wants to merge 4 commits intomicrosoft:masterfrom
dmytrokirpa:feat/headless-tooltip
Open

feat(react-headless-components-preview): add Tooltip component#36079
dmytrokirpa wants to merge 4 commits intomicrosoft:masterfrom
dmytrokirpa:feat/headless-tooltip

Conversation

@dmytrokirpa
Copy link
Copy Markdown
Contributor

@dmytrokirpa dmytrokirpa commented Apr 30, 2026

This pull request introduces a new headless Tooltip component to the @fluentui/react-headless-components-preview package, providing a non-modal floating label or description anchored to a trigger element. The implementation leverages CSS Anchor Positioning and the Popover API for improved positioning and visibility management. Supporting types, tests, and exports are added, and the package dependencies and exports are updated accordingly.

New Tooltip Component Implementation:

  • Added the Tooltip component and its supporting files (Tooltip.tsx, Tooltip.types.ts, renderTooltip.tsx, useTooltip.ts) to provide a headless tooltip with customizable positioning, visibility, and accessibility relationships. The implementation uses CSS Anchor Positioning and the Popover API for managing placement and visibility. [1] [2] [3] [4]

Testing:

  • Introduced a comprehensive test suite for the Tooltip component, covering rendering, accessibility attributes, positioning, arrow support, and aria-relationship behaviors.

Exports and Package Integration:

  • Exported the new Tooltip component, its types, and related utilities from the package entry points, making it available for consumers. [1] [2]
  • Registered the Tooltip component in the bundle size fixture for testing and documentation purposes.

Dependency and Package Configuration:

  • Added @fluentui/react-tooltip and @fluentui/react-positioning as dependencies in package.json to support the new component, and registered the new entry point for tooltip. [1] [2] [3]

@github-actions
Copy link
Copy Markdown

Pull request demo site: URL

@dmytrokirpa dmytrokirpa force-pushed the feat/headless-tooltip branch 2 times, most recently from 8674624 to 6731cf6 Compare May 1, 2026 14:36
@dmytrokirpa dmytrokirpa force-pushed the feat/headless-tooltip branch from 6731cf6 to 8995a01 Compare May 1, 2026 14:37
@dmytrokirpa dmytrokirpa marked this pull request as ready for review May 1, 2026 14:38
@dmytrokirpa dmytrokirpa requested a review from a team as a code owner May 1, 2026 14:38
@github-actions
Copy link
Copy Markdown

github-actions Bot commented May 1, 2026

📊 Bundle size report

Package & Exports Baseline (minified/GZIP) PR Change
react-headless-components-preview
react-headless-components-preview: entire library
102.351 kB
30.181 kB
105.808 kB
31.294 kB
3.457 kB
1.113 kB
Unchanged fixtures
Package & Exports Size (minified/GZIP)
global-context
createContext
510 B
328 B
global-context
createContextSelector
531 B
335 B
keyboard-key
keyboard-key package
3.746 kB
1.928 kB
keyboard-keys
Multiple keyCodes
50 B
70 B
keyboard-keys
Multiple keys
87 B
94 B
keyboard-keys
Single key
44 B
64 B
keyboard-keys
Single keyCode
39 B
59 B
priority-overflow
createOverflowManager
4.584 kB
1.873 kB
react
ActivityItem
71.22 kB
23.347 kB
react
Announced
38.472 kB
13.275 kB
react
Autofill
15.42 kB
4.766 kB
react
Breadcrumb
200.805 kB
59.601 kB
react
Button
194.354 kB
55.886 kB
react
ButtonGrid
179.242 kB
53.891 kB
react
Calendar
121.162 kB
36.83 kB
react
Callout
84.299 kB
27.593 kB
react
Check
53.206 kB
17.835 kB
react
Checkbox
59.978 kB
19.874 kB
react
ChoiceGroup
65.488 kB
21.465 kB
react
ChoiceGroupOption
58.769 kB
19.353 kB
react
Coachmark
92.7 kB
29.305 kB
react
Color
7.789 kB
3.127 kB
react
ColorPicker
134.97 kB
42.125 kB
react
ComboBox
250.687 kB
71.515 kB
react
CommandBar
201.861 kB
59.387 kB
react
ContextualMenu
154.229 kB
47.566 kB
react
DatePicker
183.251 kB
55.892 kB
react
DateTimeUtilities
5.244 kB
1.849 kB
react
DetailsList
229.929 kB
65.81 kB
react
Dialog
210.16 kB
62.358 kB
react
Divider
19.588 kB
6.84 kB
react
DocumentCard
215.843 kB
63.666 kB
react
DragDrop
8.343 kB
2.724 kB
react
DraggableZone
34.28 kB
11.488 kB
react
Dropdown
233.151 kB
67.962 kB
react
ExtendedPicker
96.823 kB
27.866 kB
react
Fabric
41.728 kB
14.343 kB
react
Facepile
209.377 kB
62.375 kB
react
FloatingPicker
240.865 kB
68.222 kB
react
FocusTrapZone
16.99 kB
5.891 kB
react
FocusZone
55.1 kB
17.451 kB
react
Grid
179.242 kB
53.891 kB
react
GroupedList
135.035 kB
40.67 kB
react
GroupedListV2
122.659 kB
37.758 kB
react
HoverCard
96.784 kB
30.688 kB
react
Icon
51.887 kB
17.263 kB
react
Icons
66.339 kB
24.385 kB
react
Image
46.901 kB
15.695 kB
react
Keytip
81.301 kB
26.677 kB
react
KeytipData
14.05 kB
4.583 kB
react
KeytipLayer
103.089 kB
31.9 kB
react
Keytips
105.873 kB
32.904 kB
react
Label
38.324 kB
13.241 kB
react
Layer
48.089 kB
16.348 kB
react
Link
39.665 kB
13.653 kB
react
List
39.346 kB
12.454 kB
react
MarqueeSelection
74.49 kB
22.402 kB
react
MessageBar
189.388 kB
56.33 kB
react
Modal
93.738 kB
30.223 kB
react
Nav
186.825 kB
55.723 kB
react
OverflowSet
33.354 kB
11.282 kB
react
Overlay
40.885 kB
14.077 kB
react
Panel
200.327 kB
59.336 kB
react
Persona
114.591 kB
36.435 kB
react
PersonaCoin
114.591 kB
36.435 kB
react
PersonaPresence
58.076 kB
19.372 kB
react
Pickers
297.91 kB
82.996 kB
react
Pivot
187.734 kB
56.5 kB
react
Popup
12.312 kB
4.197 kB
react
Positioning
22.764 kB
7.683 kB
react
PositioningContainer
73.445 kB
23.685 kB
react
ProgressIndicator
39.477 kB
13.528 kB
react
Rating
82.086 kB
26.09 kB
react
Fluent UI React (entire library)
1.019 MB
283.183 kB
react
ResizeGroup
13.35 kB
4.379 kB
react
ResponsiveMode
8.13 kB
2.966 kB
react
ScrollablePane
55.541 kB
17.718 kB
react
SearchBox
187.63 kB
55.936 kB
react
SelectableOption
724 B
413 B
react
SelectedItemsList
231.35 kB
67.176 kB
react
Selection
42.418 kB
12.26 kB
react
Separator
35.365 kB
12.132 kB
react
Shimmer
49.249 kB
16.258 kB
react
ShimmeredDetailsList
240.71 kB
68.549 kB
react
Slider
57.627 kB
19.198 kB
react
SpinButton
191.297 kB
57.006 kB
react
Spinner
41.759 kB
14.468 kB
react
Stack
42.039 kB
14.389 kB
react
Sticky
32.577 kB
10.488 kB
react
Styling
46.033 kB
15.135 kB
react
SwatchColorPicker
189.637 kB
57.417 kB
react
TeachingBubble
204.648 kB
60.317 kB
react
Text
36.886 kB
12.806 kB
react
TextField
80.798 kB
25.308 kB
react
Theme
43.486 kB
14.168 kB
react
ThemeGenerator
12.384 kB
4.116 kB
react
TimePicker
240.515 kB
69.311 kB
react
Toggle
46.201 kB
15.957 kB
react
Tooltip
87.073 kB
28.151 kB
react
Utilities
82.938 kB
25.15 kB
react
Viewport
23.872 kB
7.642 kB
react
WeeklyDayPicker
101.348 kB
31.644 kB
react
WindowProvider
1.059 kB
541 B
react-accordion
Accordion (including children components)
92.107 kB
29.097 kB
react-aria
ARIA - useARIAButtonProps
1.354 kB
648 B
react-aria
ARIA - AriaLiveAnnouncer
3.293 kB
1.507 kB
react-avatar
Avatar
48.492 kB
15.379 kB
react-avatar
AvatarGroup
17.468 kB
6.999 kB
react-avatar
AvatarGroupItem
61.513 kB
19.251 kB
react-badge
Badge
24.258 kB
7.881 kB
react-badge
CounterBadge
24.981 kB
8.137 kB
react-badge
PresenceBadge
24.216 kB
8.813 kB
react-breadcrumb
@fluentui/react-breadcrumb - package
103.889 kB
29.167 kB
react-button
Button
33.962 kB
9.022 kB
react-button
CompoundButton
40.843 kB
10.379 kB
react-button
MenuButton
38.866 kB
10.414 kB
react-button
SplitButton
47.663 kB
12.057 kB
react-button
ToggleButton
53.634 kB
11.155 kB
react-calendar-compat
Calendar Compat
138.004 kB
37.657 kB
react-card
Card - All
94.327 kB
27.472 kB
react-card
Card
86.944 kB
25.575 kB
react-card
CardFooter
12.792 kB
5.12 kB
react-card
CardHeader
15.321 kB
5.98 kB
react-card
CardPreview
12.872 kB
5.255 kB
react-charting
AreaChart
302.827 kB
94.751 kB
react-charting
ChartHoverCard
37.196 kB
12.7 kB
react-charting
DeclarativeChart
677.056 kB
191.292 kB
react-charting
DonutChart
203.52 kB
63.663 kB
react-charting
GanttChart
282.797 kB
88.761 kB
react-charting
GaugeChart
197.055 kB
61.221 kB
react-charting
GroupedVerticalBarChart
294.564 kB
91.795 kB
react-charting
HeatMapChart
285.643 kB
89.439 kB
react-charting
HorizontalBarChart
127.266 kB
39.944 kB
react-charting
HorizontalBarChartWithAxis
293.937 kB
91.167 kB
react-charting
Legends
151.485 kB
46.4 kB
react-charting
LineChart
332.438 kB
101.79 kB
react-charting
MultiStackedBarChart
181.754 kB
55.275 kB
react-charting
PieChart
134.305 kB
42.299 kB
react-charting
PolarChart
235.153 kB
74.294 kB
react-charting
SankeyChart
158.002 kB
49.166 kB
react-charting
ScatterChart
289.004 kB
91.071 kB
react-charting
Sparkline
87.616 kB
29.671 kB
react-charting
StackedBarChart
175.435 kB
52.872 kB
react-charting
TreeChart
84.809 kB
26.636 kB
react-charting
VerticalBarChart
303.589 kB
93.173 kB
react-charting
VerticalStackedBarChart
300.594 kB
92.797 kB
react-charts
AreaChart
401.757 kB
125.687 kB
react-charts
DeclarativeChart
752.513 kB
219.844 kB
react-charts
DonutChart
312.17 kB
96.288 kB
react-charts
FunnelChart
303.717 kB
93.118 kB
react-charts
GanttChart
384.858 kB
119.954 kB
react-charts
GaugeChart
311.603 kB
95.74 kB
react-charts
GroupedVerticalBarChart
392.734 kB
122.697 kB
react-charts
HeatMapChart
386.937 kB
121.084 kB
react-charts
HorizontalBarChart
291.9 kB
88.873 kB
react-charts
HorizontalBarChartWithAxis
63 B
83 B
react-charts
Legends
231.437 kB
69.656 kB
react-charts
LineChart
413.091 kB
128.576 kB
react-charts
PolarChart
340.566 kB
106.213 kB
react-charts
SankeyChart
209.97 kB
67.042 kB
react-charts
ScatterChart
392.473 kB
122.669 kB
react-charts
Sparkline
80.503 kB
26.644 kB
react-charts
VerticalBarChart
429.215 kB
127.535 kB
react-charts
VerticalStackedBarChart
398.739 kB
124.078 kB
react-checkbox
Checkbox
30.902 kB
11.007 kB
react-color-picker
ColorArea
44.591 kB
16.204 kB
react-color-picker
ColorPicker
16.157 kB
6.526 kB
react-color-picker
ColorSlider
39.577 kB
14.684 kB
react-combobox
Combobox (including child components)
102.637 kB
33.966 kB
react-combobox
Dropdown (including child components)
102.407 kB
33.704 kB
react-components
react-components: Button, FluentProvider & webLightTheme
67.61 kB
19.536 kB
react-components
react-components: Accordion, Button, FluentProvider, Image, Menu, Popover
226.203 kB
67.961 kB
react-components
react-components: FluentProvider & webLightTheme
40.806 kB
13.616 kB
react-components
react-components: entire library
1.291 MB
323.824 kB
react-datepicker-compat
DatePicker Compat
214.121 kB
62.046 kB
react-dialog
Dialog (including children components)
91.172 kB
28.31 kB
react-divider
Divider
16.354 kB
5.928 kB
react-field
Field
22.411 kB
8.393 kB
react-image
Image
13.626 kB
5.536 kB
react-input
Input
26.298 kB
8.705 kB
react-jsx-runtime
Classic Pragma
1.101 kB
550 B
react-jsx-runtime
JSX Dev Runtime
1.914 kB
908 B
react-jsx-runtime
JSX Runtime
2.268 kB
1.018 kB
react-label
Label
12.972 kB
5.261 kB
react-link
Link
16.191 kB
6.459 kB
react-list
List
75.807 kB
23.523 kB
react-list
ListItem
99.257 kB
30.321 kB
react-menu
Menu (including children components)
159.634 kB
50.691 kB
react-menu
Menu (including selectable components)
162.812 kB
51.329 kB
react-message-bar
MessageBar (all components)
23.418 kB
8.651 kB
react-motion
@fluentui/react-motion - createMotionComponent()
4.156 kB
1.818 kB
react-motion
@fluentui/react-motion - createPresenceComponent()
5.908 kB
2.442 kB
react-motion
@fluentui/react-motion - PresenceGroup
1.727 kB
823 B
react-overflow
hooks only
11.966 kB
4.565 kB
react-persona
Persona
55.447 kB
17.311 kB
react-popover
Popover
123.802 kB
39.735 kB
react-portal
Portal
8.4 kB
3.219 kB
react-portal-compat
PortalCompatProvider
5.567 kB
2.237 kB
react-positioning
usePositioning
28.889 kB
10.158 kB
react-positioning
useSafeZoneArea
12.445 kB
5 kB
react-progress
ProgressBar
20.23 kB
7.866 kB
react-provider
FluentProvider
20.194 kB
7.775 kB
react-radio
Radio
28.289 kB
9.247 kB
react-radio
RadioGroup
14.053 kB
5.703 kB
react-select
Select
26.183 kB
9.474 kB
react-slider
Slider
33.538 kB
11.611 kB
react-spinbutton
SpinButton
33.822 kB
11.128 kB
react-spinner
Spinner
23.721 kB
7.861 kB
react-swatch-picker
@fluentui/react-swatch-picker - package
92.992 kB
27.618 kB
react-switch
Switch
33.533 kB
10.657 kB
react-table
DataGrid
148.07 kB
44.013 kB
react-table
Table (Primitives only)
38.209 kB
12.782 kB
react-table
Table as DataGrid
119.815 kB
33.806 kB
react-table
Table (Selection only)
66.603 kB
19.023 kB
react-table
Table (Sort only)
65.246 kB
18.638 kB
react-tag-picker
@fluentui/react-tag-picker - package
174.502 kB
54.377 kB
react-tags
InteractionTag
13.742 kB
5.473 kB
react-tags
Tag
29.666 kB
9.433 kB
react-tags
TagGroup
71.009 kB
21.901 kB
react-teaching-popover
TeachingPopover
102.196 kB
32.335 kB
react-text
Text - Default
15.313 kB
5.968 kB
react-text
Text - Wrappers
18.473 kB
6.295 kB
react-textarea
Textarea
24.686 kB
8.972 kB
react-theme
Single theme token import
69 B
89 B
react-theme
Teams: all themes
37.985 kB
7.895 kB
react-theme
Teams: Light theme
20.803 kB
5.851 kB
react-timepicker-compat
TimePicker
105.595 kB
35.567 kB
react-toast
Toast (including Toaster)
92.099 kB
28.662 kB
react-tooltip
Tooltip
54.887 kB
19.441 kB
react-tree
FlatTree
136.789 kB
40.787 kB
react-tree
PersonaFlatTree
138.617 kB
41.303 kB
react-tree
PersonaTree
134.677 kB
40.086 kB
react-tree
Tree
132.855 kB
39.62 kB
react-utilities
SSRProvider
180 B
160 B
🤖 This report was generated against 0d337b9ac99223f6de8230629e35b911a72881f1

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds a new headless Tooltip entrypoint to @fluentui/react-headless-components-preview, including component implementation (Popover API + CSS Anchor Positioning via the package’s positioning utilities), Storybook stories/docs, tests, and package/export integration.

Changes:

  • Introduces Tooltip component implementation (useTooltip, renderTooltip, types, exports) plus Jest tests.
  • Adds Storybook stories and markdown documentation for Tooltip usage patterns and accessibility relationships.
  • Wires Tooltip into package exports, API extractor report, bundle-size fixture, dependencies, and beachball change file.

Reviewed changes

Copilot reviewed 20 out of 20 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
packages/react-components/react-headless-components-preview/stories/src/Tooltip/index.stories.tsx Registers Tooltip stories and docs in Storybook.
packages/react-components/react-headless-components-preview/stories/src/Tooltip/TooltipWithArrow.stories.tsx Adds an arrow styling/positioning example story.
packages/react-components/react-headless-components-preview/stories/src/Tooltip/TooltipRelationshipLabel.stories.tsx Demonstrates relationship="label" behavior and docs text.
packages/react-components/react-headless-components-preview/stories/src/Tooltip/TooltipRelationshipDescription.stories.tsx Demonstrates relationship="description" behavior and docs text.
packages/react-components/react-headless-components-preview/stories/src/Tooltip/TooltipPositions.stories.tsx Demonstrates different positioning shorthand values.
packages/react-components/react-headless-components-preview/stories/src/Tooltip/TooltipDescription.md Component description for docs page.
packages/react-components/react-headless-components-preview/stories/src/Tooltip/TooltipDefault.stories.tsx Default Tooltip example (with args passthrough).
packages/react-components/react-headless-components-preview/stories/src/Tooltip/TooltipControlled.stories.tsx Controlled visible example.
packages/react-components/react-headless-components-preview/stories/src/Tooltip/TooltipBestPractices.md Best-practices + accessibility guidance for tooltips.
packages/react-components/react-headless-components-preview/library/src/tooltip.ts Adds the public ./tooltip entrypoint exports.
packages/react-components/react-headless-components-preview/library/src/components/Tooltip/useTooltip.ts Implements Tooltip behavior (visibility, relationships, positioning refs, Popover API sync).
packages/react-components/react-headless-components-preview/library/src/components/Tooltip/renderTooltip.tsx Renders trigger + tooltip content (and optional arrow).
packages/react-components/react-headless-components-preview/library/src/components/Tooltip/index.ts Barrel exports for Tooltip component files.
packages/react-components/react-headless-components-preview/library/src/components/Tooltip/Tooltip.types.ts Public props/state/type surface for headless Tooltip entrypoint.
packages/react-components/react-headless-components-preview/library/src/components/Tooltip/Tooltip.tsx Tooltip component wrapper using hook + render function.
packages/react-components/react-headless-components-preview/library/src/components/Tooltip/Tooltip.test.tsx Adds unit/conformance coverage for tooltip relationships and state attributes.
packages/react-components/react-headless-components-preview/library/package.json Adds deps and registers ./tooltip export path.
packages/react-components/react-headless-components-preview/library/etc/tooltip.api.md API Extractor report for the new tooltip entrypoint.
packages/react-components/react-headless-components-preview/library/bundle-size/AllComponents.fixture.js Includes tooltip entrypoint in bundle-size fixture.
change/@fluentui-react-headless-components-preview-021e6dbb-6618-4217-a7ce-8567198a60ff.json Beachball change file for publishing the addition.

Comment on lines +145 to +147
if (visible) {
el.showPopover();
} else {
Copy link
Copy Markdown
Contributor Author

@dmytrokirpa dmytrokirpa May 3, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

added try/catch with dev warning for unsupported browser

Comment on lines +116 to +117
// stop propagation to avoid conflicting with other elements that listen for `Escape`
// e,g: Dialog, Popover, Menu and Tooltip
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fixed

@dmytrokirpa dmytrokirpa force-pushed the feat/headless-tooltip branch 2 times, most recently from 5ad6afa to a9bb2bf Compare May 2, 2026 07:26
@dmytrokirpa dmytrokirpa requested a review from a team as a code owner May 2, 2026 07:26
@dmytrokirpa dmytrokirpa requested a review from Copilot May 2, 2026 07:28
@dmytrokirpa dmytrokirpa force-pushed the feat/headless-tooltip branch from a9bb2bf to cde85aa Compare May 2, 2026 07:29

// JSDOM does not implement the Popover API yet.
// Provide a minimal test shim so components using showPopover/hidePopover can run in Jest.
if (typeof HTMLElement !== 'undefined') {
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

replaced with polyfill

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is it not enough for testing to have minimal shim? not sure if we need to bring that polyfill dependency only for testing

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it's not enough, as if we want to go with this we need to use the same hacks we have in Popover - like setting popover attribute conditionally in useEffect, etc. So I think it's better to have polyfill in tests and simpler/more robust implementation in the component itself

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 21 out of 22 changed files in this pull request and generated 9 comments.

}),
};

const positioningOptions = resolvePositioningShorthand(positioning);
@dmytrokirpa dmytrokirpa force-pushed the feat/headless-tooltip branch from cde85aa to b1905a2 Compare May 2, 2026 13:36
@dmytrokirpa dmytrokirpa force-pushed the feat/headless-tooltip branch from 526d9d5 to ae3a059 Compare May 3, 2026 06:11
/** Jest test setup file. */

require('@testing-library/jest-dom');
require('@oddbird/popover-polyfill');
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

polyfills JSDOM with Popover API

Comment thread package.json
"swc-loader": "^0.2.6",
"prettier": "2.8.8",
"puppeteer": "19.6.3",
"puppeteer": "24.42.0",
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[email protected] used previous versions of chrome/chromium where Popover API is not available, which causes test-ssr failures

});
page.on('pageerror', pageError => {
error = pageError;
error = pageError as Error;
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

pageError becomes unknown after puppeteer bump

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 24 out of 25 changed files in this pull request and generated 2 comments.

@dmytrokirpa dmytrokirpa requested review from Hotell and mainframev May 4, 2026 10:04

// JSDOM does not implement the Popover API yet.
// Provide a minimal test shim so components using showPopover/hidePopover can run in Jest.
if (typeof HTMLElement !== 'undefined') {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is it not enough for testing to have minimal shim? not sure if we need to bring that polyfill dependency only for testing

import { Tooltip } from './Tooltip';

function queryByRoleTooltip(result: RenderResult) {
const tooltips = result.baseElement.querySelectorAll('*[role="tooltip"]');
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can't we just use screen.queryByRole('tooltip') ?

content: slot.always(content, {
defaultProps: {
role: 'tooltip',
popover: 'manual',
Copy link
Copy Markdown
Contributor

@mainframev mainframev May 4, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

are u sure it should be based on popover='manual'? v9 tooltip allowed only one visible Tooltip at a time (it's know based on context similar to v9, but we could remove that in case of non manual). As previously shared, hint seems as dedicated feature for Popovers, since we already use some API beyond baseline (css anchoring properties) maybe we should consider to use hint instead?

https://developer.chrome.com/blog/popover-hint

Image

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  1. Tooltip doens't have any a11y features other than aria-labels
  2. we already have a context-based logic in v9's tooltips to show only one tooltip at a time
  3. It's not clear at this point that we'll be able to use something beyond Baseline Widely Available. If that would be the case we'll just switch from our custom usePositioning hook to floating-ui based on from react-positioning and that's it.

const contentRef = useMergedRefs(state.content.ref, containerRef);
state.content.ref = contentRef;

// When this tooltip is visible, hide any other tooltips, and register it
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we won't need this and can omit this functionality in case if auto/hint will be used

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The reasoning behind manual is:

  • auto might conflict with menus/popovers/etc
  • hint is outside of browser's support matrix

</Tooltip>,
);

const trigger = result.getByRole('button');
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this can be simplified to:

expect(screen.getByLabelText('Default Tooltip')).toBeInTheDocument();
expect(screen.getByRole('tooltip')).toHaveAttribute('popover', 'manual');

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fixed

Comment on lines +158 to +161
expect(target.hasAttribute('aria-label')).toBe(false);
expect(target.hasAttribute('aria-labelledby')).toBe(false);
expect(target.hasAttribute('aria-description')).toBe(false);
expect(target.hasAttribute('aria-describedby')).toBe(false);
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
expect(target.hasAttribute('aria-label')).toBe(false);
expect(target.hasAttribute('aria-labelledby')).toBe(false);
expect(target.hasAttribute('aria-description')).toBe(false);
expect(target.hasAttribute('aria-describedby')).toBe(false);
expect(target).not.toHaveAttribute('aria-label');
expect(target).not.toHaveAttribute('aria-labelledby');
expect(target).not.toHaveAttribute('aria-description');
expect(target).not.toHaveAttribute('aria-describedby');

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fixed


const target = result.getByRole('button');
expect(target.getAttribute('aria-label')).toBe('test-label');
expect(target.getAttribute('aria-labelledby')).toBe(null);
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
expect(target.getAttribute('aria-labelledby')).toBe(null);
expect(target).not.toHaveAttribute('aria-labelledby');

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fixed

);

const target = result.getByRole('button');
expect(target.getAttribute('aria-description')).toBe(null);
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
expect(target.getAttribute('aria-description')).toBe(null);
expect(target).not.toHaveAttribute('aria-description');

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fixed

@dmytrokirpa dmytrokirpa requested a review from mainframev May 4, 2026 14:13
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants