@ui-sdk/web 0.0.0-stage → 0.1.0-beta.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +202 -0
- package/README.md +10 -2
- package/browser/web/accordion.js +1 -0
- package/browser/web/alert-dialog.js +1 -0
- package/browser/web/autocomplete.js +1 -0
- package/browser/web/avatar.js +1 -0
- package/browser/web/button.js +1 -0
- package/browser/web/calendar.js +1 -0
- package/browser/web/carousel.js +1 -0
- package/browser/web/checkbox.js +1 -0
- package/browser/web/chunks/0eRGibL6.js +1 -0
- package/browser/web/chunks/2bIEUO6_.js +1 -0
- package/browser/web/chunks/5A9w2ULz.js +1 -0
- package/browser/web/chunks/5RSyydjV.js +1 -0
- package/browser/web/chunks/9pWTy2wl.js +1 -0
- package/browser/web/chunks/B0f2j6zz.js +1 -0
- package/browser/web/chunks/B1rux6br.js +1 -0
- package/browser/web/chunks/B3-APaNf.js +1 -0
- package/browser/web/chunks/B7EgSgjQ.js +1 -0
- package/browser/web/chunks/B8QcOzJU.js +1 -0
- package/browser/web/chunks/BFueEkwm.js +3 -0
- package/browser/web/chunks/BJj3oS29.js +1 -0
- package/browser/web/chunks/BNSvTCpr.js +1 -0
- package/browser/web/chunks/BPD0kAZB.js +1 -0
- package/browser/web/chunks/BQeduZqT.js +1 -0
- package/browser/web/chunks/B_CVFyiz.js +1 -0
- package/browser/web/chunks/B_ns1YHO.js +1 -0
- package/browser/web/chunks/BcwkVTsR.js +1 -0
- package/browser/web/chunks/BeaQ6TYM.js +1 -0
- package/browser/web/chunks/BgBB013u.js +1 -0
- package/browser/web/chunks/BgsKhHDm.js +1 -0
- package/browser/web/chunks/BjMcbuhi.js +9 -0
- package/browser/web/chunks/Bjiy_F2N.js +1 -0
- package/browser/web/chunks/BqScCLwv.js +1 -0
- package/browser/web/chunks/BqX3Utqx.js +1 -0
- package/browser/web/chunks/BtVkQf3z.js +1 -0
- package/browser/web/chunks/By30h-7B.js +1 -0
- package/browser/web/chunks/C1zqYpy2.js +1 -0
- package/browser/web/chunks/C436juFf.js +1 -0
- package/browser/web/chunks/C4_bULs1.js +1 -0
- package/browser/web/chunks/C4omqJEz.js +1 -0
- package/browser/web/chunks/C7tt0T3n.js +1 -0
- package/browser/web/chunks/C8w7s5dg.js +1 -0
- package/browser/web/chunks/CElY4erO.js +1 -0
- package/browser/web/chunks/CFODo-m2.js +1 -0
- package/browser/web/chunks/CL4wjam9.js +1 -0
- package/browser/web/chunks/CMg-8UVf.js +1 -0
- package/browser/web/chunks/COWKfakj.js +1 -0
- package/browser/web/chunks/CQBU0qZ4.js +1 -0
- package/browser/web/chunks/CV6uABgc.js +1 -0
- package/browser/web/chunks/C_SWFpWQ.js +1 -0
- package/browser/web/chunks/C_Uanbrl.js +1 -0
- package/browser/web/chunks/Ce_CSanC.js +1 -0
- package/browser/web/chunks/Cg-ZmRhS.js +1 -0
- package/browser/web/chunks/Cgf2wPI_.js +1 -0
- package/browser/web/chunks/Cuep_3Vf.js +1 -0
- package/browser/web/chunks/D02PaHn6.js +1 -0
- package/browser/web/chunks/D5LiaI5R.js +1 -0
- package/browser/web/chunks/D9UgVYvF.js +1 -0
- package/browser/web/chunks/DC08tnkE.js +2 -0
- package/browser/web/chunks/DG8YGSvu.js +1 -0
- package/browser/web/chunks/DIQd0FYD.js +1 -0
- package/browser/web/chunks/DMLqacE8.js +1 -0
- package/browser/web/chunks/DSUI3yI-.js +1 -0
- package/browser/web/chunks/DT3Hb76X.js +1 -0
- package/browser/web/chunks/DY75g3-W.js +1 -0
- package/browser/web/chunks/DZpNQKZ9.js +1 -0
- package/browser/web/chunks/Db-W1wrC.js +1 -0
- package/browser/web/chunks/Dc1xK3Ii.js +1 -0
- package/browser/web/chunks/DdF6awFs.js +1 -0
- package/browser/web/chunks/DdaCLml8.js +1 -0
- package/browser/web/chunks/Dh8MLjQO.js +1 -0
- package/browser/web/chunks/DiuslJRy.js +1 -0
- package/browser/web/chunks/DjRcw3Y0.js +1 -0
- package/browser/web/chunks/Djdv-16J.js +1 -0
- package/browser/web/chunks/DnFXe_lF.js +1 -0
- package/browser/web/chunks/DneGv1oC.js +1 -0
- package/browser/web/chunks/DsVxP-p-.js +1 -0
- package/browser/web/chunks/DwDilCo2.js +1 -0
- package/browser/web/chunks/DwV48AXv.js +1 -0
- package/browser/web/chunks/F37aF4-L.js +1 -0
- package/browser/web/chunks/LyB6XIbN.js +1 -0
- package/browser/web/chunks/NKnbYGjC.js +1 -0
- package/browser/web/chunks/Vk-rVi16.js +1 -0
- package/browser/web/chunks/XsM0J1Ex.js +1 -0
- package/browser/web/chunks/asSN9iEp.js +1 -0
- package/browser/web/chunks/c-AjHfdF.js +1 -0
- package/browser/web/chunks/dR-12TPY.js +1 -0
- package/browser/web/chunks/hR4xM0EC.js +1 -0
- package/browser/web/chunks/hqOaBxAg.js +1 -0
- package/browser/web/chunks/kMKqqeG4.js +1 -0
- package/browser/web/chunks/kXboBcfi.js +1 -0
- package/browser/web/chunks/l4aQIg22.js +1 -0
- package/browser/web/chunks/tJC0JSU4.js +1 -0
- package/browser/web/chunks/wHdS_QYM.js +1 -0
- package/browser/web/chunks/yv8dTvNI.js +1 -0
- package/browser/web/chunks/yw9M3nfi.js +1 -0
- package/browser/web/collapsible.js +1 -0
- package/browser/web/color-picker.js +1 -0
- package/browser/web/combobox.js +2 -0
- package/browser/web/command.js +1 -0
- package/browser/web/core.js +5 -0
- package/browser/web/date-input.js +1 -0
- package/browser/web/date-picker.js +1 -0
- package/browser/web/dialog.js +1 -0
- package/browser/web/drawer.js +1 -0
- package/browser/web/field.js +1 -0
- package/browser/web/file-input.js +1 -0
- package/browser/web/hover-card.js +1 -0
- package/browser/web/image-cropper.js +1 -0
- package/browser/web/input.js +1 -0
- package/browser/web/label.js +1 -0
- package/browser/web/listbox.js +1 -0
- package/browser/web/menu.js +1 -0
- package/browser/web/menubar.js +1 -0
- package/browser/web/meter.js +1 -0
- package/browser/web/navigation-menu.js +1 -0
- package/browser/web/number-input.js +1 -0
- package/browser/web/otp-input.js +2 -0
- package/browser/web/overlays.js +1 -0
- package/browser/web/pagination.js +1 -0
- package/browser/web/password-input.js +1 -0
- package/browser/web/popover.js +1 -0
- package/browser/web/preferences.js +1 -0
- package/browser/web/progress.js +1 -0
- package/browser/web/radio.js +1 -0
- package/browser/web/rating.js +1 -0
- package/browser/web/resizable.js +1 -0
- package/browser/web/scroll-area.js +1 -0
- package/browser/web/segmented-control.js +1 -0
- package/browser/web/select.js +1 -0
- package/browser/web/separator.js +1 -0
- package/browser/web/slider.js +1 -0
- package/browser/web/switch.js +1 -0
- package/browser/web/tabs.js +1 -0
- package/browser/web/textarea.js +1 -0
- package/browser/web/time-input.js +1 -0
- package/browser/web/timeline.js +1 -0
- package/browser/web/toast.js +1 -0
- package/browser/web/toggle.js +1 -0
- package/browser/web/token-input.js +8 -0
- package/browser/web/toolbar.js +1 -0
- package/browser/web/tooltip.js +1 -0
- package/browser/web/tree.js +1 -0
- package/browser/web/trigger-menu.js +4 -0
- package/browser/web/waterfall.js +1 -0
- package/browser/web.css +3378 -0
- package/browser/web.js +3 -0
- package/custom-elements.json +32315 -0
- package/dist/accordion.d.ts +2 -0
- package/dist/accordion.js +57 -0
- package/dist/action.d.ts +16 -0
- package/dist/action.js +39 -0
- package/dist/agent.d.ts +2 -0
- package/dist/agent.js +7 -0
- package/dist/autocomplete.d.ts +2 -0
- package/dist/autocomplete.js +120 -0
- package/dist/autoload.d.ts +18 -0
- package/dist/autoload.js +63 -0
- package/dist/avatar.d.ts +2 -0
- package/dist/avatar.js +27 -0
- package/dist/browser-core.d.ts +2 -0
- package/dist/browser-core.js +8 -0
- package/dist/button.d.ts +2 -0
- package/dist/button.js +35 -0
- package/dist/calendar.d.ts +23 -0
- package/dist/calendar.js +429 -0
- package/dist/carousel.d.ts +2 -0
- package/dist/carousel.js +54 -0
- package/dist/checkbox.d.ts +4 -0
- package/dist/checkbox.js +75 -0
- package/dist/collapsible.d.ts +2 -0
- package/dist/collapsible.js +28 -0
- package/dist/color-picker.d.ts +2 -0
- package/dist/color-picker.js +64 -0
- package/dist/combobox.d.ts +2 -0
- package/dist/combobox.js +334 -0
- package/dist/command.d.ts +2 -0
- package/dist/command.js +122 -0
- package/dist/date-input.d.ts +3 -0
- package/dist/date-input.js +87 -0
- package/dist/date-picker.d.ts +2 -0
- package/dist/date-picker.js +174 -0
- package/dist/default-text.d.ts +3 -0
- package/dist/default-text.js +24 -0
- package/dist/define-element.d.ts +404 -0
- package/dist/define-element.js +1489 -0
- package/dist/dialog.d.ts +3 -0
- package/dist/dialog.js +94 -0
- package/dist/drawer.d.ts +2 -0
- package/dist/drawer.js +96 -0
- package/dist/entries/accordion.d.ts +3 -0
- package/dist/entries/accordion.js +7 -0
- package/dist/entries/alert-dialog.d.ts +3 -0
- package/dist/entries/alert-dialog.js +13 -0
- package/dist/entries/autocomplete.d.ts +3 -0
- package/dist/entries/autocomplete.js +7 -0
- package/dist/entries/avatar.d.ts +2 -0
- package/dist/entries/avatar.js +3 -0
- package/dist/entries/button.d.ts +2 -0
- package/dist/entries/button.js +3 -0
- package/dist/entries/calendar.d.ts +3 -0
- package/dist/entries/calendar.js +7 -0
- package/dist/entries/carousel.d.ts +3 -0
- package/dist/entries/carousel.js +7 -0
- package/dist/entries/checkbox.d.ts +3 -0
- package/dist/entries/checkbox.js +15 -0
- package/dist/entries/collapsible.d.ts +3 -0
- package/dist/entries/collapsible.js +7 -0
- package/dist/entries/color-picker.d.ts +3 -0
- package/dist/entries/color-picker.js +7 -0
- package/dist/entries/combobox.d.ts +3 -0
- package/dist/entries/combobox.js +7 -0
- package/dist/entries/command.d.ts +3 -0
- package/dist/entries/command.js +7 -0
- package/dist/entries/date-input.d.ts +3 -0
- package/dist/entries/date-input.js +7 -0
- package/dist/entries/date-picker.d.ts +3 -0
- package/dist/entries/date-picker.js +7 -0
- package/dist/entries/dialog.d.ts +3 -0
- package/dist/entries/dialog.js +7 -0
- package/dist/entries/drawer.d.ts +3 -0
- package/dist/entries/drawer.js +8 -0
- package/dist/entries/field.d.ts +2 -0
- package/dist/entries/field.js +3 -0
- package/dist/entries/file-input.d.ts +3 -0
- package/dist/entries/file-input.js +13 -0
- package/dist/entries/hover-card.d.ts +3 -0
- package/dist/entries/hover-card.js +7 -0
- package/dist/entries/image-cropper.d.ts +3 -0
- package/dist/entries/image-cropper.js +7 -0
- package/dist/entries/input.d.ts +3 -0
- package/dist/entries/input.js +8 -0
- package/dist/entries/label.d.ts +2 -0
- package/dist/entries/label.js +3 -0
- package/dist/entries/listbox.d.ts +3 -0
- package/dist/entries/listbox.js +7 -0
- package/dist/entries/menu.d.ts +3 -0
- package/dist/entries/menu.js +7 -0
- package/dist/entries/menubar.d.ts +3 -0
- package/dist/entries/menubar.js +7 -0
- package/dist/entries/meter.d.ts +2 -0
- package/dist/entries/meter.js +3 -0
- package/dist/entries/navigation-menu.d.ts +3 -0
- package/dist/entries/navigation-menu.js +7 -0
- package/dist/entries/number-input.d.ts +3 -0
- package/dist/entries/number-input.js +7 -0
- package/dist/entries/otp-input.d.ts +3 -0
- package/dist/entries/otp-input.js +7 -0
- package/dist/entries/overlays.d.ts +2 -0
- package/dist/entries/overlays.js +3 -0
- package/dist/entries/pagination.d.ts +3 -0
- package/dist/entries/pagination.js +11 -0
- package/dist/entries/password-input.d.ts +3 -0
- package/dist/entries/password-input.js +7 -0
- package/dist/entries/popover.d.ts +3 -0
- package/dist/entries/popover.js +7 -0
- package/dist/entries/preferences.d.ts +3 -0
- package/dist/entries/preferences.js +13 -0
- package/dist/entries/progress.d.ts +2 -0
- package/dist/entries/progress.js +3 -0
- package/dist/entries/radio.d.ts +3 -0
- package/dist/entries/radio.js +7 -0
- package/dist/entries/rating.d.ts +3 -0
- package/dist/entries/rating.js +8 -0
- package/dist/entries/resizable.d.ts +3 -0
- package/dist/entries/resizable.js +11 -0
- package/dist/entries/scroll-area.d.ts +3 -0
- package/dist/entries/scroll-area.js +7 -0
- package/dist/entries/segmented-control.d.ts +3 -0
- package/dist/entries/segmented-control.js +7 -0
- package/dist/entries/select.d.ts +3 -0
- package/dist/entries/select.js +7 -0
- package/dist/entries/separator.d.ts +2 -0
- package/dist/entries/separator.js +3 -0
- package/dist/entries/slider.d.ts +3 -0
- package/dist/entries/slider.js +7 -0
- package/dist/entries/switch.d.ts +3 -0
- package/dist/entries/switch.js +7 -0
- package/dist/entries/tabs.d.ts +3 -0
- package/dist/entries/tabs.js +7 -0
- package/dist/entries/textarea.d.ts +3 -0
- package/dist/entries/textarea.js +7 -0
- package/dist/entries/time-input.d.ts +3 -0
- package/dist/entries/time-input.js +7 -0
- package/dist/entries/timeline.d.ts +3 -0
- package/dist/entries/timeline.js +7 -0
- package/dist/entries/toast.d.ts +2 -0
- package/dist/entries/toast.js +3 -0
- package/dist/entries/toggle.d.ts +3 -0
- package/dist/entries/toggle.js +12 -0
- package/dist/entries/token-input.d.ts +3 -0
- package/dist/entries/token-input.js +17 -0
- package/dist/entries/toolbar.d.ts +3 -0
- package/dist/entries/toolbar.js +7 -0
- package/dist/entries/tooltip.d.ts +3 -0
- package/dist/entries/tooltip.js +7 -0
- package/dist/entries/tree.d.ts +3 -0
- package/dist/entries/tree.js +17 -0
- package/dist/entries/trigger-menu.d.ts +3 -0
- package/dist/entries/trigger-menu.js +11 -0
- package/dist/entries/waterfall.d.ts +3 -0
- package/dist/entries/waterfall.js +11 -0
- package/dist/events.d.ts +1658 -0
- package/dist/events.js +0 -0
- package/dist/field.d.ts +2 -0
- package/dist/field.js +101 -0
- package/dist/file-input.d.ts +2 -0
- package/dist/file-input.js +140 -0
- package/dist/forward-attributes.d.ts +2 -0
- package/dist/forward-attributes.js +22 -0
- package/dist/history.d.ts +2 -0
- package/dist/history.js +11 -0
- package/dist/hover-card.d.ts +2 -0
- package/dist/hover-card.js +31 -0
- package/dist/image-cropper.d.ts +2 -0
- package/dist/image-cropper.js +66 -0
- package/dist/index.d.ts +66 -0
- package/dist/index.js +269 -0
- package/dist/input.d.ts +3 -0
- package/dist/input.js +69 -0
- package/dist/label.d.ts +2 -0
- package/dist/label.js +11 -0
- package/dist/list.d.ts +40 -0
- package/dist/list.js +192 -0
- package/dist/listbox.d.ts +2 -0
- package/dist/listbox.js +84 -0
- package/dist/menu.d.ts +4 -0
- package/dist/menu.js +295 -0
- package/dist/menubar.d.ts +4 -0
- package/dist/menubar.js +30 -0
- package/dist/meter.d.ts +2 -0
- package/dist/meter.js +22 -0
- package/dist/navigation-menu.d.ts +2 -0
- package/dist/navigation-menu.js +114 -0
- package/dist/number-input.d.ts +2 -0
- package/dist/number-input.js +73 -0
- package/dist/observe.d.ts +2 -0
- package/dist/observe.js +7 -0
- package/dist/otp-input.d.ts +2 -0
- package/dist/otp-input.js +72 -0
- package/dist/overlays.d.ts +13 -0
- package/dist/overlays.js +156 -0
- package/dist/pagination.d.ts +2 -0
- package/dist/pagination.js +127 -0
- package/dist/password-input.d.ts +2 -0
- package/dist/password-input.js +57 -0
- package/dist/popover.d.ts +2 -0
- package/dist/popover.js +64 -0
- package/dist/popup.d.ts +40 -0
- package/dist/popup.js +112 -0
- package/dist/preferences.d.ts +2 -0
- package/dist/preferences.js +56 -0
- package/dist/progress.d.ts +2 -0
- package/dist/progress.js +22 -0
- package/dist/radio.d.ts +2 -0
- package/dist/radio.js +33 -0
- package/dist/rating.d.ts +2 -0
- package/dist/rating.js +64 -0
- package/dist/resizable.d.ts +2 -0
- package/dist/resizable.js +42 -0
- package/dist/scroll-area.d.ts +2 -0
- package/dist/scroll-area.js +45 -0
- package/dist/segmented-control.d.ts +2 -0
- package/dist/segmented-control.js +28 -0
- package/dist/select.d.ts +2 -0
- package/dist/select.js +239 -0
- package/dist/separator.d.ts +2 -0
- package/dist/separator.js +11 -0
- package/dist/slider.d.ts +2 -0
- package/dist/slider.js +77 -0
- package/dist/tabs.d.ts +2 -0
- package/dist/tabs.js +37 -0
- package/dist/timeline.d.ts +2 -0
- package/dist/timeline.js +27 -0
- package/dist/toast.d.ts +20 -0
- package/dist/toast.js +177 -0
- package/dist/toggle.d.ts +3 -0
- package/dist/toggle.js +64 -0
- package/dist/token-input.d.ts +2 -0
- package/dist/token-input.js +103 -0
- package/dist/toolbar.d.ts +2 -0
- package/dist/toolbar.js +36 -0
- package/dist/tooltip.d.ts +2 -0
- package/dist/tooltip.js +35 -0
- package/dist/tree.d.ts +2 -0
- package/dist/tree.js +147 -0
- package/dist/trigger-menu.d.ts +2 -0
- package/dist/trigger-menu.js +133 -0
- package/dist/waterfall.d.ts +2 -0
- package/dist/waterfall.js +140 -0
- package/docs/README.md +89 -0
- package/docs/agents.md +1523 -0
- package/docs/components/accordion.md +1401 -0
- package/docs/components/alert-dialog.md +788 -0
- package/docs/components/autocomplete.md +1692 -0
- package/docs/components/avatar.md +261 -0
- package/docs/components/button.md +441 -0
- package/docs/components/calendar.md +1536 -0
- package/docs/components/carousel.md +1055 -0
- package/docs/components/checkbox.md +1045 -0
- package/docs/components/collapsible.md +535 -0
- package/docs/components/color-picker.md +651 -0
- package/docs/components/combobox.md +3274 -0
- package/docs/components/command.md +1431 -0
- package/docs/components/date-input.md +563 -0
- package/docs/components/date-picker.md +1136 -0
- package/docs/components/dialog.md +1360 -0
- package/docs/components/drawer.md +1201 -0
- package/docs/components/field.md +519 -0
- package/docs/components/file-input.md +617 -0
- package/docs/components/hover-card.md +486 -0
- package/docs/components/image-cropper.md +489 -0
- package/docs/components/input.md +327 -0
- package/docs/components/label.md +208 -0
- package/docs/components/listbox.md +1015 -0
- package/docs/components/menu.md +1212 -0
- package/docs/components/menubar.md +460 -0
- package/docs/components/meter.md +298 -0
- package/docs/components/navigation-menu.md +1573 -0
- package/docs/components/number-input.md +1087 -0
- package/docs/components/otp-input.md +558 -0
- package/docs/components/pagination.md +639 -0
- package/docs/components/password-input.md +649 -0
- package/docs/components/popover.md +1433 -0
- package/docs/components/preferences.md +243 -0
- package/docs/components/progress.md +406 -0
- package/docs/components/radio.md +855 -0
- package/docs/components/rating.md +431 -0
- package/docs/components/resizable.md +866 -0
- package/docs/components/scroll-area.md +898 -0
- package/docs/components/segmented-control.md +421 -0
- package/docs/components/select.md +1957 -0
- package/docs/components/separator.md +238 -0
- package/docs/components/slider.md +1018 -0
- package/docs/components/switch.md +583 -0
- package/docs/components/tabs.md +948 -0
- package/docs/components/textarea.md +331 -0
- package/docs/components/time-input.md +235 -0
- package/docs/components/timeline.md +622 -0
- package/docs/components/toast.md +1223 -0
- package/docs/components/toggle.md +522 -0
- package/docs/components/token-input.md +854 -0
- package/docs/components/toolbar.md +815 -0
- package/docs/components/tooltip.md +860 -0
- package/docs/components/tree.md +1243 -0
- package/docs/components/trigger-menu.md +1110 -0
- package/docs/components/waterfall.md +709 -0
- package/docs/controllers.md +66 -0
- package/docs/core.md +8027 -0
- package/docs/custom-parts.md +91 -0
- package/docs/first-component.md +88 -0
- package/docs/forms.md +125 -0
- package/docs/installation.md +141 -0
- package/docs/introduction.md +32 -0
- package/docs/lists-and-menus.md +166 -0
- package/docs/llms.txt +1566 -0
- package/docs/parts-and-composition.md +57 -0
- package/docs/popups.md +92 -0
- package/docs/rendering.md +71 -0
- package/docs/server-rendering.md +118 -0
- package/docs/state-and-events.md +134 -0
- package/docs/styling-and-animation.md +104 -0
- package/docs/utilities/async-options.md +332 -0
- package/docs/utilities/shortcuts.md +184 -0
- package/html-custom-data.json +14792 -0
- package/package.json +302 -3
|
@@ -0,0 +1,860 @@
|
|
|
1
|
+
# Tooltip
|
|
2
|
+
|
|
3
|
+
Name a control or add a short hint on hover and keyboard focus.
|
|
4
|
+
|
|
5
|
+
A tooltip names a control or adds a short hint when the pointer rests on it or keyboard focus reaches it. Keep it to a few words of plain text.
|
|
6
|
+
|
|
7
|
+
```ts title="basic.ts"
|
|
8
|
+
import "@ui-sdk/web/tooltip"
|
|
9
|
+
import { Bookmark, createElement } from "lucide"
|
|
10
|
+
|
|
11
|
+
function mount(root: HTMLElement) {
|
|
12
|
+
root.innerHTML = `
|
|
13
|
+
<ui-tooltip default-open>
|
|
14
|
+
<ui-tooltip-trigger>
|
|
15
|
+
<button aria-label="Add to library">${createElement(Bookmark, { "aria-hidden": "true" }).outerHTML}</button>
|
|
16
|
+
</ui-tooltip-trigger>
|
|
17
|
+
<ui-tooltip-content>Add to library</ui-tooltip-content>
|
|
18
|
+
</ui-tooltip>
|
|
19
|
+
`
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export { mount }
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
The tooltip starts open. Hover the button or reach it with Tab to show it again, and Escape closes it while focus stays on the button.
|
|
26
|
+
|
|
27
|
+
## Installation
|
|
28
|
+
|
|
29
|
+
```bash
|
|
30
|
+
npm install @ui-sdk/web @ui-sdk/core
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
Importing the component defines its elements. On the server the import does nothing.
|
|
34
|
+
|
|
35
|
+
```ts
|
|
36
|
+
import "@ui-sdk/web/tooltip"
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
## Composition
|
|
40
|
+
|
|
41
|
+
Use the following composition to build a `ui-tooltip`:
|
|
42
|
+
|
|
43
|
+
```text
|
|
44
|
+
ui-tooltip
|
|
45
|
+
├── ui-tooltip-trigger
|
|
46
|
+
│ └── button
|
|
47
|
+
└── ui-tooltip-content
|
|
48
|
+
├── ui-tooltip-arrow
|
|
49
|
+
└── ui-tooltip-shortcut
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
Wrap the trigger and its hint in a tooltip. The trigger wraps your own `<button>` or link, so it keeps everything a native button does. The arrow and the shortcut are optional.
|
|
53
|
+
|
|
54
|
+
The content has the `tooltip` role, and it's in the page from the start, hidden, so it names or describes its trigger before focus reaches it. It names a trigger without a name of its own, like a button with only an icon, and describes any other: one with text, an `aria-label` or a `title`. `type="label"` or `type="description"` overrides the guess. Keep it to plain text: a tooltip can't be focused, so links or buttons inside it can't be reached. For anything interactive, use a [Popover](./popover.md) or a [Hover Card](./hover-card.md).
|
|
55
|
+
|
|
56
|
+
## Usage
|
|
57
|
+
|
|
58
|
+
Import the parts and put them together:
|
|
59
|
+
|
|
60
|
+
```html
|
|
61
|
+
<script type="module">
|
|
62
|
+
import "@ui-sdk/web/tooltip"
|
|
63
|
+
</script>
|
|
64
|
+
|
|
65
|
+
<ui-tooltip>
|
|
66
|
+
<ui-tooltip-trigger><button>Share</button></ui-tooltip-trigger>
|
|
67
|
+
<ui-tooltip-content>Anyone with the link can view</ui-tooltip-content>
|
|
68
|
+
</ui-tooltip>
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
## Side
|
|
72
|
+
|
|
73
|
+
`side` picks where the tooltip opens: `top` by default. It flips to the other side when there isn't room, and shifts along the trigger to stay on screen. `data-side` says where it landed.
|
|
74
|
+
|
|
75
|
+
```ts title="side.ts"
|
|
76
|
+
import "@ui-sdk/web/tooltip"
|
|
77
|
+
|
|
78
|
+
const sides = [
|
|
79
|
+
{ side: "top", label: "Top" },
|
|
80
|
+
{ side: "left", label: "Left" },
|
|
81
|
+
{ side: "right", label: "Right" },
|
|
82
|
+
{ side: "bottom", label: "Bottom" },
|
|
83
|
+
]
|
|
84
|
+
|
|
85
|
+
function mount(root: HTMLElement) {
|
|
86
|
+
root.innerHTML = `
|
|
87
|
+
<div data-slot="grid">
|
|
88
|
+
${sides
|
|
89
|
+
.map(
|
|
90
|
+
({ side, label }) => `
|
|
91
|
+
<ui-tooltip>
|
|
92
|
+
<ui-tooltip-trigger><button>${label}</button></ui-tooltip-trigger>
|
|
93
|
+
<ui-tooltip-content side="${side}">Add to library</ui-tooltip-content>
|
|
94
|
+
</ui-tooltip>
|
|
95
|
+
`
|
|
96
|
+
)
|
|
97
|
+
.join("")}
|
|
98
|
+
</div>
|
|
99
|
+
`
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
export { mount }
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
Hover Top, Left, Right and Bottom. Each tooltip opens on that side of its button, or flips into the middle when there isn't room.
|
|
106
|
+
|
|
107
|
+
Add a `ui-tooltip-arrow` to point at the trigger. It follows the side the tooltip lands on, including after a flip.
|
|
108
|
+
|
|
109
|
+
```html
|
|
110
|
+
<ui-tooltip-content>
|
|
111
|
+
<ui-tooltip-arrow></ui-tooltip-arrow>
|
|
112
|
+
Add to library
|
|
113
|
+
</ui-tooltip-content>
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
## Anchor
|
|
117
|
+
|
|
118
|
+
Position the tooltip against something other than the trigger with `anchor`, a CSS selector for the element to line up with. The [controller's](#controller) `open()` also takes an element, a point like `{ x, y }`, or anything with `getBoundingClientRect()`. Here a small help button inside a field shows its tooltip along the whole field.
|
|
119
|
+
|
|
120
|
+
```ts title="anchor.ts"
|
|
121
|
+
import "@ui-sdk/web/tooltip"
|
|
122
|
+
import "@ui-sdk/web/field"
|
|
123
|
+
import "@ui-sdk/web/input"
|
|
124
|
+
import { createElement, Info } from "lucide"
|
|
125
|
+
|
|
126
|
+
function mount(root: HTMLElement) {
|
|
127
|
+
const id = `webhook-url-${crypto.randomUUID()}`
|
|
128
|
+
root.innerHTML = `
|
|
129
|
+
<ui-field>
|
|
130
|
+
<ui-field-label>Webhook URL</ui-field-label>
|
|
131
|
+
<div data-slot="row" id="${id}">
|
|
132
|
+
<ui-input>
|
|
133
|
+
<input placeholder="https://" />
|
|
134
|
+
</ui-input>
|
|
135
|
+
<ui-tooltip>
|
|
136
|
+
<ui-tooltip-trigger>
|
|
137
|
+
<button aria-label="About webhooks">${createElement(Info, { "aria-hidden": "true" }).outerHTML}</button>
|
|
138
|
+
</ui-tooltip-trigger>
|
|
139
|
+
<ui-tooltip-content anchor="#${id}" side="bottom" align="start">
|
|
140
|
+
We send a POST request here for every new order.
|
|
141
|
+
</ui-tooltip-content>
|
|
142
|
+
</ui-tooltip>
|
|
143
|
+
</div>
|
|
144
|
+
</ui-field>
|
|
145
|
+
`
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
export { mount }
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
Hover the help button. The tooltip opens below the Webhook URL field and lines up with its start, not with the button.
|
|
152
|
+
|
|
153
|
+
## Keyboard Shortcut
|
|
154
|
+
|
|
155
|
+
`shortcut` on the tooltip, like `"mod+s"`, is a hint for what the trigger's action is bound to, where `mod` is Command on Apple platforms and Control elsewhere. An empty `ui-tooltip-shortcut` shows the keys for the platform, `⌘S` or `Ctrl+S`, hidden from screen readers, and the trigger gets `aria-keyshortcuts` so they hear it instead. A `ui-tooltip-shortcut` can show other keys with its own `shortcut`.
|
|
156
|
+
|
|
157
|
+
The tooltip doesn't bind the keys. Register the shortcut yourself with [`registerShortcut`](../utilities/shortcuts.md), as the example does, or use the `shortcut` of a component that binds keys, like a [Dialog](./dialog.md#keyboard-shortcut) trigger.
|
|
158
|
+
|
|
159
|
+
```ts title="shortcut.ts"
|
|
160
|
+
import "@ui-sdk/web/tooltip"
|
|
161
|
+
import { registerShortcut } from "@ui-sdk/web"
|
|
162
|
+
import { createElement, Save } from "lucide"
|
|
163
|
+
import { log } from "./log"
|
|
164
|
+
|
|
165
|
+
function mount(root: HTMLElement) {
|
|
166
|
+
root.innerHTML = `
|
|
167
|
+
<div data-slot="row">
|
|
168
|
+
<ui-tooltip shortcut="mod+s">
|
|
169
|
+
<ui-tooltip-trigger>
|
|
170
|
+
<button aria-label="Save">${createElement(Save, { "aria-hidden": "true" }).outerHTML}</button>
|
|
171
|
+
</ui-tooltip-trigger>
|
|
172
|
+
<ui-tooltip-content>
|
|
173
|
+
Save
|
|
174
|
+
<ui-tooltip-shortcut></ui-tooltip-shortcut>
|
|
175
|
+
</ui-tooltip-content>
|
|
176
|
+
</ui-tooltip>
|
|
177
|
+
<ui-tooltip shortcut="mod+shift+e">
|
|
178
|
+
<ui-tooltip-trigger><button>Share</button></ui-tooltip-trigger>
|
|
179
|
+
<ui-tooltip-content>
|
|
180
|
+
Share with your team
|
|
181
|
+
<ui-tooltip-shortcut></ui-tooltip-shortcut>
|
|
182
|
+
</ui-tooltip-content>
|
|
183
|
+
</ui-tooltip>
|
|
184
|
+
</div>
|
|
185
|
+
`
|
|
186
|
+
const save = () => log(root, "Saved")
|
|
187
|
+
const share = () => log(root, "Shared")
|
|
188
|
+
const [saveButton, shareButton] = root.querySelectorAll("button")
|
|
189
|
+
saveButton.addEventListener("click", save)
|
|
190
|
+
shareButton.addEventListener("click", share)
|
|
191
|
+
const offSave = registerShortcut("mod+s", save)
|
|
192
|
+
const offShare = registerShortcut("mod+shift+e", share)
|
|
193
|
+
return () => {
|
|
194
|
+
offSave()
|
|
195
|
+
offShare()
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
export { mount }
|
|
200
|
+
```
|
|
201
|
+
|
|
202
|
+
Hover Save or Share to read its shortcut, then press the button or the keys. The console logs Saved or Shared.
|
|
203
|
+
|
|
204
|
+
## Disabled Buttons
|
|
205
|
+
|
|
206
|
+
A natively disabled button can't receive focus, and some browsers send it no pointer events, so its tooltip never shows. When the tooltip explains why an action is unavailable, use `aria-disabled="true"` instead and ignore the button's presses yourself. The button stays in the Tab order, screen readers announce it as dimmed, and the tooltip explains what's missing. `disabled` on the tooltip turns the explanation off once the button works.
|
|
207
|
+
|
|
208
|
+
```ts title="disabled-button.ts"
|
|
209
|
+
import "@ui-sdk/web/tooltip"
|
|
210
|
+
import "@ui-sdk/web/field"
|
|
211
|
+
import "@ui-sdk/web/input"
|
|
212
|
+
import { log } from "./log"
|
|
213
|
+
|
|
214
|
+
function mount(root: HTMLElement) {
|
|
215
|
+
root.innerHTML = `
|
|
216
|
+
<div data-slot="stack">
|
|
217
|
+
<ui-field>
|
|
218
|
+
<ui-field-label>Post title</ui-field-label>
|
|
219
|
+
<ui-input>
|
|
220
|
+
<input />
|
|
221
|
+
</ui-input>
|
|
222
|
+
</ui-field>
|
|
223
|
+
<ui-tooltip>
|
|
224
|
+
<ui-tooltip-trigger><button data-variant="solid" aria-disabled="true">Publish</button></ui-tooltip-trigger>
|
|
225
|
+
<ui-tooltip-content side="right">Add a title to publish</ui-tooltip-content>
|
|
226
|
+
</ui-tooltip>
|
|
227
|
+
</div>
|
|
228
|
+
`
|
|
229
|
+
const input = root.querySelector("input")!
|
|
230
|
+
const tooltip = root.querySelector("ui-tooltip")!
|
|
231
|
+
const publish = root.querySelector("button")!
|
|
232
|
+
const title = () => input.value.trim()
|
|
233
|
+
input.addEventListener("input", () => {
|
|
234
|
+
const blocked = !title()
|
|
235
|
+
if (blocked) {
|
|
236
|
+
publish.setAttribute("aria-disabled", "true")
|
|
237
|
+
} else {
|
|
238
|
+
publish.removeAttribute("aria-disabled")
|
|
239
|
+
}
|
|
240
|
+
tooltip.disabled = !blocked
|
|
241
|
+
})
|
|
242
|
+
publish.addEventListener("click", () => {
|
|
243
|
+
if (title()) {
|
|
244
|
+
log(root, `Published “${title()}”`)
|
|
245
|
+
}
|
|
246
|
+
})
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
export { mount }
|
|
250
|
+
```
|
|
251
|
+
|
|
252
|
+
Hover or focus Publish to learn what's missing. Type a title, and Publish works and its tooltip goes away.
|
|
253
|
+
|
|
254
|
+
## Touch
|
|
255
|
+
|
|
256
|
+
Touch screens have no hover. A tap on a plain tooltip's trigger only presses it, and the tooltip stays closed, so don't hide anything important in a tooltip.
|
|
257
|
+
|
|
258
|
+
For an info button whose only job is the tip, add `toggleable`: pressing the trigger opens and closes the tooltip, with a finger, a mouse or the keyboard, and its text is announced when a press opens it. An outside press or Escape closes it too.
|
|
259
|
+
|
|
260
|
+
```ts title="toggleable.ts"
|
|
261
|
+
import "@ui-sdk/web/tooltip"
|
|
262
|
+
import { createElement, Info } from "lucide"
|
|
263
|
+
|
|
264
|
+
function mount(root: HTMLElement) {
|
|
265
|
+
root.innerHTML = `
|
|
266
|
+
<div data-slot="row">
|
|
267
|
+
<span data-slot="label">Storage</span>
|
|
268
|
+
<ui-tooltip toggleable>
|
|
269
|
+
<ui-tooltip-trigger>
|
|
270
|
+
<button aria-label="About storage" data-size="sm">${createElement(Info, { "aria-hidden": "true" }).outerHTML}</button>
|
|
271
|
+
</ui-tooltip-trigger>
|
|
272
|
+
<ui-tooltip-content>Files in the trash still use storage.</ui-tooltip-content>
|
|
273
|
+
</ui-tooltip>
|
|
274
|
+
<span data-slot="hint">12.4 of 15 GB used</span>
|
|
275
|
+
</div>
|
|
276
|
+
`
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
export { mount }
|
|
280
|
+
```
|
|
281
|
+
|
|
282
|
+
Press the info button to open the tip, including on a touch screen. Press it again or anywhere else to close it.
|
|
283
|
+
|
|
284
|
+
## Keep Open on Press
|
|
285
|
+
|
|
286
|
+
Pressing the trigger closes the tooltip, so it doesn't cover what the press changed, and it stays closed until the pointer leaves. `close-on-press="false"` keeps it open, like for a copy button whose tooltip turns into "Copied".
|
|
287
|
+
|
|
288
|
+
```ts title="copy.ts"
|
|
289
|
+
import "@ui-sdk/web/tooltip"
|
|
290
|
+
import { Check, Copy, createElement } from "lucide"
|
|
291
|
+
|
|
292
|
+
const command = "npm install @ui-sdk/web"
|
|
293
|
+
|
|
294
|
+
function mount(root: HTMLElement) {
|
|
295
|
+
root.innerHTML = `
|
|
296
|
+
<div data-slot="row">
|
|
297
|
+
<code>${command}</code>
|
|
298
|
+
<ui-tooltip close-on-press="false">
|
|
299
|
+
<ui-tooltip-trigger><button></button></ui-tooltip-trigger>
|
|
300
|
+
<ui-tooltip-content></ui-tooltip-content>
|
|
301
|
+
</ui-tooltip>
|
|
302
|
+
</div>
|
|
303
|
+
`
|
|
304
|
+
const tooltip = root.querySelector("ui-tooltip")!
|
|
305
|
+
const button = root.querySelector("button")!
|
|
306
|
+
const content = root.querySelector("ui-tooltip-content")!
|
|
307
|
+
const render = (copied: boolean) => {
|
|
308
|
+
const label = copied ? "Copied" : "Copy"
|
|
309
|
+
button.setAttribute("aria-label", label)
|
|
310
|
+
button.replaceChildren(
|
|
311
|
+
createElement(copied ? Check : Copy, { "aria-hidden": "true" })
|
|
312
|
+
)
|
|
313
|
+
content.textContent = label
|
|
314
|
+
}
|
|
315
|
+
render(false)
|
|
316
|
+
button.addEventListener("click", () => {
|
|
317
|
+
navigator.clipboard?.writeText(command).catch(() => {})
|
|
318
|
+
render(true)
|
|
319
|
+
})
|
|
320
|
+
tooltip.addEventListener("openchangecomplete", (event) => {
|
|
321
|
+
if (!event.detail.value) {
|
|
322
|
+
render(false)
|
|
323
|
+
}
|
|
324
|
+
})
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
export { mount }
|
|
328
|
+
```
|
|
329
|
+
|
|
330
|
+
Hover the copy button and press it. The tooltip stays open and changes to Copied.
|
|
331
|
+
|
|
332
|
+
## Truncated Text
|
|
333
|
+
|
|
334
|
+
To show a tooltip only when text is cut off, cancel the open with `event.preventDefault()` in `openchange` when the text fits. Compare `scrollWidth` with `clientWidth` in the listener. The tooltip repeats the name, so `type="label"` keeps screen readers from hearing it twice.
|
|
335
|
+
|
|
336
|
+
```ts title="truncated.ts"
|
|
337
|
+
import "@ui-sdk/web/tooltip"
|
|
338
|
+
import { createElement, File } from "lucide"
|
|
339
|
+
|
|
340
|
+
const files = [
|
|
341
|
+
"Quarterly report, final revised version for the board.pdf",
|
|
342
|
+
"Notes.txt",
|
|
343
|
+
"Design review recording, October 2nd.mp4",
|
|
344
|
+
"Budget.xlsx",
|
|
345
|
+
]
|
|
346
|
+
|
|
347
|
+
function mount(root: HTMLElement) {
|
|
348
|
+
root.innerHTML = `
|
|
349
|
+
<ul>
|
|
350
|
+
${files
|
|
351
|
+
.map(
|
|
352
|
+
(file) => `
|
|
353
|
+
<li>
|
|
354
|
+
<ui-tooltip type="label">
|
|
355
|
+
<ui-tooltip-trigger><button>${createElement(File, { "aria-hidden": "true" }).outerHTML}<span>${file}</span></button></ui-tooltip-trigger>
|
|
356
|
+
<ui-tooltip-content>${file}</ui-tooltip-content>
|
|
357
|
+
</ui-tooltip>
|
|
358
|
+
</li>`
|
|
359
|
+
)
|
|
360
|
+
.join("")}
|
|
361
|
+
</ul>
|
|
362
|
+
`
|
|
363
|
+
for (const tooltip of root.querySelectorAll("ui-tooltip")) {
|
|
364
|
+
tooltip.addEventListener("openchange", (event) => {
|
|
365
|
+
const name = tooltip.querySelector("span")
|
|
366
|
+
if (event.detail.value && name && name.scrollWidth <= name.clientWidth) {
|
|
367
|
+
event.preventDefault()
|
|
368
|
+
}
|
|
369
|
+
})
|
|
370
|
+
}
|
|
371
|
+
}
|
|
372
|
+
|
|
373
|
+
export { mount }
|
|
374
|
+
```
|
|
375
|
+
|
|
376
|
+
Hover or focus each file. Only names that are cut off open a tooltip.
|
|
377
|
+
|
|
378
|
+
## Controlled
|
|
379
|
+
|
|
380
|
+
Set the element's `open` property and listen for `openchange`. Every change carries a [reason](#reasons), like `trigger-hover`, `trigger-focus`, `trigger-press`, `escape-key` or `outside-press`. Call `event.preventDefault()` to stop it. To open the tooltip from anywhere, like a step in a guided tour, use its [controller](#controller).
|
|
381
|
+
|
|
382
|
+
```ts title="controlled.ts"
|
|
383
|
+
import "@ui-sdk/web/tooltip"
|
|
384
|
+
import "@ui-sdk/web/checkbox"
|
|
385
|
+
import { Check, createElement } from "lucide"
|
|
386
|
+
import { log } from "./log"
|
|
387
|
+
|
|
388
|
+
function mount(root: HTMLElement) {
|
|
389
|
+
root.innerHTML = `
|
|
390
|
+
<div data-slot="stack">
|
|
391
|
+
<div data-slot="controls">
|
|
392
|
+
<label data-slot="label">
|
|
393
|
+
<ui-checkbox>
|
|
394
|
+
<ui-checkbox-indicator>
|
|
395
|
+
${createElement(Check, { "aria-hidden": "true" }).outerHTML}
|
|
396
|
+
</ui-checkbox-indicator>
|
|
397
|
+
</ui-checkbox>
|
|
398
|
+
Open
|
|
399
|
+
</label>
|
|
400
|
+
</div>
|
|
401
|
+
<ui-tooltip>
|
|
402
|
+
<ui-tooltip-trigger><button>Export</button></ui-tooltip-trigger>
|
|
403
|
+
<ui-tooltip-content>Download as CSV</ui-tooltip-content>
|
|
404
|
+
</ui-tooltip>
|
|
405
|
+
</div>
|
|
406
|
+
`
|
|
407
|
+
const controls = root.querySelector('[data-slot="controls"]')!
|
|
408
|
+
const checkbox = root.querySelector("ui-checkbox")!
|
|
409
|
+
const tooltip = root.querySelector("ui-tooltip")!
|
|
410
|
+
checkbox.addEventListener("checkedchange", (event) => {
|
|
411
|
+
tooltip.open = event.detail.value === true
|
|
412
|
+
})
|
|
413
|
+
tooltip.addEventListener("openchange", (event) => {
|
|
414
|
+
const { value, reason, event: cause } = event.detail
|
|
415
|
+
const inControls =
|
|
416
|
+
cause?.target instanceof Node && controls.contains(cause.target)
|
|
417
|
+
if (inControls && reason !== "escape-key") {
|
|
418
|
+
return event.preventDefault()
|
|
419
|
+
}
|
|
420
|
+
checkbox.checked = value
|
|
421
|
+
log(root, `${value ? "Opened" : "Closed"} (${reason})`)
|
|
422
|
+
})
|
|
423
|
+
}
|
|
424
|
+
|
|
425
|
+
export { mount }
|
|
426
|
+
```
|
|
427
|
+
|
|
428
|
+
Check Open, or hover Export. The console logs each change and its reason.
|
|
429
|
+
|
|
430
|
+
## Shared
|
|
431
|
+
|
|
432
|
+
A toolbar, a chart or a long list can share one tooltip instead of rendering one per item. Give the tooltip an `id` and point each trigger at it with `for`, and the triggers can sit anywhere on the page. Each trigger takes a `payload` property, here its label, and you fill the content when `payloadchange` fires, with the payload in `event.detail.value`. `UiTooltipElement<string>` types the payload. The content is in the page before the first open, so handle an `undefined` payload.
|
|
433
|
+
|
|
434
|
+
Only the trigger that opened the tooltip is described by it, so give each trigger a name of its own, like an `aria-label`. The controller's `open()` takes a payload and an `anchor` too, and on an open tooltip, `open({ payload })` replaces the payload, like another trigger taking it over. `payloadchange` reports each change, including the pointer or focus moving on to another trigger, which hands the open tooltip over without an `openchange`.
|
|
435
|
+
|
|
436
|
+
```ts title="shared.ts"
|
|
437
|
+
import "@ui-sdk/web/tooltip"
|
|
438
|
+
import type { UiTooltipElement } from "@ui-sdk/web/tooltip"
|
|
439
|
+
import { Bold, createElement, Italic, Underline } from "lucide"
|
|
440
|
+
|
|
441
|
+
const formats = [
|
|
442
|
+
{ icon: Bold, label: "Bold" },
|
|
443
|
+
{ icon: Italic, label: "Italic" },
|
|
444
|
+
{ icon: Underline, label: "Underline" },
|
|
445
|
+
]
|
|
446
|
+
|
|
447
|
+
function mount(root: HTMLElement) {
|
|
448
|
+
const id = `formatting-${crypto.randomUUID()}`
|
|
449
|
+
root.innerHTML = `
|
|
450
|
+
<div data-slot="row" role="group" aria-label="Formatting">
|
|
451
|
+
${formats
|
|
452
|
+
.map(
|
|
453
|
+
(format) => `
|
|
454
|
+
<ui-tooltip-trigger for="${id}">
|
|
455
|
+
<button aria-label="${format.label}">${createElement(format.icon, { "aria-hidden": "true" }).outerHTML}</button>
|
|
456
|
+
</ui-tooltip-trigger>
|
|
457
|
+
`
|
|
458
|
+
)
|
|
459
|
+
.join("")}
|
|
460
|
+
<ui-tooltip id="${id}">
|
|
461
|
+
<ui-tooltip-content></ui-tooltip-content>
|
|
462
|
+
</ui-tooltip>
|
|
463
|
+
</div>
|
|
464
|
+
`
|
|
465
|
+
root.querySelectorAll("ui-tooltip-trigger").forEach((trigger, index) => {
|
|
466
|
+
trigger.payload = formats[index].label
|
|
467
|
+
})
|
|
468
|
+
const tooltip = root.querySelector<UiTooltipElement<string>>("ui-tooltip")!
|
|
469
|
+
const content = root.querySelector("ui-tooltip-content")!
|
|
470
|
+
tooltip.addEventListener("payloadchange", (event) => {
|
|
471
|
+
content.textContent = event.detail.value ?? ""
|
|
472
|
+
})
|
|
473
|
+
}
|
|
474
|
+
|
|
475
|
+
export { mount }
|
|
476
|
+
```
|
|
477
|
+
|
|
478
|
+
Move along Bold, Italic and Underline. One tooltip follows the pointer and shows each button's label.
|
|
479
|
+
|
|
480
|
+
## Animation
|
|
481
|
+
|
|
482
|
+
The content has `data-starting-style` while it opens and `data-ending-style` while it closes. Transition from those states, and the tooltip stays mounted until its exit finishes. Put `transform-origin: var(--transform-origin)` on the content so it grows out of its trigger. A tooltip that opens at once, as the next one in a group does, gets `data-instant`, so skip the transition there.
|
|
483
|
+
|
|
484
|
+
```css
|
|
485
|
+
[data-slot="tooltip-content"] {
|
|
486
|
+
transform-origin: var(--transform-origin);
|
|
487
|
+
transition:
|
|
488
|
+
opacity 150ms ease-out,
|
|
489
|
+
scale 150ms ease-out;
|
|
490
|
+
|
|
491
|
+
&:is([data-starting-style], [data-ending-style]) {
|
|
492
|
+
opacity: 0;
|
|
493
|
+
scale: 0.9;
|
|
494
|
+
}
|
|
495
|
+
|
|
496
|
+
&[data-instant] {
|
|
497
|
+
transition: none;
|
|
498
|
+
}
|
|
499
|
+
}
|
|
500
|
+
```
|
|
501
|
+
|
|
502
|
+
For people who ask for less motion, drop the scale in a `prefers-reduced-motion` query and keep the fade. `openchangecomplete` fires once the tooltip has finished opening or closing, after any animation, with the new open state in `event.detail.value`.
|
|
503
|
+
|
|
504
|
+
```ts title="animation.ts"
|
|
505
|
+
import "@ui-sdk/web/tooltip"
|
|
506
|
+
import { Archive, createElement } from "lucide"
|
|
507
|
+
import { log } from "./log"
|
|
508
|
+
|
|
509
|
+
function mount(root: HTMLElement) {
|
|
510
|
+
root.innerHTML = `
|
|
511
|
+
<ui-tooltip>
|
|
512
|
+
<ui-tooltip-trigger>
|
|
513
|
+
<button aria-label="Archive">${createElement(Archive, { "aria-hidden": "true" }).outerHTML}</button>
|
|
514
|
+
</ui-tooltip-trigger>
|
|
515
|
+
<ui-tooltip-content>Archive</ui-tooltip-content>
|
|
516
|
+
</ui-tooltip>
|
|
517
|
+
`
|
|
518
|
+
const tooltip = root.querySelector("ui-tooltip")!
|
|
519
|
+
tooltip.addEventListener("openchange", (event) =>
|
|
520
|
+
log(root, event.detail.value ? "Opening" : "Closing")
|
|
521
|
+
)
|
|
522
|
+
tooltip.addEventListener("openchangecomplete", (event) =>
|
|
523
|
+
log(root, event.detail.value ? "Open" : "Closed")
|
|
524
|
+
)
|
|
525
|
+
}
|
|
526
|
+
|
|
527
|
+
export { mount }
|
|
528
|
+
```
|
|
529
|
+
|
|
530
|
+
Hover Archive, then move away. The tooltip grows out of the button and fades, and the console logs Opening, Open, Closing and Closed.
|
|
531
|
+
|
|
532
|
+
## Delay and Grouping
|
|
533
|
+
|
|
534
|
+
`delay` is how long the pointer rests on the trigger before the tooltip opens, 600 milliseconds by default. `close-delay` is how long it stays once the pointer leaves the trigger and the tooltip, 0 by default. Keyboard focus opens it at once.
|
|
535
|
+
|
|
536
|
+
Tooltips group without a provider. Once one is open, or was a moment ago, hovering the next opens it at once, and only one is open at a time, so moving along a toolbar reads like one tooltip that follows the pointer. A tooltip that opened at once gets `data-instant`, so it can skip its animation.
|
|
537
|
+
|
|
538
|
+
`disabled` stops a tooltip from opening, while its trigger keeps working.
|
|
539
|
+
|
|
540
|
+
```html
|
|
541
|
+
<ui-tooltip delay="300" close-delay="150" disabled></ui-tooltip>
|
|
542
|
+
```
|
|
543
|
+
|
|
544
|
+
## Offset
|
|
545
|
+
|
|
546
|
+
`side-offset` is the gap to the trigger, 4 pixels by default. `align-offset` shifts along it, `align` lines it up with the start, center or end of the trigger, and `collision-padding` is the space kept from the edges of the window.
|
|
547
|
+
|
|
548
|
+
```html
|
|
549
|
+
<ui-tooltip-content
|
|
550
|
+
align="start"
|
|
551
|
+
side-offset="8"
|
|
552
|
+
align-offset="4"
|
|
553
|
+
collision-padding="16"
|
|
554
|
+
></ui-tooltip-content>
|
|
555
|
+
```
|
|
556
|
+
|
|
557
|
+
## Container
|
|
558
|
+
|
|
559
|
+
Tooltips render in place and show in the top layer, so no ancestor clips or covers them. `container`, a CSS selector, renders the tooltip somewhere else, for iframes, shadow roots or a specific stacking context. See the shared [popup guide](../popups.md).
|
|
560
|
+
|
|
561
|
+
```html
|
|
562
|
+
<ui-tooltip-content container="#tooltips"></ui-tooltip-content>
|
|
563
|
+
```
|
|
564
|
+
|
|
565
|
+
## Custom Rendering
|
|
566
|
+
|
|
567
|
+
Elements have no render functions. The trigger wraps your own element, a button or a link, and that element is the trigger, with your attributes on it. Read state from the data attributes every part sets. See [Parts and Composition](../parts-and-composition.md) for the rendering contract.
|
|
568
|
+
|
|
569
|
+
```ts title="custom-rendering.ts"
|
|
570
|
+
import "@ui-sdk/web/tooltip"
|
|
571
|
+
|
|
572
|
+
function mount(root: HTMLElement) {
|
|
573
|
+
root.innerHTML = `
|
|
574
|
+
<ui-tooltip>
|
|
575
|
+
<ui-tooltip-trigger><a href="https://example.com/changelog" data-variant="link">Changelog</a></ui-tooltip-trigger>
|
|
576
|
+
<ui-tooltip-content>See what's new in 2.0</ui-tooltip-content>
|
|
577
|
+
</ui-tooltip>
|
|
578
|
+
`
|
|
579
|
+
}
|
|
580
|
+
|
|
581
|
+
export { mount }
|
|
582
|
+
```
|
|
583
|
+
|
|
584
|
+
Hover Changelog. The trigger renders as a link, and its tooltip says where it goes.
|
|
585
|
+
|
|
586
|
+
A button can be a tooltip's trigger and another component's trigger at once. Nest the triggers, and both bind the button deepest in, so it opens the popover and is named by the tooltip:
|
|
587
|
+
|
|
588
|
+
```html
|
|
589
|
+
<ui-popover>
|
|
590
|
+
<ui-tooltip>
|
|
591
|
+
<ui-tooltip-trigger>
|
|
592
|
+
<ui-popover-trigger>
|
|
593
|
+
<button><svg aria-hidden="true">…</svg></button>
|
|
594
|
+
</ui-popover-trigger>
|
|
595
|
+
</ui-tooltip-trigger>
|
|
596
|
+
<ui-tooltip-content>Notifications</ui-tooltip-content>
|
|
597
|
+
</ui-tooltip>
|
|
598
|
+
<ui-popover-content>...</ui-popover-content>
|
|
599
|
+
</ui-popover>
|
|
600
|
+
```
|
|
601
|
+
|
|
602
|
+
## Styling
|
|
603
|
+
|
|
604
|
+
Use `data-side` and `data-align` to style the content and arrow for where they landed, and `data-instant` to skip the animation of a tooltip that opened at once. The trigger gets no state attributes of its own, since it's often another component's trigger too, like a menu's. Put `transform-origin: var(--transform-origin)` on the content so it scales from the trigger.
|
|
605
|
+
|
|
606
|
+
Each part has a `data-slot`, such as `tooltip-content`, and its state attributes are listed under [Data Attributes](#data-attributes).
|
|
607
|
+
|
|
608
|
+
### `<ui-tooltip-content>`
|
|
609
|
+
- `--anchor-width`: Width of the anchor, usually the trigger. Use it to match widths.
|
|
610
|
+
- `--anchor-height`: Height of the anchor.
|
|
611
|
+
- `--available-width`: Space beside the popup, up to the viewport edge. Not inherited either.
|
|
612
|
+
- `--available-height`: Space between the anchor and the viewport edge. Use it for max-height. Not inherited, so a child that needs it copies it on the popup, like `[--list-height:var(--available-height)]`, and reads `max-h-(--list-height)`. The first popup registers both names for the whole page with `CSS.registerProperty`, so they don't inherit anywhere. A page that needs them to inherit calls it first, with `inherits: true`. An `@property` rule can't, since a registration in script wins.
|
|
613
|
+
- `--transform-origin`: The point on the anchor the popup opens from. Use it to scale from the right place.
|
|
614
|
+
- `--arrow-offset`: Where the anchor's center falls along the popup's edge, kept `arrowPadding` from the corners. Position a ::before arrow with it.
|
|
615
|
+
|
|
616
|
+
## Data Attributes
|
|
617
|
+
|
|
618
|
+
`<ui-tooltip-trigger>` and `<ui-tooltip-shortcut>` have no state attributes.
|
|
619
|
+
|
|
620
|
+
### `<ui-tooltip-content>`
|
|
621
|
+
`[data-slot="tooltip-content"]`
|
|
622
|
+
|
|
623
|
+
- `data-closed`: Present while the tooltip is closed, including while it animates out.
|
|
624
|
+
- `data-open`: Present while the tooltip is open.
|
|
625
|
+
- `data-starting-style`: Present for the first frame. Style the state you animate from.
|
|
626
|
+
- `data-ending-style`: Present while the tooltip animates out. Style the state you animate to.
|
|
627
|
+
|
|
628
|
+
### `<ui-tooltip-arrow>`
|
|
629
|
+
`[data-slot="tooltip-arrow"]`
|
|
630
|
+
|
|
631
|
+
- `data-closed`: Present while the tooltip is closed, including while it animates out.
|
|
632
|
+
- `data-open`: Present while the tooltip is open.
|
|
633
|
+
|
|
634
|
+
## API Reference
|
|
635
|
+
|
|
636
|
+
Props are attributes in kebab case, like `close-delay` and `side-offset`: `"false"` is false, and numbers are numbers. `anchor` and `container` take CSS selectors. Callbacks are DOM events.
|
|
637
|
+
|
|
638
|
+
### Tooltip
|
|
639
|
+
|
|
640
|
+
- `container?` (`DocumentFragment | Element | null`): Renders the popup into this element instead of in place, like a container inside a shadow root or an iframe. On web components, a CSS selector. Nested popups stay inside their parent.
|
|
641
|
+
- `open?` (`boolean`): Whether the tooltip is open. Pass it to control the tooltip.
|
|
642
|
+
- `defaultOpen?` (`boolean`): Whether the tooltip starts open, when uncontrolled.
|
|
643
|
+
- `openchange event`: Runs when the tooltip wants to open or close. `details.reason` says why, and `details.cancel()` stops it.
|
|
644
|
+
- `openchangecomplete event`: Runs once the tooltip has finished opening or closing, after any animation.
|
|
645
|
+
- `payloadchange event`: Runs when the payload the content shows changes: a trigger with another payload opens the tooltip, or takes the open tooltip over, which fires no `openchange`, and so does a controller's `open({ payload })` on the open tooltip. `details.cancel()` keeps the previous payload.
|
|
646
|
+
- `delay?` (`number`): Milliseconds the pointer rests on the trigger before the tooltip opens. While another tooltip is open, or was a moment ago, the next one opens at once, without a provider.
|
|
647
|
+
- `closeDelay?` (`number`): Milliseconds before the tooltip closes once the pointer leaves the trigger and the tooltip.
|
|
648
|
+
- `disabled?` (`boolean`): Stops the tooltip from opening. The trigger keeps working.
|
|
649
|
+
- `toggleable?` (`boolean`): Whether pressing the trigger opens and closes the tooltip, so touch screens can show it too. For info buttons whose only job is the tip. The text is announced when a press opens it.
|
|
650
|
+
- `closeOnPress?` (`boolean`): Whether pressing the trigger closes the tooltip. Set it to `false` to keep it open, like for a copy button whose tooltip turns into "Copied".
|
|
651
|
+
- `type?` (`"description" | "label"`): Whether the tooltip names its trigger (`"label"`) or adds a description to it (`"description"`). By default it names a trigger that has no name of its own, like an icon button, and describes any other.
|
|
652
|
+
- `shortcut?` (`string`): The keyboard shortcut of what the trigger does, like `"mod+s"`, as a hint. A `TooltipShortcut` shows it, and the trigger gets `aria-keyshortcuts`. It doesn't bind the keys: the trigger's own `shortcut`, or `registerShortcut`, does.
|
|
653
|
+
- `controller?` (`PopupController<any, TooltipOpenChangeReason, {}, string, TooltipPayloadChangeReason>`): Opens, closes and inspects the tooltip from anywhere, and connects triggers outside it. Create one with `createTooltipController()`.
|
|
654
|
+
- `debug?` (`boolean`): Logs every state change with its reason to the console, in development builds.
|
|
655
|
+
|
|
656
|
+
### TooltipTrigger
|
|
657
|
+
|
|
658
|
+
A trigger outside the tooltip names it with `for="tooltip-id"`, and takes `payload` as a property.
|
|
659
|
+
|
|
660
|
+
- `payload?` (`unknown`): Data for the content to render when this trigger opens the tooltip, like the row it belongs to.
|
|
661
|
+
- `controller?` (`PopupController<any, TooltipOpenChangeReason, {}, string, TooltipPayloadChangeReason>`): Connects a trigger outside the tooltip, like one per table row, to the tooltip with this controller.
|
|
662
|
+
|
|
663
|
+
### TooltipContent
|
|
664
|
+
|
|
665
|
+
- `side?` (`Side`): Which side of the anchor the popup opens on. Flips to the other side when there isn't room. Which side of the trigger the tooltip opens on.
|
|
666
|
+
- `align?` (`Align`): How the popup lines up with the anchor along that side. `start` and `end` follow the reading direction. How the tooltip lines up with the trigger along that side.
|
|
667
|
+
- `sideOffset?` (`number`): Gap between the anchor and the popup, in pixels. Gap between the trigger and the tooltip, in pixels.
|
|
668
|
+
- `alignOffset?` (`number`): Shift along the anchor, in pixels. Shift along the trigger, in pixels.
|
|
669
|
+
- `collisionPadding?` (`number`): Space to keep from the viewport edges, in pixels.
|
|
670
|
+
- `arrowPadding?` (`number`): Space to keep between the arrow and the popup's corners, in pixels.
|
|
671
|
+
- `anchor?` (`string | Anchor | null`): Positions the popup against this instead of its trigger: an element, a CSS selector, a point like `{ x, y }`, or anything with `getBoundingClientRect()`. It's read on every check, so it can move. A controller's `open({ anchor })` wins for that open.
|
|
672
|
+
- `container?` (`DocumentFragment | Element | null`): Renders the popup into this element instead of in place, like a container inside a shadow root or an iframe. On web components, a CSS selector. Nested popups stay inside their parent.
|
|
673
|
+
|
|
674
|
+
### TooltipArrow
|
|
675
|
+
|
|
676
|
+
Points at the trigger from the side the tooltip landed on.
|
|
677
|
+
|
|
678
|
+
### TooltipShortcut
|
|
679
|
+
|
|
680
|
+
- `shortcut?` (`string`): The keys to show. By default, the tooltip's `shortcut`.
|
|
681
|
+
|
|
682
|
+
### State
|
|
683
|
+
|
|
684
|
+
The same state shows as data attributes on each element.
|
|
685
|
+
|
|
686
|
+
`TooltipTrigger`:
|
|
687
|
+
|
|
688
|
+
- `open` (`boolean`): Whether the tooltip is open from this trigger.
|
|
689
|
+
|
|
690
|
+
`TooltipContent`:
|
|
691
|
+
|
|
692
|
+
- `open` (`boolean`): Whether the tooltip is open. False while it animates out.
|
|
693
|
+
- `instant` (`boolean`): Whether it opened at once, because another tooltip was open a moment ago. Animations can skip.
|
|
694
|
+
- `payload` (`Payload | undefined`): The payload of the last open, from the trigger that opened it or a controller, typed as the controller's `Payload`.
|
|
695
|
+
|
|
696
|
+
`TooltipArrow`:
|
|
697
|
+
|
|
698
|
+
- `open` (`boolean`): Whether the tooltip is open. False as soon as it starts closing, while it still animates out.
|
|
699
|
+
|
|
700
|
+
`TooltipShortcut`:
|
|
701
|
+
|
|
702
|
+
- `text` (`string`): The shortcut formatted for this platform: `⌘S` on Apple platforms and `Ctrl+S` elsewhere. Empty without one.
|
|
703
|
+
|
|
704
|
+
### Reasons
|
|
705
|
+
|
|
706
|
+
`event.detail.reason` says why the tooltip opened or closed.
|
|
707
|
+
|
|
708
|
+
- `trigger-hover` (`PointerEvent`): The pointer rested on a trigger, or left it, with hover opening.
|
|
709
|
+
- `trigger-focus` (`FocusEvent`): Keyboard focus reached a trigger that opens on focus, like a tooltip's.
|
|
710
|
+
- `trigger-press` (`MouseEvent | KeyboardEvent | TouchEvent`): Click, tap, Enter or Space on the part that opens, closes or toggles. Arrow keys that open a menu or submenu count too. A tap on a combobox's input that opens a sheet reports its `touchend`.
|
|
711
|
+
- `focus-out` (`KeyboardEvent | FocusEvent`): Focus left the layer, or Tab moved it out.
|
|
712
|
+
- `escape-key` (`KeyboardEvent`): Escape, or a submenu's close key (ArrowLeft in left-to-right layouts).
|
|
713
|
+
- `close-press` (`MouseEvent | KeyboardEvent | SubmitEvent`): A Close part was pressed, or a form with `method="dialog"` was submitted.
|
|
714
|
+
- `outside-press` (`MouseEvent`): A press outside the layer.
|
|
715
|
+
- `window-blur` (`FocusEvent`): The window lost focus.
|
|
716
|
+
- `back` (`Event`): Going back: the Android back button or gesture, or Backspace in an empty command input, which returns to the previous page.
|
|
717
|
+
- `imperative` (`none`): A controller or `api` call, or a property set on a web component.
|
|
718
|
+
|
|
719
|
+
For a payload change, it says what opened the tooltip or took it over.
|
|
720
|
+
|
|
721
|
+
- `trigger-hover` (`PointerEvent`): The pointer rested on a trigger, or left it, with hover opening.
|
|
722
|
+
- `trigger-focus` (`FocusEvent`): Keyboard focus reached a trigger that opens on focus, like a tooltip's.
|
|
723
|
+
- `trigger-press` (`MouseEvent | KeyboardEvent | TouchEvent`): Click, tap, Enter or Space on the part that opens, closes or toggles. Arrow keys that open a menu or submenu count too. A tap on a combobox's input that opens a sheet reports its `touchend`.
|
|
724
|
+
- `imperative` (`none`): A controller or `api` call, or a property set on a web component.
|
|
725
|
+
|
|
726
|
+
### Controller
|
|
727
|
+
|
|
728
|
+
The element's `api` property has the same methods. The `open` property reads and sets whether the tooltip
|
|
729
|
+
is open.
|
|
730
|
+
|
|
731
|
+
Every write method takes an optional `{ reason, event }`, passed to `openchange`.
|
|
732
|
+
|
|
733
|
+
- `isOpen()` (`() => boolean`): Whether it's open. False as soon as it starts closing, while it still animates out.
|
|
734
|
+
- `setOpen(open, options?)` (`(open: boolean, options?: PopupChangeOptions<TooltipOpenChangeReason> | undefined) => boolean`): Opens or closes it. Returns false when the change was canceled or it was already open or closed.
|
|
735
|
+
- `open(options?)` (`(options?: (PopupChangeOptions<TooltipPayloadChangeReason> & { payload?: Payload | undefined; anchor?: Anchor | undefined; signal?: AbortSignal | undefined; }) | undefined) => Promise<...>`): Opens it, and resolves once it closes, with why, how and any return value. Resolves exactly once and never rejects: on the next close from any source, when `signal` aborts, or with reason `"unmount"` when the component leaves the page.
|
|
736
|
+
- `close(options?)` (`(options?: (PopupChangeOptions<TooltipOpenChangeReason> & { returnValue?: string | undefined; }) | undefined) => boolean`): Closes it. `returnValue` is passed to the promise `open()` returned. Returns false when the close was canceled or it was already closed.
|
|
737
|
+
- `toggle(options?)` (`(options?: PopupChangeOptions<TooltipOpenChangeReason> | undefined) => boolean`): Opens it when it's closed, and closes it when it's open. Returns false when the change was canceled.
|
|
738
|
+
- `getPayload()` (`() => Payload | undefined`): The payload of the last open, from a controller or the trigger that opened it.
|
|
739
|
+
- `focus()` (`() => void`): Moves focus to the trigger that opened it last, or the first trigger.
|
|
740
|
+
|
|
741
|
+
### Events
|
|
742
|
+
|
|
743
|
+
Events fire on their own element and don't bubble, with the new state in `event.detail.value` and the `reason` and `event` beside it. Calling `preventDefault()` on `openchange` cancels the change.
|
|
744
|
+
|
|
745
|
+
| Member | On | Description |
|
|
746
|
+
| -------------------------- | -------------------- | ------------------------------------------------------------------------------- |
|
|
747
|
+
| `open` property, attribute | `ui-tooltip` | Whether the tooltip is open. The attribute sets where it starts, and is live |
|
|
748
|
+
| `api` property | `ui-tooltip` | The [controller](#controller) |
|
|
749
|
+
| `openchange` event | `ui-tooltip` | `detail: { value: open, reason, event }` |
|
|
750
|
+
| `openchangecomplete` event | `ui-tooltip` | `detail: { value: open }`, after the animation |
|
|
751
|
+
| `payloadchange` event | `ui-tooltip` | `detail: { value: payload, reason, event }`, when the content's payload changes |
|
|
752
|
+
| `payload` property | `ui-tooltip-trigger` | Data for the content |
|
|
753
|
+
| `for` attribute | `ui-tooltip-trigger` | The `id` of a tooltip the trigger shows from outside it |
|
|
754
|
+
|
|
755
|
+
## Accessibility
|
|
756
|
+
|
|
757
|
+
The trigger is named or described by the tooltip, following the [WAI-ARIA tooltip pattern](https://www.w3.org/WAI/ARIA/apg/patterns/tooltip/). It opens on hover and on keyboard focus, and stays open while the pointer moves onto it.
|
|
758
|
+
|
|
759
|
+
### Keyboard
|
|
760
|
+
|
|
761
|
+
| Key | Does |
|
|
762
|
+
| ------------ | ---------------------------------------------------------------------------------------------- |
|
|
763
|
+
| Tab | Focus on the trigger opens the tooltip at once; focus leaving it closes the tooltip |
|
|
764
|
+
| Escape | Closes the tooltip and leaves focus on the trigger, without closing a dialog or menu around it |
|
|
765
|
+
| Enter, Space | Presses the trigger and closes the tooltip; on a `toggleable` trigger, opens and closes it |
|
|
766
|
+
|
|
767
|
+
### Tested Behavior
|
|
768
|
+
|
|
769
|
+
Every line below is an automated test.
|
|
770
|
+
|
|
771
|
+
**Pointer**
|
|
772
|
+
|
|
773
|
+
- Resting the pointer on the trigger opens the tooltip.
|
|
774
|
+
- The tooltip waits for its delay before opening.
|
|
775
|
+
- Leaving the trigger before the delay keeps the tooltip closed.
|
|
776
|
+
- Moving the pointer away closes the tooltip.
|
|
777
|
+
- The pointer can move onto the tooltip without closing it.
|
|
778
|
+
- Opening on hover leaves focus where it was.
|
|
779
|
+
- Pressing the trigger closes the tooltip and runs the button.
|
|
780
|
+
- After a press, the tooltip stays closed until the pointer comes back.
|
|
781
|
+
|
|
782
|
+
**Keyboard**
|
|
783
|
+
|
|
784
|
+
- Keyboard focus on the trigger opens the tooltip.
|
|
785
|
+
- Focus leaving the trigger closes the tooltip.
|
|
786
|
+
- Escape closes the tooltip and leaves focus on the trigger.
|
|
787
|
+
- Escape closes a tooltip opened by hover.
|
|
788
|
+
- Tab through the toolbar shows each tooltip in turn.
|
|
789
|
+
- A click that focuses the trigger doesn't open the tooltip from focus.
|
|
790
|
+
|
|
791
|
+
**Several tooltips**
|
|
792
|
+
|
|
793
|
+
- Only one tooltip is open at a time.
|
|
794
|
+
- Once the pointer has been away a while, the delay applies again.
|
|
795
|
+
|
|
796
|
+
**Positioning**
|
|
797
|
+
|
|
798
|
+
- The tooltip opens above the trigger.
|
|
799
|
+
- The tooltip flips below the trigger when there is no room above.
|
|
800
|
+
- The tooltip opens on the requested side.
|
|
801
|
+
- The arrow points at the middle of the trigger.
|
|
802
|
+
|
|
803
|
+
**A tooltip on a popover trigger**
|
|
804
|
+
|
|
805
|
+
- Hovering shows the tooltip, and pressing opens the popover instead.
|
|
806
|
+
- Escape closes the tooltip and leaves the popover open.
|
|
807
|
+
|
|
808
|
+
**Disabled buttons**
|
|
809
|
+
|
|
810
|
+
- Browsers send hover events to a disabled button.
|
|
811
|
+
- An aria-disabled trigger shows its tooltip on hover and focus and ignores presses.
|
|
812
|
+
|
|
813
|
+
**Animation**
|
|
814
|
+
|
|
815
|
+
- The tooltip animates in from its starting style.
|
|
816
|
+
- The tooltip stays in the page while it animates out.
|
|
817
|
+
|
|
818
|
+
**Hidden while closed**
|
|
819
|
+
|
|
820
|
+
- A class that sets display on the content doesn't show it while closed.
|
|
821
|
+
|
|
822
|
+
**Options and dismissal**
|
|
823
|
+
|
|
824
|
+
- Escape closes only a tooltip that keyboard focus opened inside a popover.
|
|
825
|
+
- The pointer can leave the trigger sideways on its way to the tooltip.
|
|
826
|
+
- With closeOnPress false, pressing the trigger keeps the tooltip open.
|
|
827
|
+
- Disabled tooltips never open.
|
|
828
|
+
- A tap on a plain tooltip's trigger only presses it.
|
|
829
|
+
|
|
830
|
+
Runs in React, Vue and web components.
|
|
831
|
+
|
|
832
|
+
Also tested:
|
|
833
|
+
|
|
834
|
+
**Enhancements**
|
|
835
|
+
|
|
836
|
+
- Focus returning to the trigger after its popover closes doesn't reopen the tooltip.
|
|
837
|
+
- Tooltips open at once after another one, without a provider.
|
|
838
|
+
- Focus coming back with the window doesn't reopen the tooltip.
|
|
839
|
+
- A controller opens the tooltip without moving focus.
|
|
840
|
+
- A trigger that's a disabled button warns in development.
|
|
841
|
+
|
|
842
|
+
**Shortcuts**
|
|
843
|
+
|
|
844
|
+
- A trigger connected through a controller shows its tooltip's shortcut in a Shortcut part.
|
|
845
|
+
|
|
846
|
+
**Toggleable**
|
|
847
|
+
|
|
848
|
+
- Pressing a toggleable trigger opens and closes the tooltip.
|
|
849
|
+
- Pressing outside closes a toggleable tooltip.
|
|
850
|
+
- Enter toggles the tooltip from the keyboard and keeps focus on the trigger.
|
|
851
|
+
- A press announces the tooltip's text to screen readers.
|
|
852
|
+
- A tap opens a toggleable tooltip on a touch screen.
|
|
853
|
+
|
|
854
|
+
Runs in React, Vue and web components.
|
|
855
|
+
|
|
856
|
+
Screen readers hear the same thing in each tested framework, recorded by a virtual screen reader:
|
|
857
|
+
|
|
858
|
+
- Announcements while tabbing through triggers with tooltips.
|
|
859
|
+
|
|
860
|
+
Runs in React, Vue and web components.
|