The map's hover card: a small inverse card of the caller's words, placed against a point on the map or an element, shown while the pointer rests on a vehicle or a stop.
When to use
Use MapTooltip for a few words about a vehicle or a stop on the map, such as its line and destination, shown while a mouse pointer rests on it.
| Use instead | When |
|---|---|
| Tooltip | A short label names a control, shown on hover or keyboard focus |
| Popover | The card holds a link, a button or a field, or opens when a button is pressed |
| DetailPanel | The facts are for every reader, opened by selecting the vehicle or stop |
Kongens Nytorv
Metro M1, M2 and M3.
Props
| Name | Type | Default | Description |
|---|---|---|---|
children | ReactNode | — | The card's content: a few words on what is under the pointer, in sentence case, such as "Bus 5C to Husum". It takes the card's inverse text colour. |
anchorEl* | Element | VirtualElement | React.RefObject<Element | null> | (() => Element | VirtualElement | null) | null | — | Required. What the card sits against: a virtual element whose getBoundingClientRect() gives the point the map projects for a vehicle or stop, or an element. Pass a new one when the point moves, so the card follows. |
open | boolean | — | Whether the card is shown. Set it while the pointer rests on what the card describes, and clear it in onClose. |
defaultOpen | boolean | false | Whether the card is shown at first, when open is not set. |
onClose | (event, reason, details) => void | — | Called when the card asks to close: reason is 'escape-key' on Esc or 'outside-press' on a press outside it, and details.cancel() keeps it open. |
ref | Ref<HTMLDivElement> | — | Reaches the root, the card. |
slotProps | { portal?: TooltipPortalProps | undefined; positioner?: TooltipPositionerProps | undefined; } | — | Props for each part: portal, positioner. |
childrenReactNode, default —- The card's content: a few words on what is under the pointer, in sentence case, such as "Bus 5C to Husum". It takes the card's inverse text colour.
anchorEl (required)Element | VirtualElement | React.RefObject<Element | null> | (() => Element | VirtualElement | null) | null, default —- Required. What the card sits against: a virtual element whose
getBoundingClientRect()gives the point the map projects for a vehicle or stop, or an element. Pass a new one when the point moves, so the card follows. openboolean, default —- Whether the card is shown. Set it while the pointer rests on what the card describes, and clear it in
onClose. defaultOpenboolean, defaultfalse- Whether the card is shown at first, when
openis not set. onClose(event, reason, details) => void, default —- Called when the card asks to close:
reasonis'escape-key'on Esc or'outside-press'on a press outside it, anddetails.cancel()keeps it open. refRef<HTMLDivElement>, default —- Reaches the root, the card.
slotProps{ portal?: TooltipPortalProps | undefined; positioner?: TooltipPositionerProps | undefined; }, default —- Props for each part:
portal,positioner.
Use it
import { MapTooltip } from '@mylder/perron'Ask your agent
get_reference({ library: "base-ui", component: "Tooltip" })Keyboard and ARIA
From the Base UI reference for Tooltip and the installed TooltipRoot, TooltipPositioner, TooltipPopup and the dismiss hook they build on. "From" says who does it.
| Key | Does | From |
|---|---|---|
Escape | While the card is open, from anywhere in the document: calls onClose(event, 'escape-key', details); an uncontrolled card closes, a controlled one closes when the caller clears open | Base UI |
No other key: the card is out of the tab order (tabindex="-1") and holds no control, so Tab passes it by. Opening it from the keyboard is the map's, which moves focus between vehicles in the vehicle list rather than on the canvas.
The card keeps no role and stays in the accessibility tree, with neither role="tooltip" nor aria-hidden. Base UI sets no role on Tooltip.Popup, and role="tooltip" describes a trigger through aria-describedby, which the card has none of; left readable, a screen reader's reading cursor still finds its words, while the map's text alternative, the vehicle list, carries the same facts.
| Element | Role | Accessible name from | States announced |
|---|---|---|---|
positioner | presentation, from Base UI | none | none |
root | none: a <div> that reads as its text | none: its children are read as text | none |
What axe won't catch, from the contract, each with how this component meets it:
- Everything the eye is told, the ear is told, for every shape each prop accepts: the card shows only the caller's
children, read as text in the accessibility tree; it draws no mark, and the facts it shows are also in the vehicle list and the detail panel, the map's text alternative. - Every landmark and named region has an accessible name: none here; the card is not a landmark or a region.
- Every default label can be overridden: none here; the card owns no strings.
- Every shape the type accepts renders, in every variant:
childrenrenders a string, an element and a list alike, as theContentstory shows. - A hidden copy kept for animation is
aria-hidden, and a collapsed region isinert: none here; the card leaves the document when it closes, and Base UI makes the positionerinertwhile it is closed. - Native semantics first: a plain
<div>for words, with no role, since the card is neither a control nor a description tied to one. - Focus moves in reading order and returns on close: the card never takes focus, so opening and closing it leaves focus where it was.
- Every target is at least
size.target-minsquare: none here; the card takes no press. - Loops stop when the system asks for less motion: none here; the card has no loop and no transition.
Owned strings
No owned strings: every word on the card comes from the caller, as children.
Do and don't
For a caller using the component, with the reason. Each row is a rule: a must row's Don't is never right, a should row's needs a reason, and Checked by says what catches the Don't in a caller's code.
| Rule | Level | Do | Don't | Checked by |
|---|---|---|---|---|
| DD-1 | must | Open the card while a mouse pointer rests on a vehicle or a stop, and select it on a tap or a click, opening its detail panel | Open the card on touch: a tap has no hover, and Accessibility asks that anything shown on hover is also reached by selecting the item | review |
| DD-2 | must | Keep the card open while the pointer is over it, using the card's onPointerEnter and onPointerLeave, and close it in onClose | Close it the moment the pointer leaves the dot: Accessibility asks that a hover card stays while the pointer is over it | review |
| DD-3 | must | Give a few words: the line and its destination, the data state | Put a link, a button or a field in the card: it is out of the tab order, so the keys can't reach them; use a panel or a popover | review |
| DD-4 | should | Pass a new anchorEl when the vehicle moves, so the card moves with it | Expect the card to follow a moving point on its own: Base UI re-reads the anchor on scroll, resize and layout shift, not on every frame | review |
| DD-5 | must | Let the card's words take its inverse colour, and use components that draw their own colours on a fill, such as a line badge | Put text that sets its own secondary or tertiary colour in the card: those colours are measured on light surfaces, not on color.surface.inverse | review |
| DD-6 | must | Give the same facts in the vehicle list or the detail panel | Put anything only in the card: screen reader, keyboard and touch users never see it | review |
| DD-7 | should | Change the side through slotProps.positioner, such as side: 'bottom' | Move the card with a margin or a transform: Base UI's placement and flipping no longer match what is drawn | review |
| DD-8 | should | Show one card at a time | Open a card for each vehicle at once: the cards cover the map they describe | review |