Wrap text around dismiss buttons on clickable cards
Published 4 days ago
Let's do something that sounds easy, but is tricky to get right: wrap text around the Dismiss button of a clickable card.
<!--
Use role=group + aria-label to properly announce relationships
between child elements. Add the relative class so we can
position the clickable action button absolutely.
Bonus: set up a CSS variable to keep the card's border radius
in sync with its clickable action button's border radius.
-->
<div
role="group"
aria-label="My group"
class="
isolate max-w-lg relative p-6
bg-white shadow-md ring-1 ring-gray-900/5
[--card-radius:theme(borderRadius.xl)]
rounded-[var(--card-radius)]
"
>
<!--
Render the action button first, so that it's first in the
tab order. Position it absolutely to make the entire card
clickable, and to draw a focus ring around the card. Use
aria-labelledby to provide proper labeling.
-->
<button
class="
absolute inset-0
rounded-[var(--card-radius)]
focus-visible:outline-2
focus-visible:outline-offset-2
focus-visible:outline-blue-50
"
aria-labelledby="action-button-label"
onclick="alert('Card clicked')"
></button>
<!--
Render the dismiss button next, so it can be floated to the
right, which allows text wrapping. Add relative to stack it
on top of the action button. Implement a focus ring.
-->
<button
class="
relative float-right
rounded-full
focus-visible:outline-2
focus-visible:outline-offset-2
focus-visible:outline-blue-50
hover:bg-black/5
"
aria-label="Dismiss this card"
onclick="alert('Card dismissed')"
>
<svg aria-hidden="true" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="24" height="24"><path d="M5.72 5.72a.75.75 0 0 1 1.06 0L12 10.94l5.22-5.22a.749.749 0 0 1 1.275.326.749.749 0 0 1-.215.734L13.06 12l5.22 5.22a.749.749 0 0 1-.326 1.275.749.749 0 0 1-.734-.215L12 13.06l-5.22 5.22a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042L10.94 12 5.72 6.78a.75.75 0 0 1 0-1.06Z"></path></svg>
</button>
<!--
Render wrapped text in a separate span, for two reasons:
1. Text doesn't wrap properly around button elements, even
when they have display:inline.
2. We need to render our button first for the correct tab
order, but the wrapped text needs to render after the
dismiss button so that CSS float works properly.
Match the span's id with the button's aria-labelledby to
provide proper labeling.
-->
<span id="action-button-label">
I'm baby mixtape jawn post-ironic jean shorts, cardigan VHS same austin roof party salvia master cleanse tofu etsy enamel pin.
</span>
</div>