React Medium Image Zoom
π π The original medium.com-inspired image zooming library for React (since 2016)
Install / Use
npx skills add rpearce/react-medium-image-zoomInstalls into whichever agent you are using.
README
react-medium-image-zoom
The original medium.com-inspired image zooming library for React.
View the storybook examples to see various usages.
Features:
<img />, including allobject-fitvalues, anyobject-position, andloading="lazy"<div>and<span>with anybackground-image,background-size, andbackground-position<picture>with<source />and<img /><figure>with<img /><svg>- 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:
- Zero
dependencies
Requirements to know about:
<dialog>element (caniuse dialog)ResizeObserver(caniuse 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"
- Build a React.js Image Zoom Feature with react-medium-image-zoom Library and State Management
Quickstart
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>
)
API
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
// Allow swipe gesture to unzoom.
// Default: true
canSwipeToUnzoom?: boolean
// Your image (required).
children: ReactNode
// Custom CSS className to add to the zoomed <dialog>.
classDialog?: string
// Provide your own unzoom button icon.
// Default: ICompress
IconUnzoom?: ElementType
// Provide your own zoom button icon.
// Default: IEnlarge
IconZoom?: ElementType
// Disables the zoom/unzoom behavior.
// Default: false
isDisabled?: boolean
// First argument: boolean value of a new zoomed state (Uncontrolled
// component) or a suggested new state (Controlled component).
// Second argument: object containing the event that triggered the change.
// Default: undefined
onZoomChange?: (
value: boolean,
data: { event: React.SyntheticEvent | Event },
) => void
// 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 <p> or <button>, for example.
// Default: 'div'
wrapElement?: 'div' | 'span'
// Provide your own custom modal content component.
ZoomContent?: (props: {
img: ReactElement | null
buttonUnzoom: ReactElement<HTMLButtonElement>
onUnzoom: () => void
}) => ReactElement
// Higher quality image attributes to use on zoom.
zoomImg?: ImgHTMLAttributes<HTMLImageElement>
// 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.
export interface ControlledProps {
// ...same as UncontrolledProps
// Tell the component whether or not it should be zoomed
// Default: false
isZoomed: boolean
}
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.
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>
)
Controlled component
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.
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 and alter it to your liking. The latter is the best
option, given rems 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.
Below is some example code that demonstrates how to use this feature.
export const MyImg = () => (
<Zoom ZoomContent={CustomZoomContent}>
<img
alt="That Wanaka Tree, New Zealand by Laura Smetsers"
src="/path/to/thatwanakatree.jpg"
width="500"
/>
</Zoom>
)
const CustomZoomContent = ({
/** Default unzoom button */
buttonUnzoom,
/** Current state of the zoom modal: UNLOADED, LOADING, LOADED, UNLOADING */
modalState,
/** Your image, prepped for zooming */
img,
/** A state to check if the zoom img is loaded (useful for loading state) */
// isZoomImgLoaded,
/**
* 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.
*/
//onUnzoom,
}) => {
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'
Related Skills
node-connect
385.5kDiagnose OpenClaw Android, iOS, or macOS node pairing, QR/setup code, route, auth, and connection failures.
imsg
385.5kUse the imsg CLI from OpenClaw agents for iMessage/SMS DMs, groups, replies, reactions, polls, watching, and private-API actions.
Writing Hookify Rules
140.6kThis skill should be used when the user asks to "create a hookify rule", "write a hook rule", "configure hookify", "add a hookify rule", or needs guidance on hookify rule syntax and patterns.
Agent Development
140.6kThis skill should be used when the user asks to "create an agent", "add an agent", "write a subagent", "agent frontmatter", "when to use description", "agent examples", "agent tools", "agent colors", "autonomous agent", or needs guidance on agent structure, system prompts, triggering conditions, orβ¦
