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

htmx-magnify

v1.0.0

Published

htmx extension for image magnification with zoom glass effect

Readme

htmx-magnify


Highlights

  • Zero dependencies -- lightweight, no runtime bloat
  • Drop-in htmx extension -- works with hx-magnify attribute, no JS required
  • Mouse, touch, and keyboard support out of the box
  • Fully configurable -- glass size, zoom, border, radius, shadow, cursor style
  • Accessible -- ARIA roles, screen reader announcements, focus-visible support
  • Auto-reinit on htmx swaps -- re-initializes automatically when content changes
  • ~4 KB minified + gzipped

Table of Contents

Installation

npm

npm install htmx-magnify
import "htmx-magnify";
import "htmx-magnify/src/htmx-magnify.css";

CDN (unpkg)

<link rel="stylesheet" href="https://unpkg.com/htmx-magnify@1/src/htmx-magnify.css">
<script src="https://unpkg.com/htmx-magnify@1/dist/htmx-magnify.min.js"></script>

CDN (jsDelivr)

<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/htmx-magnify@1/src/htmx-magnify.css">
<script src="https://cdn.jsdelivr.net/npm/htmx-magnify@1/dist/htmx-magnify.min.js"></script>

Direct download

Download src/htmx-magnify.js and src/htmx-magnify.css into your project and include them with a <script> and <link> tag.

Note: htmx (>=1.9.0) is a peer dependency. Load it before htmx-magnify.

Quick Start

Add the hx-magnify attribute to any element containing an image:

<div hx-magnify hx-magnify-src="/path/to/image.jpg">
  <img src="/path/to/image.jpg" alt="Product photo">
</div>

That's it. The extension automatically:

  • Creates a magnifier glass element on hover/focus
  • Tracks mouse and touch position over the image
  • Renders a zoomed-in view inside the glass
  • Cleans up when the mouse leaves or focus is lost

Configuration

All configuration is done via HTML attributes -- no JavaScript needed:

<div hx-magnify
     hx-magnify-src="/image.jpg"
     hx-magnify-width="120"
     hx-magnify-height="120"
     hx-magnify-zoom="2.5"
     hx-magnify-radius="50"
     hx-magnify-border-width="3"
     hx-magnify-border-color="#000"
     hx-magnify-border-style="solid"
     hx-magnify-shadow="true"
     hx-magnify-cursor="none">
  <img src="/image.jpg" alt="Product">
</div>

Attributes Reference

| Attribute | Type | Default | Description | |---|---|---|---| | hx-magnify | flag | -- | Enables the magnifier on this element | | hx-magnify-src | string | (required) | URL of the high-resolution image to magnify | | hx-magnify-alt | string | "magnifier-image" | Alt text when no <img> is present in the container | | hx-magnify-img-width | string | -- | CSS width applied to the image (e.g. "400px", "100%") | | hx-magnify-img-height | string | -- | CSS height applied to the image (e.g. "300px", "auto") | | hx-magnify-width | number | 100 | Width of the magnifier glass in pixels | | hx-magnify-height | number | 100 | Height of the magnifier glass in pixels | | hx-magnify-zoom | number | 2 | Zoom multiplier (1 = no zoom, higher = more zoom) | | hx-magnify-radius | number | 50 | Border-radius percentage (0 = rectangle, 50 = circle) | | hx-magnify-border-width | number | 3 | Border width in pixels | | hx-magnify-border-color | string | "#000" | Border color (any CSS color value) | | hx-magnify-border-style | string | "solid" | Border style (solid, dashed, dotted, etc.) | | hx-magnify-shadow | boolean | true | Show a drop shadow on the glass ("true" or "false") | | hx-magnify-cursor | string | "none" | CSS cursor when hovering the image ("crosshair", "zoom-in", "pointer", etc.) |

Shape Examples

Circle glass:

<div hx-magnify hx-magnify-src="/image.jpg"
     hx-magnify-width="120" hx-magnify-height="120"
     hx-magnify-radius="50">
  <img src="/image.jpg" alt="Product">
</div>

Rectangle glass:

<div hx-magnify hx-magnify-src="/image.jpg"
     hx-magnify-width="160" hx-magnify-height="100"
     hx-magnify-radius="10">
  <img src="/image.jpg" alt="Product">
</div>

No shadow, dashed border:

<div hx-magnify hx-magnify-src="/image.jpg"
     hx-magnify-shadow="false"
     hx-magnify-border-style="dashed"
     hx-magnify-border-color="#4a90e2">
  <img src="/image.jpg" alt="Product">
</div>

Features

Touch Support

Works on mobile devices with touch events. The magnifier follows finger position and prevents scrolling during interaction.

<div hx-magnify hx-magnify-src="/image.jpg">
  <img src="/image.jpg" alt="Product">
</div>

Tip: On touch devices, the magnifier activates on touch and deactivates when the finger lifts.

Keyboard Navigation

When the magnifier is visible, keyboard users can:

| Key | Action | |---|---| | Arrow Up | Move the glass up by 10px | | Arrow Down | Move the glass down by 10px | | Arrow Left | Move the glass left by 10px | | Arrow Right | Move the glass right by 10px | | Escape | Close the magnifier |

Note: The glass position is clamped to image boundaries, so it won't move beyond the image edges.

