This library is a React.js
implementation of
Medium.com's image
zoom that allows
for images to work together for a βzoomingβ effect and works regardless of
parent elements that have overflow: hidden
or
parents with transform properties.
As an added bonus, it will let you zoom anything (see the Storybook Examples
for more).
- Installation
- Basic Usage
- API
- Migrating From v3 to v4
- Contributors
- Storybook Examples
- Changelog
- Contributing
- Code of Conduct
$ npm i react-medium-image-zoom
or
$ yarn add react-medium-image-zoom
or
<!-- this build only needs React to be already present -->
<script src="https://unpkg.com/react-medium-image-zoom"></script>
Import the component and the CSS, wrap whatever you want to be "zoomable" with this component, and the component will handle it's own state:
import React from 'react'
import Zoom from 'react-medium-image-zoom'
import 'react-medium-image-zoom/dist/styles.css'
const MyComponent = () => (
<Zoom>
<img
alt="that wanaka tree"
src="/path/to/thatwanakatree.jpg"
width="500"
/>
</Zoom>
)
export default MyComponent
You can zoom anything, so <picture>
, <figure>
, and even <div>
elements
are all valid:
// <picture>
<Zoom>
<picture>
<source media="(max-width: 800px)" srcSet="/path/to/teAraiPoint.jpg" />
<img
alt="that wanaka tree"
src="/path/to/thatwanakatree.jpg"
width="500"
/>
</picture>
</Zoom>
// <figure>
<figure>
<Zoom>
<img
alt="that wanaka tree"
src="/path/to/thatwanakatree.jpg"
width="500"
/>
</Zoom>
<figcaption>That Wanaka Tree</figcaption>
</figure>
// <div> that looks like a circle
<Zoom>
<div
aria-label="A blue circle"
style={{
width: 300,
height: 300,
borderRadius: '50%',
backgroundColor: '#0099ff'
}}
/>
</Zoom>
Import the Controlled
component and the CSS, wrap whatever you want to
be "zoomable" with this component and then dictate the zoomed/unzoomed state to
the component. Here, we will automatically zoom the component once the image has
loaded:
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 handleImgLoad = useCallback(() => {
setIsZoomed(true)
}, [])
const handleZoomChange = useCallback(shouldZoom => {
setIsZoomed(shouldZoom)
}, [])
return (
<ControlledZoom isZoomed={isZoomed} onZoomChange={handleZoomChange}>
<img
alt="that wanaka tree"
onLoad={handleImgLoad}
src="/path/to/thatwanakatree.jpg"
width="500"
/>
</ControlledZoom>
)
)
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.
There is also an example in the Storybook
Examples of how to use a
Controlled
component to create a full-screen slideshow gallery.
You can pass these options to either the default or controlled components.
Prop | Type | Required | Default | Details |
---|---|---|---|---|
closeText |
String |
no | 'Unzoom Image' |
Accessible label text for when you want to unzoom |
openText |
String |
no | 'Zoom Image' |
Accessible label text for when you want to zoom |
overlayBgColorEnd |
String |
no | 'rgba(255, 255, 255, 0.95)' |
Modal overlay background color at end of zoom |
overlayBgColorStart |
String |
no | 'rgba(255, 255, 255, 0)' |
Modal overlay background color at start of zoom |
portalEl |
Element |
no | document.body |
DOM Element to which we will append the zoom modal |
scrollableEl |
Window |
no | window |
DOM Element to which we will listen for scroll events to determine if we should unzoom |
transitionDuration |
Number |
no | 300 |
Transition duration in milliseconds for the component to use on zoom and unzoom. Set this to 0 to disable the animation |
wrapStyle |
Object |
no | null |
Optional style object to pass to the wrapper div . Useful when you want the <Zoom> container to be width: '100%' , for example |
zoomMargin |
Number |
no | 0 |
Offset in pixels the zoomed image should be from the window ' boundaries |
zoomZindex |
Number |
no | 2147483647 |
z-index value for the zoom overlay |
You can pass these options to only the controlled component.
Prop | Type | Required | Default | Details |
---|---|---|---|---|
isZoomed |
bool |
yes | false |
Tell the component whether or not it should be zoomed |
onZoomChange |
Function |
no | Function.prototype |
Listen for hints from the component about when you should zoom (true value) or unzoom (false value) |
In v3, you might have code like this:
<ImageZoom
image={{
src: '/path/to/bridge.jpg',
alt: 'Golden Gate Bridge',
className: 'img',
style: { width: '50em' }
}}
zoomImage={{
src: '/path/to/bridge-big.jpg',
alt: 'Golden Gate Bridge'
}}
zoomMargin={80}
/>
In v3
, you would pass properties for your normal image
that would be zoomed,
and you would pass an optional zoomImage
that would be a higher quality image
that would replace the original image when zoomed.
The problem with v3
was that it tried to assume too many things about what it
is you were trying to zoom, and this resulted in overly complex and
near-unmaintainable code that had a number of bugs.
In v4
, you can zoom the bridge example above like this:
<Zoom zoomMargin={40}>
<img
src="/path/to/bridge.jpg"
alt="Golden Gate Bridge"
className="img"
style={{ width: '50em'}}
/>
</Zoom>
We've removed the zoomImage
functionality (there is an issue for us
to consider re-adding something like it),
but as it was not a primary use case for many consumers, we opted to ship v4
without it.
Please see the Controlled component
(Controlled
) section for further
documentation regarding controlled components that used the isZoomed
,
onZoom
, and onUnzoom
properties.
Thanks goes to these wonderful people (emoji key):
This project follows the all-contributors specification. Contributions of any kind welcome!