Dana Fried | d8fac74 | 2024-07-08 17:55:02 | [diff] [blame] | 1 | # Help Bubbles |
| 2 | |
Dana Fried | 154c57f | 2024-10-23 17:21:58 | [diff] [blame] | 3 | [Help bubbles](./common/help_bubble/help_bubble.h) are the core visual component of both |
Dana Fried | d8fac74 | 2024-07-08 17:55:02 | [diff] [blame] | 4 | [IPH](./feature-promos.md) and [Tutorials](./tutorials.md). |
| 5 | |
| 6 | A help bubble is tinted bubble (blue in the default theme) with the following |
| 7 | elements: |
| 8 | - Text |
| 9 | - Title (optional) |
| 10 | - Icon (optional) |
| 11 | - Close button (X) |
| 12 | - Action buttons (typically between zero and two) |
| 13 | - Alternative and/or assist message for screen readers |
| 14 | |
| 15 | Most (but not all) help bubbles also have a visible arrow that points to the |
| 16 | _anchor element_ - the UI element the bubble refers to. For example, a promo for |
| 17 | a new button in the toolbar would have an arrow pointing to the button. |
| 18 | |
Dana Fried | 0aefb20 | 2025-03-14 15:57:35 | [diff] [blame] | 19 | You should be using the Feature Promo (IPH) or Tutorial Systems, |
| 20 | or [ShowPromoInPage](/chrome/browser/ui/user_education/show_promo_in_page.h) |
| 21 | or [StartutorialInPage](/chrome/browser/ui/user_education/start_tutorial_in_page.h) |
Dana Fried | d8fac74 | 2024-07-08 17:55:02 | [diff] [blame] | 22 | to display help bubbles. |
| 23 | |
Dana Fried | 0aefb20 | 2025-03-14 15:57:35 | [diff] [blame] | 24 | > Help bubbles can be created directly via a |
| 25 | [HelpBubbleFactory](./common/help_bubble/help_bubble_factory.h) and a |
| 26 | [HelpBubbleParams](./common/help_bubble/help_bubble_params.h) object, however, |
| 27 | it's bad form to create your own help bubbles directly unless you are 100% |
Dana Fried | d8fac74 | 2024-07-08 17:55:02 | [diff] [blame] | 28 | sure what you are doing! If you are tempted, please contact |
| 29 | [Frizzle Team](mailto:[email protected]) first and see if there's a more |
| 30 | idiomatic way to achieve your goal. |
| 31 | |
Dana Fried | 0aefb20 | 2025-03-14 15:57:35 | [diff] [blame] | 32 | You can also create [help bubbles with custom UI](./custom-help-bubbles.md) |
| 33 | which can be used for IPH when something other than a normal help bubble is |
| 34 | required (for example, a WebUI dialog with several links the user can click); |
| 35 | see that page for more information. |
| 36 | |
Dana Fried | d8fac74 | 2024-07-08 17:55:02 | [diff] [blame] | 37 | ## Help Bubble Arrows |
| 38 | |
| 39 | When creating an IPH or Tutorial experience, you will want to specify the arrow |
| 40 | for each bubble. This specifies where the little visible arrow that points to |
| 41 | the anchor goes on the help bubble, and by extension, how the help bubble itself |
| 42 | positions itself. |
| 43 | |
| 44 | For example if the arrow is `kTopRight`, then the arrow will be placed on top of |
| 45 | the help bubble, towards the right side of the bubble (left in RTL). This places |
| 46 | the help bubble below the anchor element, with the bulk of the bubble falling to |
| 47 | the left. Help bubbles can auto-reflect if they would fall outside the browser |
| 48 | window or the screen, but it's best to choose an arrow that maximizes the |
| 49 | likelihood that the bubble will fit, and minimizes interference with UI the user |
| 50 | will be trying to interact with. |
| 51 | |
| 52 | Your UX designer should have already determined the ideal arrow positioning in |
| 53 | their specifications; by default you should find the option that best matches |
| 54 | their design. |
| 55 | |
| 56 | ### "No Arrow" |
| 57 | |
| 58 | The `HelpBubbleArrow::kNone` option places the help bubble directly beneath the |
| 59 | anchor, with no visible arrow. This is almost always used with the |
| 60 | `kTopContainerElementId` element, which results in the help bubble sitting just |
| 61 | below the toolbar (or bookmarks bar if present), in the middle of the browser |
| 62 | window. Be careful when using this option, because it is the most obtrusive |
| 63 | position for a help bubble possible! |
| 64 | |
| 65 | ## Anchor Elements |
| 66 | |
| 67 | As mentioned above, any UI element may be an anchor. This is handled through the |
| 68 | [ElementTracker](/ui/base/interaction/element_tracker.h) system. This associates |
| 69 | a `TrackedElement` object with each UI element that is properly tagged with an |
| 70 | [ElementIdentifier](/ui/base/interaction/element_identifier.h) and visible to |
| 71 | the user. |
| 72 | |
| 73 | It is sufficient to assign an identifier; the tracker will do the rest. However, |
| 74 | note that a help bubble cannot show if the anchor element is not visible, as |
| 75 | there may be no corresponding `TrackedElement`. |
| 76 | |
| 77 | ### Creating and Assigning Identifiers |
| 78 | |
| 79 | Element identifiers are declared via macros such as |
| 80 | `DECLARE/DEFINE_ELEMENT_IDENTIFIER_VALUE()`. Convention is to put identifiers in |
| 81 | either |
| 82 | [`browser_element_identifiers.h`](/chrome/browser/ui/browser_element_identifiers.h)/[`.cc`](/chrome/browser/ui/browser_element_identifiers.cc) |
| 83 | or in the class which conceptually owns the identifier, using |
| 84 | `DECLARE/DEFINE_CLASS_ELEMENT_IDENTIFIER_VALUE()`. |
| 85 | |
| 86 | For most `View`s, assign an identifier via |
| 87 | `SetProperty(kElementIdentifierKey, <element_id>)`. For menu items (both Views |
| 88 | and Mac native context menus), use `SimpleMenuModel::SetElementIdentifierAt()`. |
| 89 | For WebUI elements, the process is more complex; see |
| 90 | [this documentation](./webui/README.md) for info. |
| 91 | |
| 92 | ### Element Contexts |
| 93 | |
| 94 | A concept you will run into when trying to anchor help bubbles is the |
| 95 | `ElementContext`. Each potential anchor element exists within a context, and |
| 96 | each help bubble will look for an anchor in a specific context or contexts. |
| 97 | |
| 98 | Contexts exist to handle cases where there are multiple browser windows, so that |
| 99 | the user cannot trigger a help bubble in a different window by accident. When |
| 100 | showing an IPH or Tutorial help bubble, the default is to look for the anchor in |
| 101 | the current context only. |
| 102 | |
| 103 | Contexts exist for: |
| 104 | - A browser or app window and all menus and secondary UI associated with that |
| 105 | window. |
| 106 | - A WebUI page. |
| 107 | - Some tab-modal dialogs. |
| 108 | |
| 109 | > The reason for the latter two being their own contexts is because tabs can be |
| 110 | moved between windows. This creates some complexity that will hopefully be |
| 111 | remedied with future updates. |
| 112 | |
| 113 | If you are trying to show a help bubble through either the IPH or Tutorials |
| 114 | system and the bubble is not appearing, consider whether the |
| 115 | `FeaturePromoSpecification` or tutorial step needs to explicitly specify "in any |
| 116 | context". This usually happens when attempting to show a help bubble anchored to |
| 117 | a WebUI page. |
| 118 | |
| 119 | ### Anchor Element Filters |
| 120 | |
| 121 | In some cases, you may be able to apply a "filter" function to the anchor of a |
| 122 | help bubble. What this means is that the eligible anchor element(s) (based on |
| 123 | identifier and context) will be passed to a function that can do _pretty much |
| 124 | anything_ and then return the actual anchor element. The returned element need |
| 125 | not be one of the initial elements found, and can be any UI element. |
| 126 | |
| 127 | Filters are often used for: |
| 128 | - Selecting one out of a set of dynamic items, such as tabs, that all share the |
| 129 | same identifier. |
| 130 | - Locating a UI element that was not assigned an identifier due to technical |
| 131 | limitations, such as specific rows of information in a cookies dialog. |
| 132 | - In this case, the initial anchor ID will usually be for the dialog or |
| 133 | container, and then the actual anchor is located from there. |
| 134 | - It is common to use `ElementTrackerViews::GetElementForView(..., true)` |
| 135 | in order to create a temporary TrackedElement for the actual anchor. |
| 136 | - This approach does not work well for non-Views elements. |
| 137 | |
| 138 | ## Available Help Bubble Implementations |
| 139 | |
| 140 | The help bubble infrastructure is presentation framework-agnostic. Currently, |
| 141 | the following help bubble types are supported in Chrome Desktop: |
| 142 | 1. Views help bubble anchored to a View |
| 143 | 2. Views help bubble anchored to a native Mac menu |
| 144 | 3. Views help bubble anchored to a WebUI element in a non-tab WebUI |
| 145 | 4. WebUI help bubble anchored to a WebUI element in a tab WebUI |
| 146 | |
| 147 | The correct type of help bubble implementation is chosen automatically based on |
| 148 | the anchor view. |
| 149 | |
| 150 | Some other platforms (e.g. ChromeOS) have created additional types of help |
| 151 | bubbles for specific applications; creating a new help bubble implementation |
| 152 | isn't particularly hard; see existing classes derived from |
Dana Fried | 154c57f | 2024-10-23 17:21:58 | [diff] [blame] | 153 | [HelpBubble](./common/help_bubble/help_bubble.h) and |
| 154 | [HelpBubbleFactory](./common/help_bubble/help_bubble_factory.h). |
Dana Fried | d8fac74 | 2024-07-08 17:55:02 | [diff] [blame] | 155 | |
| 156 | The key takeaway is that in the vast majority of User Education code, the logic |
| 157 | around help bubbles doesn't (and shouldn't!) care which factory or which help |
| 158 | bubble implementation is being used; all of the logic should be in the |
| 159 | factories. |
| 160 | |
| 161 | If you are considering extending help bubbles to new frameworks, feel free to |
| 162 | reach out to [Frizzle Team](mailto:[email protected]) for guidance. |