Basic Popover
A click-triggered panel anchored to its button, with Escape and outside-click dismiss.
6 個のフレームワーク中級
A bell trigger with an announced unread count, opening a dialog list of notifications.
<div class="relative inline-block">
<!-- The unread count is announced via aria-label, not just painted on a badge. -->
<button type="button" aria-haspopup="dialog" aria-expanded="true" aria-controls="pnotif-panel" aria-label="Notifications, 2 unread" class="relative rounded-lg border border-gray-300 bg-white p-2 text-gray-700 hover:bg-gray-50 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-blue-600 focus-visible:ring-offset-2 focus-visible:ring-offset-white dark:border-gray-700 dark:bg-gray-900 dark:text-gray-300 dark:hover:bg-gray-800 dark:focus-visible:ring-blue-400 dark:focus-visible:ring-offset-gray-900">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" class="h-5 w-5" aria-hidden="true"><path stroke-linecap="round" stroke-linejoin="round" d="M15 17h5l-1.4-1.4A2 2 0 0 1 18 14.2V11a6 6 0 0 0-4-5.7V5a2 2 0 1 0-4 0v.3A6 6 0 0 0 6 11v3.2a2 2 0 0 1-.6 1.4L4 17h5m6 0v1a3 3 0 0 1-6 0v-1m6 0H9" /></svg>
<span aria-hidden="true" class="absolute -right-1 -top-1 flex h-4 min-w-4 items-center justify-center rounded-full bg-red-600 px-1 text-[0.6rem] font-semibold text-white">2</span>
</button>
<!-- right-0: a top-right bell would run a left-anchored panel off-screen. -->
<div id="pnotif-panel" role="dialog" aria-labelledby="pnotif-title" class="absolute right-0 top-[calc(100%+0.5rem)] z-20 w-72 max-w-[calc(100vw-2rem)] rounded-xl border border-gray-200 bg-white p-2 shadow-lg dark:border-gray-700 dark:bg-gray-900">
<div class="flex items-center justify-between px-2 py-1">
<h3 id="pnotif-title" class="text-sm font-semibold text-gray-900 dark:text-gray-100">Notifications</h3>
<button type="button" class="rounded text-xs font-medium text-blue-700 hover:underline focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-blue-600 dark:text-blue-300 dark:focus-visible:ring-blue-400">Mark all read</button>
</div>
<ul class="mt-1 flex flex-col">
<li>
<button type="button" class="flex w-full items-start gap-2 rounded-md px-2 py-2 text-left hover:bg-gray-100 focus-visible:bg-gray-100 focus-visible:outline-none dark:hover:bg-gray-800 dark:focus-visible:bg-gray-800">
<span aria-hidden="true" class="mt-1.5 h-2 w-2 shrink-0 rounded-full bg-blue-600 dark:bg-blue-400"></span>
<span class="min-w-0">
<span class="block text-sm text-gray-800 dark:text-gray-200">Mara approved your pull request</span>
<span class="block text-xs text-gray-500 dark:text-gray-400">2m ago</span>
</span>
</button>
</li>
</ul>
</div>
</div>| Prop | 型 | デフォルト | 説明 |
|---|---|---|---|
label必須 | string | - | 読み込み中に読み上げられるアクセシブルなラベル。 |
notes必須 | ReadonlyArray<{ id: string; title: string; time: string; unread: boolean }> | - | Notes |
onMarkAllRead | () => void | - | On mark all read |
A bell whose unread count is announced via `aria-label` (`"Notifications, 2 unread"`), not just painted on the badge. It opens a `role="dialog"` list with a "Mark all read" action that disables itself at zero. The panel anchors to the trigger's RIGHT edge (`right-0`) because a top-right bell would run a left-anchored panel off-screen, and stays inside the viewport with `max-w-[calc(100vw-2rem)]`. Escape closes and restores focus.