Skip to main content

Stretched Links

Makes a whole block clickable by expanding one link inside it to cover the block — the Bootstrap "stretched link" pattern, for cards and any other container.

Yoko Core owns the mechanic. Themes own the look. The entire integration surface is two CSS classes, and a theme never has to reimplement the behavior.

For editors

The Yoko Stretched Link panel on a Group block, with Use as stretched link container switched on
On the container. Switched on here, the block becomes the click area — but nothing is clickable until a link inside it is set to stretch.

Two toggles, both in a Yoko Stretched Link panel in the block inspector.

  1. Select the container — a Group, Columns, or Column block — and turn on Use as stretched link container.
  2. Select the link inside it — a Button, Post Title, Heading, or Read More — and turn on Stretch link over container.

That's it. The whole container now follows that link.

The Yoko Stretched Link panel on a Heading block, with Stretch link over container switched on
On the link. The panel appears on Buttons, Post Titles, Headings and Read More blocks.

The two toggles are independent on purpose: a link set to stretch with no container ancestor stays an ordinary link rather than expanding into whatever happens to be around it. The inspector says so directly when that happens.

Seeing the pairing in the editor

In the editor canvas, a designated container is outlined with a dashed border and so is the link filling it, so the pairing is visible without selecting each block in turn.

A card in the editor with a dashed outline around the whole group and a second dashed outline around its title
The outer dashed outline is the container; the inner one is the link that fills it. Both are editor-only and never render on the site. They are hidden on the block you have selected, so click elsewhere to see them.

Warnings the panel shows

The panel showing a Dormant warning beneath the enabled toggle
The dormant state: the link toggle is on, but no ancestor is a container, so the link behaves normally.
WarningMeaning
Dormant: no ancestor block has "Use as stretched link container" enabledThe link toggle is on but nothing will change. Turn the container toggle on too.
No link inside this block is set to stretch yetThe container is designated but nothing inside it stretches, so nothing is clickable.
Another link in this container is already set to stretchTwo links are competing. Only the last one rendered wins — turn the others off.
This block has no link yetThe block needs a URL before there is anything to stretch.

Things worth knowing

The panel warning that another link in this container is already set to stretch
Two links set to stretch in one container. Nothing looks broken on the page — the first link simply stops covering the card — which is why the warning matters more than it looks.
  • Other links inside the container keep working. Taxonomy terms, icon buttons, and form controls are lifted above the overlay automatically.
  • Selecting text inside the container is harder, because the overlay sits above the text. That is inherent to the pattern, not a bug.
  • Only one link per container. A second one silently wins over the first, which is why the panel warns.
  • Prefer stretching the title over the button. The title text is the better accessible name for the link a screen reader announces.
  • Nested groups are fine. A card built as an outer group holding an inner group for its padded content used to have its click area stop at the inner group, because core positions every constrained group. The plugin now takes the wrappers between the link and its container out of the running — see Wrappers between the link and the container below.
  • Cover blocks are not offered. A Cover positions its own inner container for its background layers, so designating one would be asking for trouble even now. Wrap the Cover in a Group and designate the Group instead.

What keyboard users see

Tabbing to a stretched link outlines the whole container, not just the link text, so the highlight matches the area that will actually respond to a click.

A card on the front end with a focus ring around its entire edge
Keyboard focus on the card's stretched title. The ring traces the container because that is the real click target — a ring around the title alone would understate it.

The click area is an overlay on the link, stretched to the edges of its nearest positioned ancestor. That is normally the container — but core positions more elements than it looks like, and this rule ships with every block theme:

:where( .wp-block-group.wp-block-group-is-layout-constrained ) {
position: relative;
}

Constrained is the default group layout, so the ordinary way to build a card —

Group  ← designated as the container
└── Group (constrained) ← core makes this positioned
├── Heading ← the stretched link
└── Paragraph

— put a positioned element between the link and the container, and the click area stopped at the inner group. The container's own padding did nothing. Measured on that shape, one point in five across the card activated the link.

