Medium Zoom
Medium Zoom is a lightweight, responsive JavaScript library designed to replicate the elegant image zooming experience found on the Medium platform. Currently stable at version 1.1.0, the package sees active development with regular patch releases addressing bugs and minor enhancements, building upon its significant 1.0.0 refactor. Key differentiators include its high performance (aiming for 60fps), support for high-definition image loading on zoom, extensive customization options for margin, background, and scroll offset, and a pluggable architecture allowing for custom features and templates. It is framework-agnostic, working seamlessly across React, Vue, Angular, Svelte, and Solid, and offers comprehensive event handling for various zoom states. The library focuses on providing a smooth, intuitive user experience that is friendly to mouse, keyboard, and touch gestures.
Common errors
-
Uncaught TypeError: mediumZoom is not a function
cause Incorrect import statement or using CommonJS `require` when an ES module environment expects `import`.fixEnsure you are using `import mediumZoom from 'medium-zoom';` for ESM setups. If using CommonJS, ensure your build pipeline correctly handles the module export. -
TypeError: Cannot read properties of null (reading 'style')
cause The `mediumZoom` function was called with a selector that did not match any elements in the DOM, or the elements were not yet available when the script ran.fixVerify your CSS selector is correct and matches existing `<img>` elements. Wrap your `mediumZoom` initialization in a `DOMContentLoaded` listener or defer it until your images are present in the DOM. -
Zoom effect doesn't appear or the overlay is unstyled
cause The required CSS stylesheet for medium-zoom was not loaded or imported.fixAdd `import 'medium-zoom/dist/medium-zoom.css';` to your main JavaScript/TypeScript file or include a `<link>` tag for the CSS in your HTML. -
Images dynamically added to the DOM are not zoomable.
cause The `mediumZoom` function was initialized before the dynamic images existed, and the zoom instance was not updated to include them.fixAfter dynamically adding new images, use the `zoom.attach(selector)` method on your existing `mediumZoom` instance to make the new images zoomable.
Warnings
- breaking Version 1.0.0 introduced significant changes where most methods (excluding getters and animation methods) became chainable, and animation methods (`open()`, `close()`, `toggle()`) now return Promises. This may break existing code relying on previous return values or synchronous animation flow.
- gotcha The CSS styles for medium-zoom are not automatically included with the JavaScript. Failing to import the CSS will result in an unstyled zoom overlay and animations, making the feature appear broken or incomplete.
- gotcha Earlier versions of medium-zoom (prior to 1.0.4) had limited or no compatibility with Server-Side Rendering (SSR) environments due to direct use of browser-specific `window` objects. This could lead to build failures or runtime errors in SSR frameworks.
Install
-
npm install medium-zoom -
yarn add medium-zoom -
pnpm add medium-zoom
Imports
- mediumZoom
const mediumZoom = require('medium-zoom');import mediumZoom from 'medium-zoom';
- Zoom / Options (TypeScript Types)
import type { Zoom, Options } from 'medium-zoom'; - CSS Styles
import 'medium-zoom/medium-zoom.css';
import 'medium-zoom/dist/medium-zoom.css';
Quickstart
import mediumZoom from 'medium-zoom';
import 'medium-zoom/dist/medium-zoom.css';
document.addEventListener('DOMContentLoaded', () => {
// Initialize mediumZoom on all images with the class 'zoomable-image'
const zoom = mediumZoom('.zoomable-image', {
margin: 24, // Space between the image and the edge of the viewport
background: 'rgba(0, 0, 0, 0.8)', // Dark overlay background
scrollOffset: 40 // Scroll offset to close the zoom
});
// Attach additional images or selectors dynamically
zoom.attach('#another-zoomable-image');
// Listen for events: 'open', 'opened', 'close', 'closed'
zoom.on('open', (event) => {
console.log('Zoom effect starting for:', event.target);
// You can update options after the zoom is opened
zoom.update({ background: 'rgba(25, 18, 25, 0.95)' });
});
zoom.on('closed', () => {
console.log('Zoom effect finished closing.');
});
// Example of programmatic open (returns a Promise since v1.0.0)
// document.getElementById('open-btn')?.addEventListener('click', async () => {
// await zoom.open(document.querySelector('.zoomable-image'));
// console.log('Programmatic zoom opened.');
// });
});
// To make this code runnable, ensure your HTML contains:
// <img class="zoomable-image" src="https://picsum.photos/id/1018/400/300" alt="Forest road" />
// <img id="another-zoomable-image" src="https://picsum.photos/id/1025/400/300" alt="Pug dog" />