Working With Multiple CSS Anchors And Popovers Inside The WordPress Loop
CSS-Tricks
·
Feb 19, 2025
·
article
I know, _super_ niche, but it could be any loop, really. The challenge is having multiple tooltips on the same page that make use of the [Popover API](https://css-tricks.com/poppin-in/) for toggling goodness and [CSS Anchor Positioning](https://css-tricks.com/css-anchor-positioning-guide/) for attaching a tooltip to its respective anchor element.
There’s plenty of moving pieces when working with popovers:
* A `popover` needs an ID ([and an accessible role](https://css-tricks.com/tooltip-best-practices/) while we’re at it).
* A `popovertarget` needs to reference that ID.
* IDs have to be unique for semantics, yes, but also to hook a `popover` into a `popovertarget`.
That’s just the part dealing with the Popover API. Turning to anchors:
* An anchor needs an `anchor-name`.
* A target element needs to reference that `anchor-name`.
* Each `anchor-name` must be unique to attach the target to its anchor properly.
The requirements themselves are challenging. But it’s more challenging working inside a loop because you need a way to generate unique IDs and anchor names so everything is hooked up properly without conflicting with other elements on the page. In WordPress, we query an array of page objects:
```
$property_query = new WP_Query(array(
'post_type' => 'page',
'post_status' => 'publish',
'posts_per_page' => -1, // Query them all!
'orderby' => 'title',
'order' => "ASC"
));
```
Before we get into our `while()` statement I’d like to stub out the HTML. This is how I want a page object to look inside of its container:
```
```
OK, let’s stub out the tooltip markup while we’re here, focusing just inside the `` element since that’s what represents a single page.
```
accent-color
Experimental feature
```
With me so far? We’ll start with the Popover side of things. Right now we have a `` that is connected to a `
CodePen Embed Fallback
Styling isn’t really what we’re talking about, but it does help to reset a few popover things so it doesn’t get that border and sit directly in the center of the page. You’ll want to [check out Michelle Barker’s article](https://css-irl.info/progressively-enhanced-popover-toggletips/) for some great tips that make this enhance progressively.
```
.info-tip {
position: relative; /* Sets containment */
/* Bail if Anchor Positioning is not supported */
[popovertarget] {
display: none;
}
/* Style things up if Anchor Positioning is supported */
@supports (anchor-name: --infotip) {
[popovertarget] {
display: inline;
position: relative;
}
[popover] {
border: 0; /* Removes default border */
margin: 0; /* Resets placement */
position: absolute; /* Required */
}
}
```
This is also the point at which you’ll want to start using Chrome because Safari and Firefox are still working on supporting the feature.
CodePen Embed Fallback
We’re doing good! The big deal at the moment is positioning the tooltip’s content so that it is beside the button. This is where we can start working with Anchor Positioning. [Juan Diego’s guide is the bee’s knees](https://css-tricks.com/css-anchor-positioning-guide/) if you’re looking for a deep dive. The gist is that we can connect an anchor to its target element in CSS. First, we register the `
```
.tooltip {
position: relative; /* Sets containment */
/* Bail if Anchor Positioning is not supported */
[popovertarget] {
display: none;
}
/* Style things up if Anchor Positioning is supported */
@supports (anchor-name: --tooltip) {
[popovertarget] {
anchor-name: --tooltip;
display: inline;
position: relative;
}
[popover] {
border: 0; /* Removes default border */
margin: 0; /* Resets placement */
position: absolute; /* Required */
position-anchor: --tooltip;
top: anchor(--tooltip -15%);
left: anchor(--tooltip 110%);
}
}
}
```
CodePen Embed Fallback
This is exactly what we want! But it’s also where things more complicated when we try to add more tooltips to the page. Notice that both buttons want to cull the same tooltip.
CodePen Embed Fallback
That’s no good. What we need is a unique ID for each tooltip. I’ll simplify the HTML so we’re looking at the right spot:
```
Experimental feature
```
The popover has an ID of `#experimental-label`. The anchor references it in the `popovertarget` attribute. This connects them but also connects other tooltips that are on the page. What would be ideal is to have a sequence of IDs, like:
```
```
We can make the page query into a function that we call:
```
function letterOutput($letter, $propertyID) {
$property_query = new WP_Query(array(
'post_type' => 'page',
'post_status' => 'publish',
'posts_per_page' => -1, // Query them all!
'orderby' => 'title',
'order' => "ASC"
));
}
```
And when calling the function, we’ll take two arguments that are specific only to what I was working on. If you’re curious, we have a structured set of pages that go Almanac → Type → Letter → Feature (e.g., Almanac → Properties → A → `accent-color`). This function outputs the child pages of a “Letter” (i.e., A → `accent-color`, `anchor-name`, etc.). A child page might be an “experimental” CSS feature and we’re marking that in the UI with tooltops next to each experimental feature.
We’ll put the HTML into an object that we can return when calling the function. I’ll cut it down for brevity…
```
$html .= '';
$html .= '';
$html .= '
accent-color
';
$html .= '';
$html .= ' ';
// ...
$html .= '';
$html .= '
// ...
$html .= '
$html .= '';
$html .= '';
$html .= '';
return $html;
```
WordPress has some functions we can leverage for looping through this markup. For example, we can insert `the_title()` in place of the hardcoded post title:
```
$html .= '
' . get_the_title(); . '
';
```
We can also use `get_the_id()` to insert the unique identifier associated with the post. For example, we can use it to give each `` element a unique ID:
```
$html .= '';
```
This is the secret sauce for getting the unique identifiers needed for the popovers:
```
// Outputs something like `id="experimental-label-12345"`
$html .= '
```
We can do the exact same thing on the `` so that each button is wired to the right popover:
```
$html .= ' ';
```
We ought to do the same thing to the `.tooltip` element itself to distinguish one from another:
```
$html .= '';
```
I can’t exactly recreate a WordPress instance in a CodePen demo, but here’s a simplified example with similar markup:
CodePen Embed Fallback
The popovers work! Clicking either one triggers its respective `popover` element. The problem you may have realized is that the targets are both attached to the same anchor element — so it looks like we’re triggering the same `popover` when clicking either button!
This is the CSS side of things. What we need is a similar way to apply unique identifiers to each anchor, but as dashed-idents instead of IDs. Something like this:
```
/* First tooltip */
#info-tip-1 {
[popovertarget] {
anchor-name: --infotip-1;
}
[popover] {
position-anchor: --infotip-1;
top: anchor(--infotip-1 -15%);
left: anchor(--infotip-1 100%);
}
}
/* Second tooltip */
#info-tip-2 {
[popovertarget] {
anchor-name: --infotip-1;
}
[popover] {
position-anchor: --infotip-1;
top: anchor(--infotip-1 -15%);
left: anchor(--infotip-1 100%);
}
}
/* Rest of tooltips... */
```
This is where I feel like I had to make a compromise. I could have leveraged an `@for` loop in Sass to generate unique identifiers but then I’d be introducing a new dependency. I could also drop a `` tag directly into the WordPress template and use the same functions to generate the same post identifiers but then I’m maintaining styles in PHP.
I chose the latter. I like having dashed-idents that match the IDs set on the `.tooltip` and `popover`. It ain’t pretty, but it works:
```
$html .= '
<style>
#info-tip-' . get_the_id() . ' {
[popovertarget] {
anchor-name: --infotip-' . get_the_id() . ';
}
[popover] {
position-anchor: --infotip-' . get_the_id() . ';
top: anchor(--infotip-' . get_the_id() . ' -15%);
left: anchor(--infotip-' . get_the_id() . ' 100%);
}
}
'
```
We’re technically done!
CodePen Embed Fallback
The only thing I had left to do for my specific use case was add a conditional statement that outputs the tooltip only if it is marked an “Experimental Feature” in the CMS. But you get the idea.
### Isn’t there a better way?!
Yes! But not quite yet. [Bramus proposed a new ident() function](https://www.bram.us/2024/12/18/the-future-of-css-construct-custom-idents-and-dashed-idents-with-ident/) that, when it becomes official, will generate a series of dashed idents that can be used to name things like the anchors I’m working with and prevent those names from colliding with one another.
```
...
...
...
...
...
```
```
/* Hypothetical example — does not work! */
.group-item {
anchor-name: ident("--infotip-" attr(id) "-anchor");
/* --infotip-item-1-anchor, --infotip-item-2-anchor, etc. */
}
```
Let’s keep our fingers crossed for that to hit the specifications soon!
---
[Working With Multiple CSS Anchors and Popovers Inside the WordPress Loop](https://css-tricks.com/working-with-multiple-css-anchors-and-popovers-inside-the-wordpress-loop/) originally published on [CSS-Tricks](https://css-tricks.com), which is part of the [DigitalOcean](https://try.digitalocean.com/css-tricks/?utm%5Fmedium=rss&utm%5Fsource=css-tricks.com&utm%5Fcampaign=family%5F&utm%5Fcontent=) family. You should [get the newsletter](https://css-tricks.com/newsletters/).
https://css-tricks.com/working-with-multiple-css-anchors-and-popovers-inside-the-wordpress-loop/