https://github.com/rpearce/react-medium-image-zoom
π π The original medium.com-inspired image zooming library for React (since 2016)
https://github.com/rpearce/react-medium-image-zoom
hacktoberfest image-zoom medium props react react-images reactjs typescript zoom zoom-images zoomable
Last synced: about 1 year ago
JSON representation
π π The original medium.com-inspired image zooming library for React (since 2016)
- Host: GitHub
- URL: https://github.com/rpearce/react-medium-image-zoom
- Owner: rpearce
- License: bsd-3-clause
- Created: 2016-07-13T18:15:49.000Z (almost 10 years ago)
- Default Branch: main
- Last Pushed: 2025-05-09T00:03:54.000Z (about 1 year ago)
- Last Synced: 2025-05-12T13:15:06.118Z (about 1 year ago)
- Topics: hacktoberfest, image-zoom, medium, props, react, react-images, reactjs, typescript, zoom, zoom-images, zoomable
- Language: TypeScript
- Homepage: https://rpearce.github.io/react-medium-image-zoom/
- Size: 97.3 MB
- Stars: 1,993
- Watchers: 10
- Forks: 103
- Open Issues: 4
-
Metadata Files:
- Readme: README.md
- Changelog: CHANGELOG.md
- Contributing: CONTRIBUTING.md
- Funding: .github/FUNDING.yml
- License: LICENSE
- Code of conduct: CODE_OF_CONDUCT.md
- Security: SECURITY.md
Awesome Lists containing this project
README
# react-medium-image-zoom
[](https://www.npmjs.com/package/react-medium-image-zoom) [](https://bundlejs.com/?q=react-medium-image-zoom) [](https://www.npmjs.com/package/react-medium-image-zoom) [](#contributors-)
The original [medium.com-inspired image zooming](https://medium.design/image-zoom-on-medium-24d146fc0c20)
library for [React](https://reactjs.org).
[View the storybook examples](https://rpearce.github.io/react-medium-image-zoom/)
to see various usages.
Features:
* `
`, including all [`object-fit`](https://developer.mozilla.org/en-US/docs/Web/CSS/object-fit)
values, any [`object-position`](https://developer.mozilla.org/en-US/docs/Web/CSS/object-position),
and [`loading="lazy"`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/img#attr-loading)
* `
` and `` with any [`background-image`](https://developer.mozilla.org/en-US/docs/Web/CSS/background-image),
[`background-size`](https://developer.mozilla.org/en-US/docs/Web/CSS/background-size),
and [`background-position`](https://developer.mozilla.org/en-US/docs/Web/CSS/background-position)
* `` with `` and `
`
* `` with `
`
* ``
* [Custom zoom modal content](#custom-zoom-modal-content) (π)
* Accessibility:
* JAWS in Chrome, Edge, and Firefox (Windows)
* NVDA in Chrome, Edge, and Firefox (Windows)
* VoiceOver in Safari (macOS, iOS)
* TalkBack in Chrome (Android)
* Supports popular tools:
* [Gatsby](https://www.gatsbyjs.com) and [gatsby-plugin-image](https://www.gatsbyjs.com/plugins/gatsby-plugin-image/)
* [Next.js](https://nextjs.org/docs/api-reference/next/image)
* Zero `dependencies`
Requirements to know about:
* `` element ([caniuse dialog](https://caniuse.com/dialog))
* `ResizeObserver` ([caniuse ResizeObserver](https://caniuse.com/mdn-api_resizeobserver))
* Package build target is `ES2021`. If you need to support older environments,
run this package through your build system.
## Media and Tutorials
* [2024-08-2024 β _React Round Up_ β "Building a Seamless Image Zoom Feature"](https://topenddevs.com/podcasts/react-round-up/episodes/building-a-seamless-image-zoom-feature-rru-265)
* [Build a React.js Image Zoom Feature with react-medium-image-zoom Library and State Management](https://www.youtube.com/watch?v=w24gLJzmXp0)
## Quickstart
```bash
npm install --save react-medium-image-zoom
```
```javascript
import React from 'react'
import Zoom from 'react-medium-image-zoom'
import 'react-medium-image-zoom/dist/styles.css'
export const MyImg = () => (
)
```
## API
You can pass these options to either the `Uncontrolled` (default) or
`Controlled` components.
```typescript
export interface UncontrolledProps {
// Accessible label text for when you want to unzoom.
// Default: 'Minimize image'
a11yNameButtonUnzoom?: string
// Accessible label text for when you want to zoom.
// Default: 'Expand image'
a11yNameButtonZoom?: string
// Allow swipe gesture to unzoom.
// Default: true
canSwipeToUnzoom?: boolean
// Your image (required).
children: ReactNode
// Custom CSS className to add to the zoomed .
classDialog?: string
// Provide your own unzoom button icon.
// Default: ICompress
IconUnzoom?: ElementType
// Provide your own zoom button icon.
// Default: IEnlarge
IconZoom?: ElementType
// Swipe gesture threshold after which to unzoom.
// Default: 10
swipeToUnzoomThreshold?: number
// Specify what type of element should be used for
// internal component usage. This is useful if the
// image is inside a
or , for example.
// Default: 'div'
wrapElement?: 'div' | 'span'
// Provide your own custom modal content component.
ZoomContent?: (props: {
img: ReactElement | null;
buttonUnzoom: ReactElement;
onUnzoom: () => void;
}) => ReactElement;
// Higher quality image attributes to use on zoom.
zoomImg?: ImgHTMLAttributes
// Offset in pixels the zoomed image should
// be from the window's boundaries.
// Default: 0
zoomMargin?: number
}
```
You can pass these options to only the `Controlled` component.
```typescript
export interface ControlledProps {
// ...same as UncontrolledProps
// Tell the component whether or not it should be zoomed
// Default: false
isZoomed: boolean
// Listen for hints from the component about when you
// should zoom (`true` value) or unzoom (`false` value)
onZoomChange?: (value: boolean) => void
}
```
## Basic Usage
### Uncontrolled component (default)
Import the component and the CSS, wrap your image with the component, and the
component will handle it's own state.
```javascript
import React from 'react'
import Zoom from 'react-medium-image-zoom'
import 'react-medium-image-zoom/dist/styles.css'
//
export const MyImg = () => (
)
//
export const MyDiv = () => (
)
//
export const MyPicture = () => (
)
//
export const MyFigure = () => (
Photo by Laura Smetsers
)
```
### Controlled component
Import the `Controlled` component and the CSS, wrap your image with the
component, and then dictate the `isZoomed` state to the component.
```javascript
import React, { useCallback, useState } from 'react'
import { Controlled as ControlledZoom } from 'react-medium-image-zoom'
import 'react-medium-image-zoom/dist/styles.css'
const MyComponent = () => {
const [isZoomed, setIsZoomed] = useState(false)
const handleZoomChange = useCallback(shouldZoom => {
setIsZoomed(shouldZoom)
}, [])
return (
)
}
export default MyComponent
```
The `onZoomChange` prop accepts a callback that will receive `true` or `false`
based on events that occur (like click or scroll events) to assist you in
determining when to zoom and unzoom the component.
## Styles
You can import the default styles from `react-medium-image-zoom/dist/styles.css`
and override the values from your code, or you can copy [the styles.css
file](./source/styles.css) and alter it to your liking. The latter is the best
option, given `rem`s should be used instead of `px` to account for different
default browser font sizes, and it's hard for a library to guess at what these
values should be.
An example of customizing the transition duration, timing function, overlay
background color, and unzoom button styles with `:focus-visible` can be found in
this story: https://rpearce.github.io/react-medium-image-zoom/?path=/story/img--custom-modal-styles
### Custom zoom modal content
If you want to customize the zoomed modal experience with a caption, form, or
other set of components, you can do so by providing a custom component to the
`ZoomContent` prop.
[View the live example of custom zoom modal content.](https://rpearce.github.io/react-medium-image-zoom/?path=/story/img--modal-figure-caption)
Below is some example code that demonstrates how to use this feature.
```javascript
export const MyImg = () => (
)
const CustomZoomContent = ({
buttonUnzoom, // default unzoom button
modalState, // current state of the zoom modal: UNLOADED, LOADING, LOADED, UNLOADING
img, // your image, prepped for zooming
//onUnzoom, // unused here, but a callback to manually unzoom the image and
// close the modal if you want to use your own buttons or
// listeners in your custom experience
}) => {
const [isLoaded, setIsLoaded] = useState(false)
useLayoutEffect(() => {
if (modalState === 'LOADED') {
setIsLoaded(true)
} else if (modalState === 'UNLOADING') {
setIsLoaded(false)
}
}, [modalState])
const classCaption = isLoaded
? 'zoom-caption zoom-caption--loaded'
: 'zoom-caption'
return <>
{buttonUnzoom}
{img}
That Wanaka Tree, also known as the Wanaka Willow, is a willow tree
located at the southern end of Lake WΔnaka in the Otago region of New
Zealand.
Wikipedia,
That Wanaka Tree
>
}
```
## Migrating From v4 to v5
Here are the prop changes from `v4` to be aware of:
* `closeText` was renamed to `a11yNameButtonUnzoom`
* `openText` was renamed to `a11yNameButtonZoom`
* `overlayBgColorStart` was removed and is now controlled via the CSS selector `[data-rmiz-modal-overlay="hidden"]`
* `overlayBgColorEnd` was removed and is now controlled via the CSS selector `[data-rmiz-modal-overlay="visible"]`
* `portalEl` was removed, for we are using the `` element now
* `transitionDuration` was removed and is now controlled via the CSS selectors `[data-rmiz-modal-overlay]` and `[data-rmiz-modal-img]`
* `wrapElement` was removed then added back in `v5.1.0`
* `wrapStyle` was removed
* `zoomZindex` was removed, for we are using the `` element now
And you can now provide `zoomImg` props to specify a different image to load when zooming.
## Contributors β¨
Thanks goes to these wonderful people ([emoji key](https://allcontributors.org/docs/en/emoji-key)):

Robert Pearce
π» π¬ β οΈ π π‘ π¨ π π€ π

Cameron Bothner
π» π π π‘ π€ π β οΈ

Jeremy Bini
π» π

ismay
π π€

Rajit Singh
π

Roberto Saccon
π

wtfdaemon
π

Josh Sloat
π π» π‘ π π€ π π¨ π¬

Aswin
π¬

Alex Shelkovskiy
π

Adrian Bindiu
π

Kendall Buchanan
π

Kaycee
π»

Anuj
π π¬

Ludwig Frank
π π»

LX
π π€

Rosen Tomov
π

Tom Moor
π» π

Johan Preynat
π» π

Rahul Gaba
π» π

Spencer Davis
π» π€ π π¨

dnlnvl
π»

Madi
π€

Ben Hood
π€ π π‘ π

Navilan
π€

13806
π

Akshay Kadam (A2K)
π π€

Jake Stewart
π π€

hhh
π

@davalapar
π

Sun Knudsen
π» π π€ π‘ π¬ π β οΈ π

Douglas Galdino
π» π π π€ π‘ π β οΈ

Mohammed Faragallah
π π€ π‘

Youngrok Kim
π» π

Nandhagopal Ezhilmaran
π

Mattia Astorino
π

Dan Wood
π

Zachery C Gentry
π

xmflsct
π

Will.iam
π» β οΈ

Gourav Goyal
π

Joshua Chen
π π»

David Edler
π π»

rikusen0335
π€

Surjith S M
π€

developergunny
π

Khan Mohsin
π¬

Robin Goudeketting
π

Botros Toro
π€

Christian Guevara
π¬

Johan Book
π

Paolo Di Bello
π€

Tommaso De Rossi
π π

Lezan
π π€

Ibrahim H. Sluma
π

Ben Gotow
π

Rubon72
π

wanderingme
π

Thomas Strobl
π π€ π‘ π¬ π

Songkeys
π π€ π‘ π¬ π

AntoineS92
π

Sindre Aubert
π

mx
π

Sander Heling
π

Yida Zhang
π π»

Nir
π

hhatakeyama
π

Paco
π π€

LichLord91
π

just-small-potato
π€

walmsles
π

tenshin
π¬

Steven Tey
π

Sergey
π π» π

Diego Azevedo
π

Faizan Ahmad
π

Kunal L.
π

Kevin Wang
π€

u3u
π€ π

Hong
π»

Wojciech Rok
π» π€

Matija
π

Jiayi Hu
π

Zeit der Forschung
π

Andrei Barabas
π π€

NΓ©meth Benedek
π

iMalFect
π

Karl Horky
π π€ π

ιζ¨ζ
π
This project follows the [all-contributors](https://github.com/all-contributors/all-contributors) specification. Contributions of any kind welcome!