Popover
A popover is a floating content container that appears relative to a trigger element. Popovers display richer, persistent content that requires explicit user interaction (click or tap), while tooltips appear automatically on hover or focus with brief, contextual information.
Ready to use
Tooltip and Popover share the same component base. Both display contextual information, but their behaviour and purpose differ. A Tooltip offers short contextual hints that appear on hover or focus and disappear automatically; a Popover is a persistent overlay that provides extra information or actions — links, preferences — and stays open until dismissed.
Anatomy
Section titled “Anatomy”- Popover
- Arrow
- Bubble
- Icon Button (optional)
- Title (optional)
- Content
- Link (optional)
When to use it
Section titled “When to use it”Use a Tooltip when:
- You need to provide brief, contextual information about an element.
- The information clarifies a label, icon, or control without interrupting the flow.
- The content is short, non-essential, and disappears automatically.
Use a Popover when:
- You need to display additional information, options, or actions that require user interaction.
- The content is richer (title, link, button) and must persist until dismissed.
- The user needs time to read or interact before closing.
Avoid both when:
- The content is critical to completing a task — use a Modal instead.
- The message is too long to fit in a small floating container.
- The user might miss the message because of automatic disappearance or poor trigger placement.
Properties
Section titled “Properties”Variant
Tooltip for hover/focus-triggered hints (no close button, no link). Popover for click/tap-triggered overlays (includes a close button, optional title, and optional link). Both share the same bubble, padding, and elevation.
Arrow placement
Top, Bottom, Left, or Right — but actual placement adjusts dynamically based on context. The arrow can live anywhere along the bubble’s perimeter (top-left, bottom-centre, right-top), not just the four cardinal positions; the predefined directions are visual references.
Contrast
Two variants for legibility across surfaces: Contrast (True) uses a dark bubble for use on light backgrounds (default), Contrast (False) uses a light bubble for dark or overlay surfaces. Behaviour, spacing, and accessibility rules stay identical.
Content slot
The replaceable slot accepts custom content such as energy labels, formatted text, or component instances. Any interactive element inside follows the system’s touch-area and focus-order rules.
Width
The bubble uses hug-content auto layout with a 150 px minimum and a 320 px maximum, so short labels and longer translations both fit without truncation or horizontal scroll.
Platform considerations
Section titled “Platform considerations”Desktop
Use both Tooltip and Popover here. Tooltips trigger on hover or focus and disappear on blur or Escape; Popovers trigger on click and persist until dismissed.
Tablet
Mixed input — Popovers work well for click/tap actions. Tooltips become less reliable as hover affordances disappear; reserve them for keyboard-focusable controls.
Mobile
Avoid Tooltips entirely (no reliable hover). Replace Popovers with a Bottom Sheet (modal-style overlay) to keep accessibility and usability intact on touch interfaces. The Bottom Sheet keeps the same hierarchy and purpose but adapts the layout for smaller viewports.
Best practices
Section titled “Best practices”Pick the variant that matches the interaction model — Tooltips for hints, Popovers for actions.
Do
Use Tooltips for short, non-interactive explanations triggered on hover or focus, use Popovers for extended or actionable content, replace both with a Bottom Sheet on mobile, ensure clear close and dismissal actions for Popovers with proper focus management, position the arrow so it clearly references the trigger, and maintain consistent spacing and elevation across brands.
Don't
Don’t include interactive elements inside Tooltips (they must disappear when focus or hover is lost), don’t use Tooltips on mobile, don’t put critical task content inside either component (use a Modal), and don’t position the bubble so the arrow doesn’t clearly point back to the trigger.
Content guidelines
Section titled “Content guidelines”Keep Tooltip copy to a short sentence or phrase (max 80–100 characters in English), use simple punctuation and sentence case, and avoid formatting, links, or interactive elements inside them. Popovers can hold longer content with titles and links — aim for up to 300–350 characters and reach for a Modal or side panel if the copy keeps growing. Both components should resize vertically or horizontally for longer languages (German, Finnish), so avoid fixed text heights and check wrapping behaviour at mobile and tablet widths. Keep the title > body > link hierarchy regardless of language so the announcement order stays predictable.
Styles
Section titled “Styles”A popover is a floating content container that appears relative to a trigger element.
<div class="tng-popover is-contrast"> <div class="tng-popover-bubble"> <p class="tng-text-body">…</p> </div></div>Sit sit occaecat minim aute tempor veniam Lorem non et anim. Id in quis eiusmod ea velit sit qui aute cillum aliquip ad aliqua ex. Proident irure proident labore occaecat ex velit Lorem.
Sit sit occaecat minim aute tempor veniam Lorem non et anim. Id in quis eiusmod ea velit sit qui aute cillum aliquip ad aliqua ex. Proident irure proident labore occaecat ex velit Lorem.
Elements
Section titled “Elements”An arrow can be placed at top, right, bottom or left using the data-placement attribute.
<div class="tng-popover is-contrast"> <div class="tng-popover-arrow" data-placement="top"></div> <div class="tng-popover-bubble"> <p class="tng-text-body">…</p> </div></div>Sit sit occaecat minim aute tempor veniam Lorem non et anim. Id in quis eiusmod ea velit sit qui aute cillum aliquip ad aliqua ex. Proident irure proident labore occaecat ex velit Lorem.
Sit sit occaecat minim aute tempor veniam Lorem non et anim. Id in quis eiusmod ea velit sit qui aute cillum aliquip ad aliqua ex. Proident irure proident labore occaecat ex velit Lorem.
Backdrop
Section titled “Backdrop”<div class="tng-backdrop"></div><div class="tng-popover is-contrast"> <div class="tng-popover-bubble"> <p class="tng-text-body">…</p> </div></div>Sit sit occaecat minim aute tempor veniam Lorem non et anim. Id in quis eiusmod ea velit sit qui aute cillum aliquip ad aliqua ex. Proident irure proident labore occaecat ex velit Lorem.
Sit sit occaecat minim aute tempor veniam Lorem non et anim. Id in quis eiusmod ea velit sit qui aute cillum aliquip ad aliqua ex. Proident irure proident labore occaecat ex velit Lorem.
Close button
Section titled “Close button”<div class="tng-popover is-contrast"> <div class="tng-popover-bubble"> <button class="tng-icon-button is-ghost" aria-label="Close"> <i class="tng-icon icon-close" aria-hidden="true"></i> </button> <p class="tng-text-body">…</p> </div></div>Sit sit occaecat minim aute tempor veniam Lorem non et anim. Id in quis eiusmod ea velit sit qui aute cillum aliquip ad aliqua ex. Proident irure proident labore occaecat ex velit Lorem.
Sit sit occaecat minim aute tempor veniam Lorem non et anim. Id in quis eiusmod ea velit sit qui aute cillum aliquip ad aliqua ex. Proident irure proident labore occaecat ex velit Lorem.
<div class="tng-popover is-contrast"> <div class="tng-popover-bubble"> <div class="tng-text-title">…</div> <p class="tng-text-body">…</p> </div></div>Sit sit occaecat minim aute tempor veniam Lorem non et anim. Id in quis eiusmod ea velit sit qui aute cillum aliquip ad aliqua ex. Proident irure proident labore occaecat ex velit Lorem.
Sit sit occaecat minim aute tempor veniam Lorem non et anim. Id in quis eiusmod ea velit sit qui aute cillum aliquip ad aliqua ex. Proident irure proident labore occaecat ex velit Lorem.
Compose the link with .is-neutral so it adopts the popover’s foreground colour instead of the default link blue.
<div class="tng-popover is-contrast"> <div class="tng-popover-bubble"> <p class="tng-text-body">…</p> <a class="tng-link is-neutral">Link</a> </div></div>Sit sit occaecat minim aute tempor veniam Lorem non et anim. Id in quis eiusmod ea velit sit qui aute cillum aliquip ad aliqua ex. Proident irure proident labore occaecat ex velit Lorem.
LinkSit sit occaecat minim aute tempor veniam Lorem non et anim. Id in quis eiusmod ea velit sit qui aute cillum aliquip ad aliqua ex. Proident irure proident labore occaecat ex velit Lorem.
LinkRecipes
Section titled “Recipes”Tooltip
Section titled “Tooltip”This is a tooltip.
Popover
Section titled “Popover”This is a popover with interactive content.
Popover
Section titled “Popover”The Popover is a provider component that displays rich interactive content when triggered by a click. Unlike tooltips which appear on hover, popovers require explicit user interaction to open and close.
This component must wrap PopoverTrigger and PopoverContent to function correctly.
Properties
Section titled “Properties”| Prop | Type | Description | Optional |
|---|---|---|---|
isContrast |
boolean |
Choose between dark or light version of the popover | ✅ |
initialOpen |
boolean |
Whether the popover is initially open, false by default |
✅ |
placement |
Placement |
Position of the popover relative to trigger (top, top-start, top-end | bottom, bottom-start, bottom-end | left, left-start, left-end | right, right-start, right-end). top by default |
✅ |
offset |
number |
Distance in pixels between trigger and tooltip, defaults to 8px | ✅ |
Example
Section titled “Example”import { Popover, PopoverTrigger, PopoverContent, IconButton,} from '@tmedxp/react-components';
const PopoverExample = () => { return ( <Popover placement="bottom" isContrast={false}> <PopoverTrigger> <IconButton iconName="info" size="sm" isNeutral /> </PopoverTrigger> <PopoverContent title="More Information" labels={{ Close: 'Close' }}> <p>This is detailed interactive content.</p> </PopoverContent> </Popover> );};
export { PopoverExample };PopoverTrigger
Section titled “PopoverTrigger”The PopoverTrigger component wraps an element that opens the popover when clicked. It toggles the popover’s visibility on each click.
Must be used within a Popover provider.
The children of this component must be an interactable element (button, link,..)
Example
Section titled “Example”import { Popover, PopoverTrigger, PopoverContent, IconButton,} from '@tmedxp/react-components';
const PopoverTriggerExample = () => { return ( <Popover placement="right"> <PopoverTrigger> <IconButton iconName="info" size="sm" isNeutral /> </PopoverTrigger> <PopoverContent title="Details" labels={{ Close: 'Close popover' }}> Click the icon to toggle this popover </PopoverContent> </Popover> );};
export { PopoverTriggerExample };PopoverContent
Section titled “PopoverContent”The PopoverContent component displays interactive content in a panel. It includes a close button, optional title, optional link button, and can render as a modal on mobile devices.
Must be used within a Popover provider.
Properties
Section titled “Properties”| Prop | Type | Description | Optional |
|---|---|---|---|
labels |
PopoverLabels |
Accessibility labels, requires Close property for close button |
❌ |
title |
string |
Optional title displayed at the top of the popover | ✅ |
linkProperties |
LinkProperties |
Optional link configuration displayed at the bottom | ✅ |
useModalOnMobile |
boolean |
Renders as a modal on mobile devices, false by default |
✅ |
className |
string |
Custom CSS class names for styling | ✅ |
hideCloseIcon |
boolean |
Show / hide the close icon. Visible by default. | ✅ |
Example
Section titled “Example”import { Popover, PopoverTrigger, PopoverContent, IconButton,} from '@tmedxp/react-components';
const PopoverContentExample = () => { return ( <Popover placement="bottom"> <PopoverTrigger> <IconButton iconName="info" size="sm" isNeutral /> </PopoverTrigger> <PopoverContent title="Additional Information" linkProperties={{ text: 'Learn More', href: '/more-info', }} useModalOnMobile={true} labels={{ Close: 'Close popover' }} > <p>This is detailed content with interactive elements.</p> <ul> <li>Feature 1</li> <li>Feature 2</li> </ul> </PopoverContent> </Popover> );};
export { PopoverContentExample };Tooltip
Section titled “Tooltip”The Tooltip is a provider component that displays short contextual hints on hover or focus. It manages the state and positioning of tooltips, ensuring proper coordination between the trigger element and tooltip content.
This component must wrap TooltipTrigger and TooltipContent to function correctly.
Properties
Section titled “Properties”| Prop | Type | Description | Optional |
|---|---|---|---|
isContrast |
boolean |
Choose between dark or light version of the tooltip | ✅ |
initialOpen |
boolean |
Whether the tooltip is initially open, false by default |
✅ |
placement |
Placement |
Position of the tooltip relative to trigger (top, top-start, top-end | bottom, bottom-start, bottom-end | left, left-start, left-end | right, right-start, right-end). top by default |
✅ |
offset |
number |
Distance in pixels between trigger and tooltip, defaults to 8px | ✅ |
Example
Section titled “Example”import { Tooltip, TooltipTrigger, TooltipContent, IconButton,} from '@tmedxp/react-components';
const TooltipExample = () => { return ( <Tooltip placement="top" isContrast={false}> <TooltipTrigger> <IconButton iconName="info" size="sm" isNeutral /> </TooltipTrigger> <TooltipContent>This is helpful information</TooltipContent> </Tooltip> );};
export { TooltipExample };TooltipTrigger
Section titled “TooltipTrigger”The TooltipTrigger component wraps an element that triggers the tooltip display. When the user hovers over or focuses on this element, the associated tooltip content appears.
Must be used within a Tooltip provider.
The children of this component must be an interactable element (button, link,…)
Example
Section titled “Example”import { Tooltip, TooltipTrigger, TooltipContent, IconButton,} from '@tmedxp/react-components';
const TooltipTriggerExample = () => { return ( <Tooltip placement="top"> <TooltipTrigger> <IconButton iconName="info" size="sm" isNeutral /> </TooltipTrigger> <TooltipContent>Helpful information appears here</TooltipContent> </Tooltip> );};
export { TooltipTriggerExample };TooltipContent
Section titled “TooltipContent”The TooltipContent component displays the actual content of the tooltip. It appears in a floating bubble with an arrow pointing to the trigger element. The content automatically positions itself relative to the trigger and viewport.
Must be used within a Tooltip provider.
Properties
Section titled “Properties”TooltipContentProperties extends HTMLProps<HTMLElement> which means it includes all standard HTML element attributes.
| Prop | Type | Description | Optional |
|---|---|---|---|
className |
string |
Custom CSS class names for styling | ✅ |
Example
Section titled “Example”import { Tooltip, TooltipTrigger, TooltipContent, IconButton,} from '@tmedxp/react-components';
const TooltipContentExample = () => { return ( <Tooltip placement="bottom" isContrast={true}> <TooltipTrigger> <IconButton iconName="help" size="sm" isNeutral /> </TooltipTrigger> <TooltipContent className="custom-tooltip"> <p>This is detailed information that helps the user.</p> <p>It can contain multiple elements.</p> </TooltipContent> </Tooltip> );};
export { TooltipContentExample };useTooltipContext hook
Section titled “useTooltipContext hook”The useTooltipContext hook provides access to the tooltip context, allowing child components to interact with the tooltip state and positioning. This hook must be used within a Tooltip or Popover provider component.
Returns
Section titled “Returns”The hook returns an object with the following properties:
| Property | Type | Description |
|---|---|---|
open |
boolean |
Current open/closed state of the tooltip |
setOpen |
(open: boolean) => void |
Function to programmatically open or close the tooltip |
This hook is primarily used internally by TooltipTrigger, TooltipContent, PopoverTrigger, and PopoverContent components but it can be used in custom components that need access to the tooltip state.
Example
Section titled “Example”import { useTooltipContext } from '@tmedxp/react-components';
const CustomText = () => { const { open } = useTooltipContext(); return <p>Tooltip is {open ? 'open' : 'closed'}</p>;};
const CustomComponent = () => { return ( <Popover> <CustomText /> <PopoverTrigger> <button>Toggle Tooltip</button> </PopoverTrigger> <PopoverContent> <span>Some text</span> </PopoverContent> </Popover> );};
export { CustomTooltipComponent };The popover follows the WAI-ARIA Disclosure pattern — a trigger that shows and hides additional content, with its open state exposed through aria-expanded — and meets WCAG 2.1 AA. It comes in two forms: a tooltip that reveals short, non-interactive text on hover or focus (the Tooltip pattern), and a popover that reveals a panel of interactive content on click. Both are non-modal: focus is never trapped, the trigger keeps or regains focus, and the browser weaves the content into the tab order rather than sealing the user inside it. An accessible popover stays reachable and dismissible from the keyboard, keeps assistive technology informed of its open state, and gives its trigger and content an accessible name.
For designers
Section titled “For designers”- Text, icons, and their background must maintain accessible contrast on every supported surface and in both the default and contrast (
is-contrast) themes. Source: WCAG 1.4.3 Contrast (Minimum). - State must never be conveyed by colour alone — pair it with text, an icon, or a shape. Source: WCAG 1.4.1 Use of Color.
- Focus styles must stay visible, meet contrast requirements on every supported surface, and be clearly distinguishable from hover. Source: WCAG 2.4.7 Focus Visible.
- Content that appears on hover or focus must be dismissable, hoverable, and persistent — a tooltip must survive the pointer moving toward it and stay until it is dismissed or focus leaves, never vanishing on a timer. Source: WCAG 1.4.13 Content on Hover or Focus.
- Position the arrow or pointer so it clearly references the triggering element, and keep enough spacing that the panel neither overlaps the trigger nor crowds nearby controls.
- Use semantic colour tokens (e.g.
foreground/neutral/default) rather than fixed values, so the component adapts correctly across themes and surfaces.
For developers
Section titled “For developers”Build both forms on the native HTML Popover API — the trigger carries popovertarget and the panel the popover attribute — so the browser handles the hard parts: it promotes the panel to the top layer, light-dismisses it on outside click or Escape, weaves it into the sequential tab order after the trigger, and restores focus to the trigger on close. This is deliberately non-modal, so do not add a focus trap or a manual focus-return. Use popover="auto" for the interactive popover and popover="hint" for the tooltip, so a tooltip can surface without dismissing an open popover. A tooltip holds only short, non-interactive text and never takes focus — if the content needs a link or button, use a popover instead. Keep decorative icons out of the accessibility tree with aria-hidden="true". Each element’s role, accessible name, and state are in the Labelling elements section below.
Keyboard interaction
Section titled “Keyboard interaction”| Key | Action |
|---|---|
| Enter / Space | With the trigger focused, open or close the popover |
| Escape | Dismiss the open popover or tooltip and return focus to the trigger |
| Tab / Shift + Tab | Move into the open popover and through its content, then on to the next / previous control — focus is never trapped |
A tooltip appears when its trigger receives focus (or hover) and hides on blur, pointer-leave, or Escape; it never receives focus itself. All triggers and controls must be fully operable from the keyboard. Source: WCAG 2.1.1 Keyboard. Interactive targets must be at least 44 px high for comfortable touch use — comfortably clearing the WCAG AA minimum. Source: WCAG 2.5.8 Target Size (Minimum).
Labelling elements
Section titled “Labelling elements”Give every element the role, name, and state assistive technology needs. The two forms share one design but carry different semantics, so they are documented separately — each demo stacks the trigger with the surface it opens.
Popover
Section titled “Popover”The interactive form: a role="dialog" panel of controls. Its content slot is a placeholder, since consumer-slotted content carries its own component’s semantics.
- Popover trigger
- Popover
- Close button
Popover trigger
A button carrying popovertarget to toggle the panel. Keep aria-expanded in sync with the open / closed state — the recipe updates it on the panel’s toggle event. Name an icon-only trigger with aria-label; otherwise its text content is its name.
Popover
role="dialog" on the panel. Name it with aria-labelledby pointing at the visible title, or aria-label when there is no title — a dialog with no name announces only as “dialog”.
Close button
An icon-only button with popovertarget set to the panel’s id so it closes the panel. Give it aria-label="Close"; its icon is decorative.
Tooltip
Section titled “Tooltip”The descriptive form: a role="tooltip" bubble of short, non-interactive text. The text is intrinsic and is the accessible description — there is no content slot and nothing inside takes focus.
Battery range is measured on the WLTP cycle.
- Tooltip trigger
- Tooltip
Tooltip trigger
Link the trigger to the tooltip with aria-describedby pointing at the tooltip’s id, so the text is announced as a description when the trigger is focused. Name an icon-only trigger with aria-label.
Tooltip
role="tooltip" on the bubble; its text content is the description. It is not focusable and takes no name of its own.
Source: WCAG 4.1.2 Name, Role, Value.