I do know, tremendous area of interest, however it could possibly be any loop, actually. The problem is having a number of tooltips on the identical web page that make use of the Popover API for toggling goodness and CSS Anchor Positioning for attaching a tooltip to its respective anchor component.
There’s loads of transferring items when working with popovers:
- A
popover
wants an ID (and an accessible position whereas we’re at it). - A
popovertarget
must reference that ID. - IDs should be distinctive for semantics, sure, but in addition to hook a
popover
right into apopovertarget
.
That’s simply the half coping with the Popover API. Turning to anchors:
- An anchor wants an
anchor-name
. - A goal component must reference that
anchor-name
. - Every
anchor-name
should be distinctive to connect the goal to its anchor correctly.
The necessities themselves are difficult. But it surely’s tougher working inside a loop since you want a option to generate distinctive IDs and anchor names so every thing is connected correctly with out conflicting with different components on the web page. In WordPress, we question an array of web page objects:
$property_query = new WP_Query(array(
'post_type' => 'web page',
'post_status' => 'publish',
'posts_per_page' => -1, // Question all of them!
'orderby' => 'title',
'order' => "ASC"
));
Earlier than we get into our whereas()
assertion I’d wish to stub out the HTML. That is how I desire a web page object to look within its container:
<div class="almanac-group">
<div class="group-letter"><a href="#">A</a></div>
<div class="group-list">
<particulars id="" class="group-item">
<abstract>
<h2><code>accent-color</code></h2>
</abstract>
</particulars>
<!-- Repeat for all properties -->
</div>
</div>
<!-- Repeat for all the alphabet -->
OK, let’s stub out the tooltip markup whereas we’re right here, focusing simply contained in the <particulars>
component since that’s what represents a single web page.
<particulars id="web page" class="group-item">
<abstract>
<h2><code>accent-color</code></h2>
<span id="tooltip" class="tooltip">
<!-- Popover Goal and Anchor -->
<button class="info-tip-button" aria-labelledby="experimental-label" popovertarget="experimental-label">
<!-- and so forth. -->
</button>
<!-- Popover and Anchor Goal -->
<div popover id="experimental-label" class="info-tip-content" position="tooltip">
Experimental characteristic
</div>
</span>
</abstract>
</particulars>
With me to this point? We’ll begin with the Popover aspect of issues. Proper now we’ve a <button>
that’s related to a <div popover>
. Clicking the previous toggles the latter.
Styling isn’t actually what we’re speaking about, however it does assist to reset a number of popover issues so it doesn’t get that border and sit instantly within the middle of the web page. You’ll need to try Michelle Barker’s article for some nice suggestions that make this improve progressively.
.info-tip {
place: relative; /* Units containment */
/* Bail if Anchor Positioning shouldn't be supported */
[popovertarget] {
show: none;
}
/* Fashion issues up if Anchor Positioning is supported */
@helps (anchor-name: --infotip) {
[popovertarget] {
show: inline;
place: relative;
}
[popover] {
border: 0; /* Removes default border */
margin: 0; /* Resets placement */
place: absolute; /* Required */
}
}
That is additionally the purpose at which you’ll need to begin utilizing Chrome as a result of Safari and Firefox are nonetheless engaged on supporting the characteristic.
We’re doing good! The large deal for the time being is positioning the tooltip’s content material in order that it’s beside the button. That is the place we are able to begin working with Anchor Positioning. Juan Diego’s information is the bee’s knees for those who’re on the lookout for a deep dive. The gist is that we are able to join an anchor to its goal component in CSS. First, we register the <button>
because the anchor component by giving it an anchor-name
. Then we anchor the <div popover>
to the <button>
with position-anchor
and use the anchor()
perform on its inset properties to place it precisely the place we wish, relative to the <button>
:
.tooltip {
place: relative; /* Units containment */
/* Bail if Anchor Positioning shouldn't be supported */
[popovertarget] {
show: none;
}
/* Fashion issues up if Anchor Positioning is supported */
@helps (anchor-name: --tooltip) {
[popovertarget] {
anchor-name: --tooltip;
show: inline;
place: relative;
}
[popover] {
border: 0; /* Removes default border */
margin: 0; /* Resets placement */
place: absolute; /* Required */
position-anchor: --tooltip;
high: anchor(--tooltip -15%);
left: anchor(--tooltip 110%);
}
}
}
That is precisely what we wish! But it surely’s additionally the place issues extra sophisticated after we attempt to add extra tooltips to the web page. Discover that each buttons need to cull the identical tooltip.
That’s no good. What we’d like is a singular ID for every tooltip. I’ll simplify the HTML so we’re wanting on the proper spot:
<particulars>
<!-- ... -->
<!-- Popover Goal and Anchor -->
<button class="info-tip-button" aria-labelledby="experimental-label" popovertarget="experimental-label">
<!-- ... -->
</button>
<!-- Popover and Anchor Goal -->
<div popover id="experimental-label" class="info-tip-content" position="tooltip">
Experimental characteristic
</div>
<!-- ... -->
</particulars>
The popover has an ID of #experimental-label
. The anchor references it within the popovertarget
attribute. This connects them but in addition connects different tooltips which are on the web page. What could be perfect is to have a sequence of IDs, like:
<!-- Popover and Anchor Goal -->
<div popover id="experimental-label-1" class="info-tip-content" position="tooltip"> ... </div>
<div popover id="experimental-label-2" class="info-tip-content" position="tooltip"> ... </div>
<div popover id="experimental-label-3" class="info-tip-content" position="tooltip"> ... </div>
<!-- and so forth... -->
We are able to make the web page question right into a perform that we name:
perform letterOutput($letter, $propertyID) {
$property_query = new WP_Query(array(
'post_type' => 'web page',
'post_status' => 'publish',
'posts_per_page' => -1, // Question all of them!
'orderby' => 'title',
'order' => "ASC"
));
}
And when calling the perform, we’ll take two arguments which are particular solely to what I used to be engaged on. In case you’re curious, we’ve a structured set of pages that go Almanac → Sort → Letter → Characteristic (e.g., Almanac → Properties → A → accent-color
). This perform outputs the kid pages of a “Letter” (i.e., A → accent-color
, anchor-name
, and so forth.). A baby web page is perhaps an “experimental” CSS characteristic and we’re marking that within the UI with tooltops subsequent to every experimental characteristic.
We’ll put the HTML into an object that we are able to return when calling the perform. I’ll reduce it down for brevity…
$html .= '<particulars id="web page" class="group-item">';
$html .= '<abstract>';
$html .= '<h2><code>accent-color</code></h2>';
$html .= '<span id="tooltip" class="tooltip">';
$html .= '<button class="info-tip-button" aria-labelledby="experimental-label" popovertarget="experimental-label"> ';
// ...
$html .= '</button>';
$html .= '<div popover id="experimental-label" class="info-tip-content" position="tooltip">';
// ...
$html .= '</div>';
$html .= '</span>';
$html .= '</abstract>';
$html .= '</particulars>';
return $html;
WordPress has some capabilities we are able to leverage for looping via this markup. For instance, we are able to insert the_title()
instead of the hardcoded submit title:
$html .= '<h2><code>' . get_the_title(); . '</code></h2>';
We are able to additionally use get_the_id()
to insert the distinctive identifier related to the submit. For instance, we are able to use it to provide every <particulars>
component a singular ID:
$html .= '<particulars id="page-' . get_the_id(); . '" class="group-item">';
That is the key sauce for getting the distinctive identifiers wanted for the popovers:
// Outputs one thing like `id="experimental-label-12345"`
$html .= '<div popover id="experimental-label-' . get_the_id(); . '" class="info-tip-content" position="tooltip">';
We are able to do the very same factor on the <button>
so that every button is wired to the best popover:
$html .= '<button class="info-tip-button" aria-labelledby="experimental-label-' . get_the_id(); . '" popovertarget="experimental-label"> ';
We should do the identical factor to the .tooltip
component itself to tell apart one from one other:
$html .= '<span id="tooltip-' . get_the_id(); . '" class="tooltip">';
I can’t precisely recreate a WordPress occasion in a CodePen demo, however right here’s a simplified instance with comparable markup:
The popovers work! Clicking both one triggers its respective popover
component. The issue you’ll have realized is that the targets are each connected to the identical anchor component — so it seems to be like we’re triggering the identical popover
when clicking both button!
That is the CSS aspect of issues. What we’d like is an analogous option to apply distinctive identifiers to every anchor, however as dashed-idents as an alternative of IDs. One thing like this:
/* First tooltip */
#info-tip-1 {
[popovertarget] {
anchor-name: --infotip-1;
}
[popover] {
position-anchor: --infotip-1;
high: anchor(--infotip-1 -15%);
left: anchor(--infotip-1 100%);
}
}
/* Second tooltip */
#info-tip-2 {
[popovertarget] {
anchor-name: --infotip-1;
}
[popover] {
position-anchor: --infotip-1;
high: anchor(--infotip-1 -15%);
left: anchor(--infotip-1 100%);
}
}
/* Remainder of tooltips... */
That is the place I really feel like I needed to make a compromise. I may have leveraged an @for
loop in Sass to generate distinctive identifiers however then I’d be introducing a brand new dependency. I may additionally drop a <model>
tag instantly into the WordPress template and use the identical capabilities to generate the identical submit identifiers however then I’m sustaining kinds in PHP.
I selected the latter. I like having dashed-idents that match the IDs set on the .tooltip
and popover
. It ain’t fairly, however it works:
$html .= '
<model>
#info-tip-' . get_the_id() . ' {
[popovertarget] {
anchor-name: --infotip-' . get_the_id() . ';
}
[popover] {
position-anchor: --infotip-' . get_the_id() . ';
high: anchor(--infotip-' . get_the_id() . ' -15%);
left: anchor(--infotip-' . get_the_id() . ' 100%);
}
}
</model>'
We’re technically performed!
The one factor I had left to do for my particular use case was add a conditional assertion that outputs the tooltip solely whether it is marked an “Experimental Characteristic” within the CMS. However you get the concept.
Isn’t there a greater manner?!
Sure! However not fairly but. Bramus proposed a brand new ident()
perform that, when it turns into official, will generate a sequence of dashed idents that can be utilized to call issues just like the anchors I’m working with and forestall these names from colliding with each other.
<div class="group-list">
<particulars id="item-1" class="group-item">...</particulars>
<particulars id="item-2" class="group-item">...</particulars>
<particulars id="item-3" class="group-item">...</particulars>
<particulars id="item-4" class="group-item">...</particulars>
<particulars id="item-5" class="group-item">...</particulars>
<!-- and so forth. -->
</div>
/* Hypothetical instance — doesn't work! */
.group-item {
anchor-name: ident("--infotip-" attr(id) "-anchor");
/* --infotip-item-1-anchor, --infotip-item-2-anchor, and so forth. */
}
Let’s hold our fingers crossed for that to hit the specs quickly!