chrome

<tc-popover>

Click-triggered floating panel anchored to a slotted trigger. Outside-click and Esc close, auto-flips on overflow. Top-layer rendering.

import "@ra9/tan-compose-kit/popover"

Props

NameTypeDefaultDescription
openbooleanfalseWhether the popover is showing. Reflects to the `open` attribute.
placement"top" | "bottom" | "left" | "right""bottom"Preferred side. Auto-flips when there isn't room.
offsetnumber8Gap between trigger and panel, in pixels.
dismissiblebooleantrueClose on outside click and Esc.

Events

EventDetailWhen
tc-openFires when the popover opens.
tc-close{ reason: "outside" | "escape" | "trigger" | "api" }Fires when the popover closes. `reason` reports what dismissed it.

Slots

SlotDescription
triggerThe element that toggles the popover when clicked.
(default)Popover content.

CSS variables

VariableDefaultDescription
--tc-popover-bgvar(--tc-color-surface, #ffffff)Panel background.
--tc-popover-fgvar(--tc-color-ink, #14171f)Panel text color.
--tc-popover-rulevar(--tc-color-rule, #ece5d3)Border color.
--tc-popover-radiusvar(--tc-radius-md, 8px)Corner radius.
--tc-popover-shadowvar(--tc-shadow-lg, …)Drop shadow.
--tc-popover-padding12px 14pxInner padding.
--tc-popover-min-width200pxMinimum width.
--tc-popover-max-width340pxMaximum width.

Examples

Basic

Profile ▾
Mia Carter mia@example.com
Account settings Sign out
<tc-popover> <tc-button slot="trigger">Profile ▾</tc-button> <strong>Mia Carter</strong> <span>mia@example.com</span> <hr> <a href="#">Account settings</a> <a href="#">Sign out</a> </tc-popover>

Placement

Top Above Bottom Below Left Left of Right Right of

Filter form

Popovers shine for compact forms anchored to a trigger — date pickers, filter pills, formatting toolbars.

Filter
Status
Reset Apply

Non-dismissible

Use dismissible="false" for confirmation flows where you want the user to make a choice rather than dismiss by clicking away.

<tc-popover dismissible="false" id="confirmDelete"> <tc-button slot="trigger" variant="danger">Delete row…</tc-button> <div style="display:grid;gap:10px;"> <p>This can't be undone.</p> <div style="display:flex;gap:8px;justify-content:flex-end;"> <tc-button variant="ghost" size="sm" onclick="this.closest('tc-popover').open=false">Cancel</tc-button> <tc-button variant="danger" size="sm">Delete</tc-button> </div> </div> </tc-popover>

Controlled

<tc-popover id="menu"> <tc-button slot="trigger">Open</tc-button> <div>…</div> </tc-popover> <script> const p = document.getElementById("menu"); document.querySelector("#external").addEventListener("click", () => { p.open = !p.open; }); p.addEventListener("tc-close", (e) => console.log("closed because:", e.detail.reason)); </script>

Accessibility

  • The panel has role="dialog". Use it for short interactive surfaces. For long-form modal flows, prefer <tc-modal>.
  • Esc and outside click both close (unless dismissible="false").
  • Trigger uses any element you slot in. Make sure it's a real <button> or has role="button" and tabindex="0" for keyboard activation.
  • The popover renders in the browser top-layer, so it sits above transform, backdrop-filter, and overflow: hidden ancestors.

Theming

<tc-popover style=" --tc-popover-bg: #14171f; --tc-popover-fg: #f5f5f5; --tc-popover-rule: #2a2f3a; --tc-popover-radius: 12px; --tc-popover-padding: 16px; " > <tc-button slot="trigger">Dark popover</tc-button> <div>Inverted surface.</div> </tc-popover>