The plugin now resets position on exactly the elements between the link and its container, so the overlay reaches the container again. A group that is positioned for its own reasons but does not contain the stretched link is untouched.

Two cases it cannot fix, and what to do instead:

CaseWhat happensWhat to do
A wrapper between the link and the container has a transform, filter, backdrop-filter, perspective, contain or will-changeThat element becomes the containing block whatever its position is, and the click area stops there. A hover transform does it only while hovered, which looks like the card flickeringPut the transform on the container itself. That is where a card's hover treatment belongs anyway
A wrapper between them genuinely needs its own positioning — an absolutely placed badge, a sticky headerResetting it would move that childAdd yoko-link-keep-position to that wrapper. The click area then stops there deliberately, and the badge stays put

In DevTools the symptom is unmistakable: inspect the ::after on the stretched link and its box will match some inner element rather than the container.

For theme developers

Yoko Core adds two classes at render time and ships no hover styling at all:

ClassOnMeaning
yoko-link-containerthe container blockthis element is the click area
yoko-stretched-linkthe anchorthis link's hit area is stretched

Style the affordance against the container:

.yoko-link-container:hover {
/* the theme's own card hover treatment */
}

The plugin's own stylesheet only does the mechanical work — position: relative on the container, the absolutely positioned ::after overlay, raising other interactive descendants above it, and moving the keyboard focus ring off the link text and onto the overlay so it traces the real click target. It loads only on pages that actually contain a designated container.

Hover and active transitions

Because the container is the click area, one transition on the container covers everything inside it — the same result the Card block gets from being a link, without giving up the card's other links.

.yoko-link-container {
transition:
background-color 250ms ease,
box-shadow 250ms ease,
transform 250ms ease;
}

/* :hover and :active both propagate from the stretched link to its ancestors,
so the container gets them even though it is a div. */
.yoko-link-container:hover,
.yoko-link-container:focus-within {
box-shadow: 0 14px 28px rgba( 15, 23, 42, 0.18 );
transform: translateY( -6px );
}

.yoko-link-container:active {
transform: translateY( -1px );
transition-duration: 80ms;
}
StateSelectorWhy
Hover.yoko-link-container:hoverthe overlay covers the container, so hovering anywhere hits it
Active.yoko-link-container:active:active on the overlay propagates to its ancestors
Keyboard.yoko-link-container:focus-withinthe container is not focusable itself; the stretched link inside it is

Descendant selectors work from there — .yoko-link-container:hover img zooms the card image. The Cards page on the Playground demo site has all three states running next to the Card block's.

Filters

// Which blocks can carry a stretched link.
add_filter( 'yoko_core_stretched_link_blocks', function ( $blocks ) {
$blocks[] = 'core/post-excerpt';
return $blocks;
} );

// Which blocks can act as the click area.
add_filter( 'yoko_core_stretched_link_container_blocks', function ( $blocks ) {
$blocks[] = 'core/cover';
return $blocks;
} );

Both lists are handed to the editor as well as the render filters, so a block added by either filter gets its toggle and its markup together.

core/query, core/post-template, and core/comment-template can never be containers. Each renders every item of a loop inside one wrapper, so a single overlay would cover an entire feed instead of one card — filtering them in is refused rather than honored.

Auditing a site

A stretched link fails quietly by design, which is right for visitors and wrong for support: "the card isn't clickable" looks exactly like "nobody set it up".

wp yoko stretched-links audit

Reports every dormant link, every container with nothing to stretch, and every container holding competing links, with the post ID for each. Accepts --post_type=<type> and --format=<format>.

Debugging

  • View source and search for yoko-link-container and yoko-stretched-link. Both present but not clickable usually means the theme overrode position on the container, or a closer descendant became the containing block. Positioned descendants are handled; one carrying a transform or a filter is not — see Wrappers between the link and the container.
  • With WP_DEBUG on, debug.log carries [yoko-core] stretched-link: lines when a toggle is on but the block rendered no linked anchor.