Skip to content

Stretch Link

<quiet-stretch-link> stable since 6.0

Turns an entire region into a single clickable link while keeping nested buttons, links, and form controls fully interactive and accessible. Reach for it when an entire card, media tile, or block of content should activate one destination.

HTML doesn't allow interactive elements inside an <a>, so a clickable card or list item stops being valid as soon as it contains its own button, link, or form control. A stretch link works around this by placing a link over the region instead of wrapping the content in it. Since nothing is nested inside the link, the markup stays valid and interactive elements keep working as expected.

Click an empty part of the region and it follows the link; click a nested button, link, or form control and that element responds instead. Modifier and middle clicks open a new tab or window, just like a native link. The link is keyboard focusable with a meaningful name, and each nested control keeps its place in the tab order.

A tabby kitten sleeps next to a toy mouse.

The sleepy tabby

Clicking anywhere on this card follows the link, but the buttons below still works on their own.

Adopt me Learn more
<quiet-stretch-link label="The sleepy tabby" href="https://example.com" target="_blank" rel="noreferrer noopener" style="max-width: 340px;">
  <quiet-card>
    <img slot="media" src="https://images.unsplash.com/photo-1515073883629-5e2924e3e106?q=80&w=1000&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D" alt="A tabby kitten sleeps next to a toy mouse.">

    <h3 style="font-size: 1.125rem; margin-block: 0 .5rem;">The sleepy tabby</h3>
    <p style="margin: 0;">Clicking anywhere on this card follows the link, but the buttons below still works on their own.</p>

    <quiet-button slot="footer" variant="primary">Adopt me</quiet-button>
    <quiet-button slot="footer">Learn more</quiet-button>
  </quiet-card>
</quiet-stretch-link>

The content sits above the link so text selection and nested controls keep working, which means the link isn't the topmost element over your content. As a result, right-clicking the content won't show the browser's Copy link address option. This is an intentional trade-off, since the link can't sit on top for right-clicks without covering the selectable content.

Examples Jump to heading

Providing a label Jump to heading

Because the content isn't nested inside the link, the link has no text of its own to announce. Set the label attribute to give it a concise, meaningful accessible name. For voice control and consistency, it should contain the region's primary visible text, such as its heading.

Clementine

A curious calico looking for a sunny windowsill to call home.

Adopt me
<quiet-stretch-link label="Clementine" href="https://example.com" target="_blank" rel="noreferrer noopener" style="max-width: 340px;">
  <quiet-card>
    <strong>Clementine</strong>
    <p style="margin-block: .5rem 0;">A curious calico looking for a sunny windowsill to call home.</p>

    <quiet-button slot="footer" variant="primary">Adopt me</quiet-button>
  </quiet-card>
</quiet-stretch-link>

When you omit the label, the link borrows its accessible name from the region's visible text. This works well for short content, like a single heading, where the visible text already makes a good name.

<quiet-stretch-link href="https://example.com">
  <quiet-card>
    <h3>Clementine</h3>
  </quiet-card>
</quiet-stretch-link>

For larger regions, prefer an explicit label. The fallback concatenates all of the region's visible text, including the labels of nested buttons and links, which can produce a long, noisy name. If you do rely on it, lead with a heading or descriptive text rather than a bare button or link, so the link's name starts with where it goes.

Opening in a new tab Jump to heading

Use the target attribute to control where the link opens. When linking to an external domain, set rel to noreferrer noopener for safety.

Mochi's adventures

The card opens this profile in a new tab, but the follow button still works on its own.

Follow Mochi
<quiet-stretch-link
  label="Mochi's adventures"
  href="https://example.com"
  target="_blank"
  rel="noreferrer noopener"
  style="max-width: 340px;"
>
  <quiet-card>
    <h3 style="font-size: 1.125rem; margin-block: 0 .5rem;">Mochi's adventures</h3>
    <p style="margin: 0;">The card opens this profile in a new tab, but the follow button still works on its own.</p>

    <quiet-button slot="footer" variant="primary">
      <quiet-icon slot="start" name="user-plus"></quiet-icon>
      Follow Mochi
    </quiet-button>
  </quiet-card>
</quiet-stretch-link>

Nesting interactive elements Jump to heading

Buttons, links, form controls, and similar elements keep working as expected. They're never triggered by the stretched link, and the stretched link is never triggered by them. This includes interactive elements nested inside a custom element's shadow root, such as the controls inside Quiet's own components.

Project Whiskers

Tap the card to open the project, or use the controls below.

Quick View More Info
<quiet-stretch-link label="Project Whiskers" href="https://example.com" target="_blank" rel="noreferrer noopener" style="max-width: 340px;">
  <quiet-card>
    <h3 style="font-size: 1.125rem; margin-block: 0 .5rem;">Project Whiskers</h3>
    <p style="margin: 0;">Tap the card to open the project, or use the controls below.</p>

    <quiet-button slot="footer" variant="primary">Quick View</quiet-button>
    <quiet-button slot="footer">More Info</quiet-button>
  </quiet-card>
</quiet-stretch-link>

Excluding an element Jump to heading

To stop a non-interactive element from following the link when clicked, add data-stretch-link="ignore" to it. This is handy for badges, captions, or other regions that shouldn't navigate.

Excluded elements still inherit the region's pointer cursor, since they're not links themselves. Reset it with cursor: auto if you'd rather they not look clickable, as shown below.

Cats in space

The whole card is a link, the button still works, and the tags below do nothing when clicked.

