Skip to main content
Copy for LLM

Image Hotspots

<x-wirekit::image-hotspots> lays markers over an image: a shop shows the products in a room, a guide names the parts of a machine. Each marker is a button named after its target. On hover and focus its name shows beside it, and a press sends wirekit:image-hotspots-select, so the page decides what opens, a quick view, a drawer or another page. On the phone a strip under the image lists the targets as links.

Basic Usage

Give the image, its size in pixels and the markers, each with its position in percent of the image and the name of its target:

A Room With Three Products
A living room with a sofa, a floor lamp and a rug

The markers come in the order Tab reaches them, so put them in the order a reader should meet them. A marker right of the middle shows its name on its left, the others on their right. A name longer than the room between its marker and the edge of the image wraps onto a second line, so it never runs past the image, not even on a phone.

Markers

Each marker is an array:

Key Type Required Description
x, y int|float yes Where the center of the marker stands, in percent of the image's width and height, from its top left corner
label string yes The name of the target: the marker's accessible name, the text beside it and the text of its card
target string|int no What the page needs to open the target, an id or a key. It comes back in the event
href string no The link of the target's card in the strip. Without it the card is text
image string no A thumbnail on the target's card
phoneX, phoneY int|float no The position on the phone's file. They fall back to x and y

A marker without a label would be a button nobody can identify, and one without a position has no place, so both are reported and left out. A position outside 0 to 100 is reported and held at the edge.

A File for the Phone

A phone often shows another crop of the same scene. phone-src gives it, with its own size, and every marker takes its position on it from phoneX and phoneY. The browser switches the file below 48rem, and the markers move at the same width:

<x-wirekit::image-hotspots
    src="/img/living-room.jpg"
    alt="A living room with a sofa, a floor lamp and a rug"
    width="1600"
    height="1000"
    phone-src="/img/living-room-phone.jpg"
    phone-width="900"
    phone-height="1200"
    :markers="[
        ['x' => 24, 'y' => 58, 'phoneX' => 30, 'phoneY' => 70, 'label' => 'Sofa Bergen', 'target' => 'sofa-bergen'],
        ['x' => 71, 'y' => 34, 'phoneX' => 64, 'phoneY' => 22, 'label' => 'Floor lamp Arc', 'target' => 'lamp-arc'],
    ]"
/>

The image takes no ratio of its own: its box is the image, so a percentage of the box is a percentage of the image, on either file.

The Strip on the Phone

Below 48rem a strip under the image lists the targets, each a link where it has an href, with its thumbnail where it has an image. A press on a marker marks its card and scrolls the strip until the card is in view. The strip is always in the markup, also where the stylesheet hides it, so screen readers and search engines read the targets as links. :strip="false" leaves it out:

Markers Without a Strip
A workbench with a drill, a vice and a lamp

Opening the Target

A press sends wirekit:image-hotspots-select from the marker, and it bubbles. Its detail carries index, target and label. In a Livewire component the page opens what it needs:

<x-wirekit::image-hotspots
    src="/img/living-room.jpg"
    alt="A living room with a sofa, a floor lamp and a rug"
    width="1600"
    height="1000"
    :markers="$hotspots"
    x-on:wirekit:image-hotspots-select="$wire.openQuickView($event.detail.target)"
/>
public function openQuickView(string $product): void
{
    $this->quickView = Product::where('slug', $product)->firstOrFail();
}

The marker takes the focus when it is pressed, also in Safari, which does not focus a button it clicks. A quick view in a modal or a drawer hands the focus back to it when it closes.

The component holds no state outside itself, so it works as a slide of a carousel, one image of a campaign after another.

Props

Prop Type Default Description
src string — The image's address. Without one nothing renders, and it is reported
alt string '' The image's text alternative
srcset string|null null Responsive sources of the image
sizes string|null null The width the image takes in the layout, for srcset
width int|null null The image's width in pixels, which with height reserves its box before the file arrives
height int|null null The image's height in pixels
phone-src string|null null The file a phone shows below 48rem. See A File for the Phone
phone-srcset string|null null Responsive sources of the phone's file
phone-width int|null null The phone file's width in pixels
phone-height int|null null The phone file's height in pixels
loading string 'lazy' 'lazy' or 'eager'. An image at the top of the page loads eager
fetchpriority string|null null 'high', 'low' or 'auto' on the <img>; null leaves it to the browser. 'high' suits an image at the top of the page, which the browser then fetches first
markers array [] The markers. See Markers
icon string 'plus' The icon each marker shows
label string|null "Hotspots" The name of the markers as a group
strip bool true The strip of targets under the image on the phone
strip-label string|null "In this image" The name of the strip
scope string|null null Scoped personalization key

Events

Event Detail When
wirekit:image-hotspots-select { index, target, label } A marker was pressed, with the mouse, a finger or the keyboard

Accessibility

  • Every marker is a <button> whose name is its target's name, and the markers are a list named by label, so a screen reader says how many there are.
  • The name beside a marker shows on hover and on focus, never on hover alone. Escape hides every name on screen, the one under the pointer as well while the focus is elsewhere, until its marker loses the focus or the pointer (WCAG 1.4.13). In a modal or a drawer, that press leaves the dialog open, and the next Escape closes it.
  • A marker measures --size-wk-sm, 2rem, past the 24 pixels of WCAG 2.5.8. It stands on a fill of its own inside a ring in the text color, so one of the two keeps 3:1 against any image (WCAG 1.4.11).
  • The strip is a named scroll region the keyboard can reach, and its cards are a list of links.
  • The label's fade follows --transition-wk-duration and stops under prefers-reduced-motion: reduce, and the strip scrolls without a glide there.

Keyboard Interaction

Key Action
Tab Moves to the next marker, in the order of markers
Enter / Space Presses the marker
Escape Hides the name beside the focused marker and the one under the pointer. With no name on screen, it closes the dialog around the image

Updated in WireKit v2.71.0 (2026-11-02)

Was this page helpful?

Thank you for your feedback!

Voting requires cookies or local storage. What we store