The original medium.com-inspired image zooming library for React.
Features:
<img />
, including allobject-fit
values, anyobject-position
, andloading="lazy"
<div>
and<span>
with anybackground-image
,background-size
, andbackground-position
<picture>
with<source />
and<img />
<figure>
with<img />
- Accessibility:
- JAWS in Chrome, Edge, and Firefox (Windows)
- NVDA in Chrome, Edge, and Firefox (Windows)
- VoiceOver in Safari (macOS, iOS)
- TalkBack in Chrome (Android)
- Zero
dependencies
View the storybook examples to see various usages. NOTE: Help is wanted with making the examples more informative, so please start a discussion if you're able to help!
npm install --save react-medium-image-zoom
import React from 'react'
import Zoom from 'react-medium-image-zoom'
import 'react-medium-image-zoom/dist/styles.css'
export const MyImg = () => (
<Zoom>
<img
alt="That Wanaka Tree, New Zealand by Laura Smetsers"
src="/path/to/thatwanakatree.jpg"
width="500"
/>
</Zoom>
)
This library's compilation target is ES2022
, but it only uses features from
ES2020
and below. If you find you need to support older browsers, add
react-medium-image-zoom
to your build system.
You can pass these options to either the Uncontrolled
(default) or
Controlled
components.
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
// Your image
children: ReactNode
// Provide your own unzoom button icon
// Default: ICompress
IconUnzoom?: ElementType
// Provide your own zoom button icon
// Default: IEnlarge
IconZoom?: ElementType
// Scrollable parent element
// Default: window
scrollableEl?: Window | HTMLElement
// Higher quality image attributes to use on zoom
zoomImg?: ImgHTMLAttributes<HTMLImageElement>
// Offset in pixels the zoomed image should
// be from the window's boundaries
zoomMargin?: number
}
You can pass these options to only the Controlled
component.
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
}
Import the component and the CSS, wrap your image with the 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'
// <img />
export const MyImg = () => (
<Zoom>
<img
alt="That Wanaka Tree, New Zealand by Laura Smetsers"
src="/path/to/thatwanakatree.jpg"
width="500"
/>
</Zoom>
)
// <div>
export const MyDiv = () => (
<Zoom>
<div
aria-label="That Wanaka Tree, New Zealand by Laura Smetsers"
role="img"
style={{
backgroundColor: '#fff',
backgroundImage: `url("/path/to/thatwanakatree.jpg")`,
backgroundPosition: '50%',
backgroundRepeat: 'no-repeat',
backgroundSize: 'cover',
height: '0',
paddingBottom: '56%',
width: '100%',
}}
/>
</Zoom>
)
// <picture>
export const MyPicture = () => (
<Zoom>
<picture>
<source media="(max-width: 800px)" srcSet="/path/to/teAraiPoint.jpg" />
<img
alt="A beautiful, serene setting in nature"
src="/path/to/thatwanakatree.jpg"
width="500"
/>
</picture>
</Zoom>
)
// <figure>
export const MyFigure = () => (
<figure>
<Zoom>
<img
alt="That Wanaka Tree, New Zealand by Laura Smetsers"
src="/path/to/thatwanakatree.jpg"
width="500"
/>
</Zoom>
<figcaption>Photo by Laura Smetsers</figcaption>
</figure>
)
Import the Controlled
component and the CSS, wrap your image with the
component, and then dictate the isZoomed
state to the component.
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 (
<ControlledZoom isZoomed={isZoomed} onZoomChange={handleZoomChange}>
<img
alt="That wanaka tree, alone in the water near mountains"
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.
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 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, but it's hard to guess at what these values should
be.
TODO
Thanks goes to these wonderful people (emoji key):
This project follows the all-contributors specification. Contributions of any kind welcome!