Accessibility

  • ARIA roles -- glass has role="img" with aria-label="Image magnifier"
  • Screen reader live region -- announces magnifier state changes (aria-live="polite")
  • Focus management -- container gets htmx-magnify-container class with outline on :focus-visible
  • Keyboard operable -- full magnifier control without a mouse

Custom Events

The extension dispatches custom events on the container element for integration with your application:

| Event | When | event.detail | |---|---|---| | magnifier-initialized | Glass element created and ready | container element | | magnifier-visible | Glass shown (mouseenter / focusin) | container element | | magnifier-invisible | Glass hidden (mouseleave / focusout) | container element | | magnifier-moved | Glass position updated | container element |

const magnifier = document.querySelector("[hx-magnify]");

magnifier.addEventListener("magnifier-initialized", (e) => {
  console.log("Magnifier ready");
});

magnifier.addEventListener("magnifier-visible", (e) => {
  console.log("Magnifier shown");
});

magnifier.addEventListener("magnifier-invisible", (e) => {
  console.log("Magnifier hidden");
});

magnifier.addEventListener("magnifier-moved", (e) => {
  console.log("Magnifier moved");
});

Dynamic Reconfiguration

You can change magnifier settings at runtime by updating attributes and re-processing with htmx:

const magnifier = document.querySelector("#my-magnifier");

// Clean up existing instance
magnifier._htmxMagnifier.cleanup();

// Update attributes
magnifier.setAttribute("hx-magnify-zoom", "3");
magnifier.setAttribute("hx-magnify-width", "150");

// Re-initialize
htmx.process(magnifier);

htmx Integration

Works seamlessly with htmx content swaps. The extension automatically re-initializes when new content is loaded via htmx:afterSwap and cleans up on htmx:afterRemoveNode:

<button hx-get="/api/product-image" hx-target="#image-container" hx-swap="innerHTML">
  Load Image
</button>

<div id="image-container">
  <div hx-magnify hx-magnify-src="/api/product-image">
    <img src="/api/product-image" alt="Product">
  </div>
</div>

Note: No extra configuration needed. The extension hooks into htmx lifecycle events automatically.

Programmatic Usage

If you need to initialize magnifiers outside of htmx:

import { initMagnifier } from "htmx-magnify";

// Initialize a single container
const container = document.querySelector("#my-magnifier");
initMagnifier(container);

// Initialize all magnifiers on the page
document.querySelectorAll("[hx-magnify]").forEach(initMagnifier);

API Reference

initMagnifier(container)

Manually initialize a magnifier on a container element.

  • container (HTMLElement) -- A DOM element with hx-magnify and hx-magnify-src attributes
  • Returns: undefined
  • Side effects: Adds htmx-magnify-container class, creates glass element, attaches event listeners
  • Idempotent: Calling on an already-initialized container is a no-op
import { initMagnifier } from "htmx-magnify";

const container = document.querySelector("#my-magnifier");
initMagnifier(container);

DEFAULTS

Object containing the default configuration values:

import { DEFAULTS } from "htmx-magnify";

console.log(DEFAULTS); // { width: 100, height: 100, zoom: 2, radius: 50, ... }

| Property | Value | |---|---| | width | 100 | | height | 100 | | zoom | 2 | | radius | 50 | | borderStyle | "solid" | | borderColor | "#000" | | borderWidth | 3 | | shadow | true | | cursor | "none" |

container._htmxMagnifier

Internal handle attached to each initialized container. Contains:

| Property | Type | Description | |---|---|---| | _htmxMagnifier.config | Object | Current configuration | | _htmxMagnifier.cleanup() | Function | Removes glass, event listeners, and resets the container | | _htmxMagnifier.handleShow() | Function | Programmatically show the magnifier | | _htmxMagnifier.handleHide() | Function | Programmatically hide the magnifier |

const container = document.querySelector("[hx-magnify]");

// Show magnifier programmatically
container._htmxMagnifier.handleShow();

// Hide magnifier programmatically
container._htmxMagnifier.handleHide();

// Full cleanup (removes glass, listeners, sr-only element)
container._htmxMagnifier.cleanup();

Development

# Install dependencies
npm install

# Run dev server with demo
npm run dev

# Run tests
npm test

# Run tests in watch mode
npm run test:watch

# Run tests with coverage
npm run test:coverage

# Lint
npm run lint

# Build for production
npm run build

Project Structure

htmx-magnify/
├── src/
│   ├── htmx-magnify.js      # Main extension source
│   └── htmx-magnify.css     # Styles for glass, container, sr-only
├── dist/
│   ├── htmx-magnify.js      # ESM bundle
│   └── htmx-magnify.min.js  # IIFE minified bundle
├── demo/
│   └── index.html           # Interactive demo page
├── test/
│   ├── setup.js             # Vitest + jsdom setup, mocks
│   └── htmx-magnify.test.js # Unit tests (28 tests)
├── .github/workflows/
│   ├── ci.yml               # Lint, test, build (Node 18/20/22)
│   ├── release.yml          # Manual version bump + GitHub release
│   └── publish.yml          # npm publish on release
├── package.json
├── vitest.config.js
└── .eslintrc.json

Contributing

See CONTRIBUTING.md for guidelines on:

  • Setting up the development environment
  • Running tests and linting
  • Submitting pull requests

Security

To report security vulnerabilities, please use GitHub's private vulnerability reporting. See SECURITY.md for details.

License

MIT