20 CSS Popovers
20 hand-coded CSS popovers built on the native Popover API and CSS Anchor Positioning — no positioning library, no z-index wrangling. Covers declarative show and hide with popovertarget, auto versus manual dismissal, tethering panels with position-anchor, position-area placement, flip fallbacks near the viewport edge, entry and exit animation with @starting-style, and real surfaces like listboxes, profile flyouts and filter menus. Scoped under .pop-NN for no-collision pasting, prefers-reduced-motion guarded, framework-agnostic.
Related21 CSS Tooltips22 CSS Dropdown Menu Designs36 CSS Modals20 CSS Custom Select Dropdowns20 Tailwind CSS Popovers
Course pickPartner: Zero to Mastery
Affiliate linkWant to build production-ready CSS layouts, animations and UI from scratch?
You just browsed 20 popovers. Learn the Flexbox, Grid and animation thinking behind them, so the next component starts in your head, not in a copy-paste.
Every ZTM course in one membership: $25/month, paid yearly at $299 · 30‑day money-back guarantee
The CSS Bootcamp. We may earn a commission, at no extra cost to you.
02. Auto vs Manual Popover Behavior (opens in a new tab)
03. Basic Anchored Popover (opens in a new tab)
04. Discrete Entry and Exit Animations (opens in a new tab)
05. Custom Backdrop and Light Dismiss (opens in a new tab)
06. Grid Placement with Position Area (opens in a new tab)
07. Flip and Fallback Positions (opens in a new tab)
08. Tooltip Arrow Pointing to Anchor (opens in a new tab)
09. Match Anchor Width for Dropdowns (opens in a new tab)
10. Submenus and Nested Popovers (opens in a new tab)
11. Custom Select Listbox Popover (opens in a new tab)
12. Tooltip on Hover and Focus (opens in a new tab)
13. User Profile Flyout Menu (opens in a new tab)
14. Date Picker Popover Panel (opens in a new tab)
15. Popover Menu with Checkbox Filters (opens in a new tab)
16. Cross Browser Fallback and Polyfill (opens in a new tab)
17. Popover vs Dialog Showcase (opens in a new tab)
18. Glassmorphic Popover Overlay (opens in a new tab)
19. Dark and Light Mode Popover (opens in a new tab)
20. Accessible Tooltip with ARIA Roles (opens in a new tab)
Frequently asked questions
How does the HTML Popover API work?
popover on the element you want to float and popovertarget="its-id" on the button that opens it — that is the whole setup. The browser then hands you four behaviours for free that people used to write libraries for: the panel is promoted to the top layer, so it escapes any ancestor with overflow: hidden and ignores z-index entirely; clicking outside closes it; Escape closes it; and focus returns to the trigger on close. The top-layer behaviour is the one that changes how you build. A dropdown inside a scrolling table or a transformed card used to require portalling the panel to the end of the body to stop it being clipped — with popover the element stays where it belongs in your markup and still renders above everything. Pair it with popovertargetaction="show" or "hide" when you want a dedicated open or close control rather than a toggle.What is the difference between popover auto and popover manual?
popover="auto" (the default, so bare popover means the same thing) is dismissive: clicking outside closes it, Escape closes it, and opening a second auto popover force-closes the first unless they are nested. That is what you want for a menu, a tooltip or a profile flyout — the user should be able to click away and carry on. popover="manual" opts out of all of it. Nothing closes it except an explicit popovertargetaction="hide" button or a hidePopover() call, and several manual popovers can sit open at once. Reach for manual when closing would lose work: a filter menu the user is ticking several boxes in, a persistent panel, an inline editor. The mistake is choosing manual because auto felt unpredictable — if a menu keeps vanishing when you open another, that is nesting being declared wrongly rather than a reason to abandon the light-dismiss behaviour you actually want.How do I position a popover next to its button with CSS?
anchor-name: --my-anchor, give the panel position-anchor: --my-anchor, then place it with position-area — a nine-cell grid around the anchor, so position-area: block-end puts the panel below and block-start inline-end puts it above and to the right. This is what replaces the measure-on-scroll-and-resize loop that Popper and Floating UI exist to run. Two things to know. Anchor names are global, so scope them per component or two instances of the same widget will fight over the same name. And support for anchor positioning lags support for popover itself — a browser can have one without the other, so gate them with separate @supports checks and let the panel fall back to a plain absolutely-positioned element rather than assuming both arrived together.Why does my popover animation not work?
display: none and the top layer, and neither transitions by default. The recipe has three parts and missing any one of them silently breaks it. First, @starting-style declares the values the element animates FROM on first paint — without it there is no starting point and the panel just appears. Second, transition-behavior: allow-discrete lets discrete properties like display participate in the transition instead of flipping instantly. Third — and this is the one almost everyone misses — you must include overlay in the transition property list, because overlay is what keeps the element in the top layer; without it the panel drops out of the top layer the moment closing starts and the exit animation plays behind everything else on the page. One ordering trap: the @starting-style rule has to come after the open-state rule it refers to, or it loses the cascade and does nothing.How do I stop a popover from being cut off at the edge of the screen?
position-try-fallbacks. Declare the alternatives you will accept — flip-block, flip-inline, or both — and the browser tries the preferred position-area first, then each fallback in order until one fits the viewport. For finer control, write a named @position-try block with its own placement and margins and reference it by name. Two details make it work in practice. The fallback only fires when the panel would genuinely overflow, so test it with the anchor pushed close to an edge rather than in the middle of a comfortable layout. And anything visually tied to the anchor — a tooltip arrow especially — has to be positioned against the anchor rather than the panel, or it stays pointing the original direction after the panel flips and ends up detached, which looks worse than no arrow at all.Should I use popover or the dialog element?
<dialog> with showModal() when they must deal with it first: focus is trapped inside, the rest of the page goes inert, and the backdrop blocks interaction. That is right for a destructive confirmation, a required form, a blocking flow. Use popover when they can look at it and carry on: menus, tooltips, flyouts, filter panels, notifications. Focus is not trapped, the page stays interactive, and clicking elsewhere dismisses it. The common error is reaching for a modal because it is the pattern you know, and trapping a user inside a dropdown they only wanted to glance at. The features do overlap — a <dialog> can carry a popover attribute for non-modal use — but treat modality as the deciding question and the choice is usually obvious.Is the Popover API accessible by default?
aria-expanded on the trigger and keep it in sync, because nothing does that for you and a screen reader user otherwise has no idea whether the panel is open. Give the panel the role its content deserves: menu with menuitem children for a menu, listbox with option children for a select. And if the panel is a hint describing the trigger, wire aria-describedby rather than using role="tooltip" on something click-triggered, which contradicts what a tooltip is. Keyboard navigation inside the panel — arrow keys, typeahead, roving tabindex — is still yours to implement.How do these port to React, Vue, Svelte and Tailwind?
popover and popovertarget are plain attributes, so they pass straight through JSX and templates. React needs one accommodation — attribute casing. Write popover="auto" and popoverTarget in JSX, and note that React versions before 19 did not pass unknown attributes through cleanly, so on older versions you may need ref plus setAttribute. Where you do call the imperative methods, guard them: showPopover() and hidePopover() throw if the element is not in the document or not currently in the required state, so wrap them in try/catch or check matches(':popover-open') first. In Next or Nuxt, feature detection must run in an effect rather than the component body, since HTMLElement does not exist during the server pass. For Tailwind the panel is a short utility chain plus the open: and starting: variants.Related collections
30 CSS Badges
30 hand-coded CSS badges for status indicators, notifications, membership tiers, live-data displays, and SEO / DevOps / financial dashboards — upload progress, typing indicator, transit line status, Core Web Vitals, ECG heartbeat, CI/CD build pipeline, countdown ring, live price ticker, keycap shortcut, wax seal, conference lanyard, and holographic collectibles. Copy-paste HTML and CSS, WCAG 2.2 accessible, MIT licensed.
20 CSS Banners & Alerts
20 hand-coded CSS banner and alert bars for e-commerce storefronts, SaaS dashboards, marketing sites, and compliance-bound products. Covers GDPR cookie consent with a real preferences panel, promo bars with countdown timers, free-shipping threshold progress, app-install smart banners, maintenance and incident status bars, newsletter signup bars, age verification gates, limited-stock urgency banners, live event announcements, browser upgrade notices, geo and currency switchers, sticky top announcement bars, bottom cookie bars, inline form validation alerts, icon-aligned alert banners, left-border accent alerts, diagonal stripe promos, full-width hero banners, animated gradient border alerts, and a text-wrapping laboratory that shows five strategies for the unbreakable string that breaks more banners than anything else. Every bar is scoped under a .ba-NN prefix for no-collision pasting, guards prefers-reduced-motion, carries the correct aria-live and role semantics, and ports unchanged to React, Vue, Svelte, Astro, Next.js and Tailwind.
25 CSS Blockquotes
25 CSS blockquotes for article pull quotes, testimonial cards, docs callout admonitions, statement banners, and social-post embeds. Covers giant decorative quotation marks, minimalist hairline and classic left borders, animated gradient and glowing neon borders, glassmorphism and aurora backgrounds, brutalist cards, speech bubbles, thick accent rails, highlighted mark text, newspaper multi-column layouts, an expandable read-more disclosure, a scroll-snap testimonial slider, and one-click copy.



















