Basic Popover
A click-triggered panel anchored to its button, with Escape and outside-click dismiss.
6 फ्रेमवर्कमध्यम
A popover with a heading, body copy and an action - labelled by its own heading.
<!--
This is the point where a tooltip stops being viable. There is a button
inside, and a tooltip may not contain interactive content - you cannot hover
your way to a control that disappears when the pointer leaves the trigger.
So it is role="dialog", click-triggered, and labelled by its own heading via
aria-labelledby instead of a hand-written aria-label.
-->
<div class="rpop">
<button
class="rpop__trigger"
type="button"
aria-haspopup="dialog"
aria-expanded="false"
aria-controls="rpop-panel"
>
What is a seat?
</button>
<div
class="rpop__panel"
id="rpop-panel"
role="dialog"
aria-labelledby="rpop-title"
hidden
>
<h3 class="rpop__title" id="rpop-title">Seats and billing</h3>
<p class="rpop__copy">
A seat is one person with access to this workspace. Seats are billed
monthly and prorated the day someone joins.
</p>
<a class="rpop__cta" href="#billing">Read the billing guide</a>
</div>
</div>
<script>
document.querySelectorAll('.rpop').forEach(function (root) {
var trigger = root.querySelector('.rpop__trigger');
var panel = root.querySelector('.rpop__panel');
function setOpen(open) {
panel.hidden = !open;
trigger.setAttribute('aria-expanded', String(open));
}
trigger.addEventListener('click', function () {
var next = trigger.getAttribute('aria-expanded') !== 'true';
setOpen(next);
// Move into the panel on open: the reason this popover exists is the
// thing inside it, and Tab from the trigger should not have to walk past
// the rest of the page to get there.
if (next) root.querySelector('.rpop__cta').focus();
});
root.addEventListener('keydown', function (event) {
if (event.key !== 'Escape') return;
setOpen(false);
trigger.focus();
});
document.addEventListener('mousedown', function (event) {
if (!root.contains(event.target)) setOpen(false);
});
});
</script>| Prop | टाइप | डिफ़ॉल्ट | विवरण |
|---|---|---|---|
labelआवश्यक | string | - | लोड होते समय पढ़ा जाने वाला एक्सेसिबल लेबल। |
titleआवश्यक | string | - | कार्ड की हेडिंग टेक्स्ट। |
copyआवश्यक | string | - | टाइटल के नीचे दिखने वाला मुख्य टेक्स्ट। |
ctaLabel | string | 'Learn more' | कॉल-टू-एक्शन बटन का टेक्स्ट। |
onClick | () => void | - | जब यूज़र कंट्रोल को एक्टिवेट करता है तब फ़ायर होता है। |
The button inside is exactly why this is a `role="dialog"` and not a tooltip: a tooltip may not contain interactive content, because you cannot hover your way into a bubble that closes the moment the pointer leaves the trigger. That single fact decides the whole component - click-triggered, focus moved into the panel on open, `aria-labelledby` pointing at the visible `<h3>` rather than a hand-written `aria-label` that will drift from it. The focus move uses `requestAnimationFrame` because the panel does not exist until React commits the render. Note the link colour flips to `blue-300` on dark: `blue-700` is tuned for white and fails AA outright on a near-black panel.