npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

strapi-plugin-image-hotspot

v1.0.4

Published

Custom field for adding interactive hotspots to images

Downloads

199

Readme

Image Hotspot Plugin

A Strapi v5 plugin that provides a custom field for adding interactive hotspots (points and rectangles) to images with various action types.

Preview

Preview

Features

  • Image Selection: Select images from the media library via modal dialog
  • Point Hotspots: Add point hotspots by clicking on the image
  • Rectangle Hotspots: Add rectangle hotspots by clicking and dragging
  • Hotspot Management: Drag, resize, and delete hotspots
  • Visual Feedback: Visual indicators for selected hotspots
  • Multiple Action Types: Configure actions for each hotspot:
    • Link: Navigate to a URL (with target options)
    • Modal: Display content in a modal dialog
    • Tooltip: Show tooltip text on hover
    • Callback: Execute custom JavaScript functions
    • Custom: Define custom actions with name and JSON payload
    • None: No action
  • Automatic Image Population: Server-side middleware automatically populates image fields in API responses, so you get full image objects instead of just IDs

Installation

This plugin is automatically loaded by Strapi when placed in the src/plugins directory.

Server-Side Features

The plugin includes server-side middleware that automatically:

  • Intercepts API responses for content types using the image-hotspot field
  • Populates image references with full media objects (including URL, alternative text, etc.)
  • Works with both single entity and collection responses

This means when you fetch data via the API, the image field in your hotspot data will already contain the full media object, not just an ID.

Usage

Adding to Content Type Schema

In your content type schema, use:

{
  "attributes": {
    "imageHotspot": {
      "type": "customField",
      "customField": "plugin::image-hotspot::image-hotspot"
    }
  }
}

Action Types

Link Action

Navigate to a URL when the hotspot is clicked:

  • url: The target URL
  • target: "_self" (same tab) or "_blank" (new tab)

Modal Action

Display content in a modal dialog:

  • modalTitle: Title of the modal
  • modalContent: Content to display in the modal

Tooltip Action

Show tooltip text on hover:

  • tooltipText: Text to display in the tooltip

Callback Action

Execute a custom JavaScript function when the hotspot is clicked:

  • callbackName: Name of the function to call (e.g., "handleHotspotClick")
  • callbackParams: JSON object with parameters to pass to the function

Example:

{
  "type": "callback",
  "callbackName": "handleHotspotClick",
  "callbackParams": {
    "hotspotId": "123",
    "action": "navigate"
  }
}

On the frontend, you would implement the callback function:

window.handleHotspotClick = function (params) {
  console.log("Hotspot clicked with params:", params);
  // Your custom logic here
};

Custom Action

Define a custom action with a name and JSON payload for flexible frontend handling:

  • customName: Name identifier for the custom action (e.g., "product-detail")
  • customPayload: JSON object with any data structure you need

Example:

{
  "type": "custom",
  "customName": "product-detail",
  "customPayload": {
    "productId": "123",
    "variant": "blue",
    "showModal": true
  }
}

On the frontend, you can handle custom actions based on the customName and use the customPayload as needed:

function handleHotspotClick(hotspot) {
  if (hotspot.action?.type === "custom") {
    switch (hotspot.action.customName) {
      case "product-detail":
        // Handle product detail action
        showProductDetail(hotspot.action.customPayload);
        break;
      default:
        console.log(
          "Custom action:",
          hotspot.action.customName,
          hotspot.action.customPayload,
        );
    }
  }
}

Using in Frontend

When rendering the image with hotspots on your frontend, you'll need to:

  1. Parse the JSON data from the custom field
  2. Render the image (the image object is automatically populated by the server)
  3. Position hotspots based on their coordinates
  4. Handle click events based on the action type

Note: The server automatically populates the image field with the full media object, so you can directly access data.image.url without needing to fetch the media separately.

Example React component:

import { ImageHotspotValue } from "./types";

function HotspotImage({ data }: { data: ImageHotspotValue }) {
  const handleHotspotClick = (hotspot: Hotspot) => {
    if (!hotspot.action) return;

    switch (hotspot.action.type) {
      case "link":
        if (hotspot.action.url) {
          window.open(hotspot.action.url, hotspot.action.target || "_self");
        }
        break;
      case "modal":
        // Show modal with hotspot.action.modalTitle and hotspot.action.modalContent
        break;
      case "tooltip":
        // Show tooltip with hotspot.action.tooltipText
        break;
      case "callback":
        if (
          hotspot.action.callbackName &&
          window[hotspot.action.callbackName]
        ) {
          window[hotspot.action.callbackName](hotspot.action.callbackParams);
        }
        break;
      case "custom":
        // Handle custom action based on customName and customPayload
        console.log(
          "Custom action:",
          hotspot.action.customName,
          hotspot.action.customPayload,
        );
        // Implement your custom action handling logic here
        break;
    }
  };

  return (
    <div className="hotspot-container">
      <img src={data.image?.url} alt={data.image?.alternativeText} />
      {data.hotspots?.map((hotspot) => (
        <div
          key={hotspot.id}
          className={`hotspot hotspot-${hotspot.type}`}
          style={{
            left: `${hotspot.x}%`,
            top: `${hotspot.y}%`,
            width: hotspot.width ? `${hotspot.width}%` : undefined,
            height: hotspot.height ? `${hotspot.height}%` : undefined,
          }}
          onClick={() => handleHotspotClick(hotspot)}
        >
          {hotspot.label}
        </div>
      ))}
    </div>
  );
}

License

MIT