Basic Popover
A click-triggered panel anchored to its button, with Escape and outside-click dismiss.
6 个框架中级
A hint that opens on hover AND keyboard focus, with role="tooltip" and aria-describedby.
<!--
Read the listeners before the CSS. There are FOUR of them, in two pairs:
mouseenter / mouseleave the mouse user
focus / blur everyone else
A tooltip bound to hover alone is invisible to a keyboard user, and hover
cannot be produced by a touch screen at all. The focus pair is not an
enhancement; it is half the component. This is why a CSS :hover-only tooltip
is a bug however elegant it looks.
aria-describedby is what makes the text reach a screen reader. Without it the
tooltip is a floating div that happens to be near a button, semantically
unrelated to it. The tooltip's own role="tooltip" gives it the right
announcement; the id link is what gets it announced at all.
Escape dismisses it even while hovered - per APG, a tooltip covering the thing
you are trying to read must be dismissable without moving the pointer.
-->
<span class="tip">
<button class="tip__trigger" type="button" aria-describedby="tip-1">
Retention
</button>
<span class="tip__bubble" id="tip-1" role="tooltip">
Deleted items are recoverable for 30 days.
</span>
</span>
<script>
document.querySelectorAll('.tip').forEach(function (root) {
var trigger = root.querySelector('.tip__trigger');
var bubble = root.querySelector('.tip__bubble');
var timer = null;
function show() {
// A short delay keeps the tooltip from strobing as the pointer crosses a
// row of controls on its way somewhere else.
timer = window.setTimeout(function () {
bubble.classList.add('tip__bubble--in');
}, 150);
}
function hide() {
window.clearTimeout(timer);
bubble.classList.remove('tip__bubble--in');
}
// Pointer.
trigger.addEventListener('mouseenter', show);
trigger.addEventListener('mouseleave', hide);
// Keyboard. Same handlers - the tooltip cannot tell how you arrived.
trigger.addEventListener('focus', show);
trigger.addEventListener('blur', hide);
trigger.addEventListener('keydown', function (event) {
if (event.key === 'Escape') hide();
});
});
</script>| Prop | 类型 | 默认值 | 说明 |
|---|---|---|---|
text必填 | string | - | 按下按钮时写入剪贴板的字符串。 |
children必填 | ReactNode | - | 在组件内部渲染的内容。 |
delay | number | 150 | 入场动画前等待的秒数。 |
className | string | - | 合并到根元素上的额外类名。 |
The hover-only tooltip is the most common accessibility regression on the web: it works perfectly for the person who wrote it and does not exist for anyone navigating by keyboard - or on any touch screen, which cannot produce hover at all. So there are four listeners in two pairs: `mouseenter`/`mouseleave` and `focus`/`blur`. The focus pair is not an enhancement, it is half the component. `aria-describedby` is the other half: without that id link the bubble is a floating div that happens to sit near a button, semantically unrelated to it. It is hidden with `visibility`, never `display: none`, because a display:none element leaves the accessibility tree and takes the description with it. Escape dismisses it even while hovered - per APG, a bubble may be covering the very thing you are trying to read. Keep it plain text: a tooltip may not contain interactive content (reach for `popover-rich-content` instead). Tune `delay` to stop it strobing as the pointer crosses a row of controls.