Image Hotspots
An annotated image with glowing pin markers, each opening a small popover of detail content. Built for product-feature callouts, annotated screenshots, and simple maps.
<arc-image-hotspots> Overview
>
Image Hotspots lays glowing pins over a picture and gives each pin a popover. Slot the image and the `<arc-hotspot>` children together — every pin positions itself from its own x and y attributes, given as percentages of the image, so source order never matters and the markup stays a flat list of facts about the picture.
Each pin is a real button: keyboard-focusable, labeled for screen readers, and carrying `aria-expanded` popover semantics. Clicking or activating a pin opens its popover anchored above the pin, flipping to fit near viewport edges. The parent keeps one popover open at a time, and an open popover closes on Escape, on a click anywhere else, or on a second click of its pin.
The pins render server-side at their coordinates because positioning is pure CSS derived from attributes; only the popover interaction needs JavaScript. Every hotspot reports its activity through `arc-open` and `arc-close` events that bubble to the parent, with `detail.value` carrying the hotspot's label — or its index when no label is set.Guidelines
When to use
- Give every hotspot a label — it names the pin for screen readers, heads the popover, and identifies the hotspot in events
- Keep popover content to a sentence or two; link out for anything longer
- Place pins on the feature they describe, not beside it — coordinates are the whole message
- Use a handful of pins per image; three to six is the comfortable range
- Constrain the component to a readable width so pin targets stay comfortably apart
When not to use
- Do not crowd pins so close together that their popovers cover each other's targets
- Do not put critical information only in a popover — undiscovered pins go unread
- Do not use Image Hotspots for step-by-step onboarding — that is Guided Tour's job
- Do not rely on pixel positions in your head; x and y are percentages of the image box
Features
- Percentage-based pin coordinates — responsive by construction, no measuring
- Pulsing accent pins with a glow that rises on hover and focus
- One popover open at a time, coordinated by the parent
- Escape and outside-click both dismiss the open popover
- Popovers flip and shift to stay inside the viewport
- Pins are real buttons: focusable, labeled, `aria-expanded` state
- `arc-open` / `arc-close` events with `detail.value` naming the hotspot
- Pins server-render at their positions; popovers stay closed without JS
- Ambient pulse is suppressed under `prefers-reduced-motion`
Preview
Usage
This component requires JavaScript. No pure HTML/CSS version is available — use the Web Component directly or a framework wrapper.
<arc-image-hotspots>
<img src="/screenshots/dashboard.png" alt="Analytics dashboard" />
<arc-hotspot x="18" y="30" label="Navigation">
Jump between reports, alerts, and settings from one rail.
</arc-hotspot>
<arc-hotspot x="60" y="45" label="Live charts">
Metrics stream in real time — no refresh required.
</arc-hotspot>
<arc-hotspot x="85" y="78" label="Exports">
Any panel exports to CSV, PNG, or a shared link.
</arc-hotspot>
</arc-image-hotspots> import { ImageHotspots, Hotspot } from '@arclux/arc-ui-react';
export default function FeatureTour() {
return (
<ImageHotspots onArcOpen={(e) => console.log('opened', e.detail.value)}>
<img src="/screenshots/dashboard.png" alt="Analytics dashboard" />
<Hotspot x={18} y={30} label="Navigation">
Jump between reports, alerts, and settings from one rail.
</Hotspot>
<Hotspot x={60} y={45} label="Live charts">
Metrics stream in real time — no refresh required.
</Hotspot>
<Hotspot x={85} y={78} label="Exports">
Any panel exports to CSV, PNG, or a shared link.
</Hotspot>
</ImageHotspots>
);
} <script setup>
import { ImageHotspots, Hotspot } from '@arclux/arc-ui-vue';
</script>
<template>
<ImageHotspots>
<img src="/screenshots/dashboard.png" alt="Analytics dashboard" />
<Hotspot :x="18" :y="30" label="Navigation">
Jump between reports, alerts, and settings from one rail.
</Hotspot>
<Hotspot :x="60" :y="45" label="Live charts">
Metrics stream in real time — no refresh required.
</Hotspot>
<Hotspot :x="85" :y="78" label="Exports">
Any panel exports to CSV, PNG, or a shared link.
</Hotspot>
</ImageHotspots>
</template> <script>
import { ImageHotspots, Hotspot } from '@arclux/arc-ui-svelte';
</script>
<ImageHotspots>
<img src="/screenshots/dashboard.png" alt="Analytics dashboard" />
<Hotspot x={18} y={30} label="Navigation">
Jump between reports, alerts, and settings from one rail.
</Hotspot>
<Hotspot x={60} y={45} label="Live charts">
Metrics stream in real time — no refresh required.
</Hotspot>
<Hotspot x={85} y={78} label="Exports">
Any panel exports to CSV, PNG, or a shared link.
</Hotspot>
</ImageHotspots> import { Component } from '@angular/core';
import { ImageHotspots, Hotspot } from '@arclux/arc-ui-angular';
@Component({
imports: [ImageHotspots, Hotspot],
template: `
<arc-image-hotspots>
<img src="/screenshots/dashboard.png" alt="Analytics dashboard" />
<arc-hotspot x="18" y="30" label="Navigation">
Jump between reports, alerts, and settings from one rail.
</arc-hotspot>
<arc-hotspot x="60" y="45" label="Live charts">
Metrics stream in real time — no refresh required.
</arc-hotspot>
<arc-hotspot x="85" y="78" label="Exports">
Any panel exports to CSV, PNG, or a shared link.
</arc-hotspot>
</arc-image-hotspots>
`,
})
export class FeatureTourComponent {} import { ImageHotspots, Hotspot } from '@arclux/arc-ui-solid';
export default function FeatureTour() {
return (
<ImageHotspots>
<img src="/screenshots/dashboard.png" alt="Analytics dashboard" />
<Hotspot x={18} y={30} label="Navigation">
Jump between reports, alerts, and settings from one rail.
</Hotspot>
<Hotspot x={60} y={45} label="Live charts">
Metrics stream in real time — no refresh required.
</Hotspot>
<Hotspot x={85} y={78} label="Exports">
Any panel exports to CSV, PNG, or a shared link.
</Hotspot>
</ImageHotspots>
);
} import { ImageHotspots, Hotspot } from '@arclux/arc-ui-preact';
export default function FeatureTour() {
return (
<ImageHotspots>
<img src="/screenshots/dashboard.png" alt="Analytics dashboard" />
<Hotspot x={18} y={30} label="Navigation">
Jump between reports, alerts, and settings from one rail.
</Hotspot>
<Hotspot x={60} y={45} label="Live charts">
Metrics stream in real time — no refresh required.
</Hotspot>
<Hotspot x={85} y={78} label="Exports">
Any panel exports to CSV, PNG, or a shared link.
</Hotspot>
</ImageHotspots>
);
} Hotspot
<arc-hotspot> A single glowing pin inside an Image Hotspots surface. The x and y attributes position it as percentages of the image, the label names it, and slotted children become the popover body.
-
xnumber50 - Horizontal position of the pin as a percentage of the image width, from 0 (left edge) to 100 (right edge). Values outside the range are clamped; a non-numeric value falls back to 50.
-
ynumber50 - Vertical position of the pin as a percentage of the image height, from 0 (top edge) to 100 (bottom edge). Values outside the range are clamped; a non-numeric value falls back to 50.
-
labelstring'' - Accessible name for the pin button, repeated as the heading of the popover. Always set it — without a label the pin announces nothing useful to a screen reader.
-
openbooleanfalse - Whether the pin's popover is currently visible. Reflected as an attribute. Opens on click; closes on Escape, outside click, or a second click on the pin.
See Also
- Popover Floating content panel anchored to a trigger element, with four placement positions and automatic outside-click dismissal.
- Tooltip Contextual hint that appears on hover or focus, providing supplementary information without cluttering the UI. Supports four placement positions and a configurable show delay.
- Image Enhanced image component with shimmer loading skeleton, smooth fade-in transition, error fallback, and aspect ratio presets.
- Guided Tour Multi-step onboarding that composes spotlight with popover-styled tooltips at each step. Step counter uses accent-primary gradient text.