Featured Vaccinated Indoor Launch
<quiet-stretch-link label="Cats in space" href="https://example.com" target="_blank" rel="noreferrer noopener" id="stretch-link__ignore" style="max-width: 340px;">
  <quiet-card>
    <h3 style="font-size: 1.125rem; margin-block: 0 .5rem;">Cats in space</h3>
    <p style="margin: 0 0 .75rem;">The whole card is a link, the button still works, and the tags below do nothing when clicked.</p>

    <quiet-badge data-stretch-link="ignore" variant="primary">Featured</quiet-badge>
    <quiet-badge data-stretch-link="ignore" variant="neutral">Vaccinated</quiet-badge>
    <quiet-badge data-stretch-link="ignore" variant="neutral">Indoor</quiet-badge>

    <quiet-button slot="footer" variant="primary">Launch</quiet-button>
  </quiet-card>
</quiet-stretch-link>

<style>
  #stretch-link__ignore [data-stretch-link="ignore"] {
    cursor: auto;
  }
</style>

Wrapping inline content Jump to heading

The stretch link is display: block by default, so it fills the available width and the clickable area always matches the host's box. To shrink-wrap inline content instead, change the host's display property to inline-block or inline-flex.

Meet Pumpkin, our cat of the week Adopt
<quiet-stretch-link
  label="Meet Pumpkin"
  href="https://example.com"
  target="_blank"
  rel="noreferrer noopener"
  id="stretch-link__inline"
>
  <span class="box">
    Meet Pumpkin, our cat of the week
    <quiet-button size="sm" variant="primary">Adopt</quiet-button>
  </span>
</quiet-stretch-link>

<style>
  #stretch-link__inline {
    display: inline-block;

    .box {
      display: flex;
      align-items: center;
      gap: 1rem;
      padding: 1rem;
      border: var(--quiet-border-style) var(--quiet-border-width) var(--quiet-neutral-stroke-softer);
      border-radius: var(--quiet-border-radius-md);
      background-color: var(--quiet-paper-color);
      box-shadow: var(--quiet-shadow-softer);
    }
  }
</style>

The stretch link is a behavior, not a look, though it does show a pointer cursor over the clickable region for you. Make the region feel clickable by styling the content you slot in, for example by changing the background or elevation on hover.

Hover me

This card lifts when you hover it, and the button below still works.

Adopt me
<quiet-stretch-link
  label="Hover me"
  href="https://example.com"
  target="_blank"
  rel="noreferrer noopener"
  id="stretch-link__hover"
  style="max-width: 340px;"
>
  <quiet-card>
    <strong>Hover me</strong>
    <p style="margin-block: .5rem 0;">This card lifts when you hover it, and the button below still works.</p>

    <quiet-button slot="footer" variant="primary">Adopt me</quiet-button>
  </quiet-card>
</quiet-stretch-link>

<style>
  #stretch-link__hover quiet-card {
    transition: box-shadow 0.2s ease, transform 0.2s ease;
  }

  #stretch-link__hover:hover quiet-card {
    box-shadow: var(--quiet-shadow-mid);
    transform: translateY(-2px);
  }
</style>

API Jump to heading

Importing Jump to heading

The autoloader is the recommended way to import components but, if you prefer to do it manually, the following code snippets will be helpful.

CDN Self-hosted

To manually import <quiet-stretch-link> from the CDN, use the following code.

import 'https://cdn.quietui.org/v5.3.1/components/stretch-link/stretch-link.js';

To manually import <quiet-stretch-link> from a self-hosted distribution, use the following code. Remember to replace /path/to/quiet with the appropriate local path.

import '/path/to/quiet/components/stretch-link/stretch-link.js';

Slots Jump to heading

Stretch Link supports the following slots. Learn more about using slots

Name Description
(default) The content to make clickable. Interactive elements such as buttons, links, and form controls remain usable and are not nested inside the link in the DOM.

Properties Jump to heading

Stretch Link has the following properties that can be set with corresponding attributes. In many cases, the attribute's name is the same as the property's name. If an attribute is different, it will be displayed after the property. Learn more about attributes and properties

Property Description Reflects Type Default
href The URL the link points to. Without it, the region renders its content but isn't clickable. string
target Opens the link in the specified target. '_blank' | '_parent' | '_self' | '_top' | undefined
rel Sets the link's rel attribute. When linking to an external domain, you should probably set this to noreferrer noopener. string | undefined
download Sets the link's download attribute, causing the linked file to be downloaded. string | undefined
label An accessible label for the link. Because the content isn't nested inside the link, this gives assistive devices a meaningful name for the destination. For voice control and consistency, it should contain the region's primary visible text, such as its heading. When omitted, the link borrows its name from the region's visible text, which works well for short content but can be verbose for larger regions. string | undefined

CSS parts Jump to heading

Stretch Link exposes internal elements that can be styled with CSS using the selectors shown below. Learn more about CSS parts

Name Description CSS selector
link The internal anchor that stretches over the content to capture clicks, an <a> element. ::part(link)
content The container that wraps the default slot, a <div> element. ::part(content)

Custom States Jump to heading

Stretch Link has the following custom states. You can target them with CSS using the selectors shown below. Learn more about custom states

Name Description CSS selector
link Applied when an href is set and the region behaves as a link. :state(link)
Search this website Toggle dark mode View the code on GitHub Follow @quietui.org on Bluesky Follow @quiet_ui on X

    No results found