Ecosyste.ms: Awesome

An open API service indexing awesome lists of open source software.

Awesome Lists | Featured Topics | Projects

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 23 hours ago
JSON representation

πŸ”Ž 🏞 The original medium.com-inspired image zooming library for React (since 2016)

Awesome Lists containing this project

README

        

# react-medium-image-zoom

[![npm version](https://img.shields.io/npm/v/react-medium-image-zoom.svg)](https://www.npmjs.com/package/react-medium-image-zoom) [![react-medium-image-zoom bundlejs badge](https://deno.bundlejs.com/?q=react-medium-image-zoom&badge=&config={%22esbuild%22:{%22external%22:[%22react%22,%22react-dom%22]}})](https://bundlejs.com/?q=react-medium-image-zoom) [![npm downloads](https://img.shields.io/npm/dm/react-medium-image-zoom.svg)](https://www.npmjs.com/package/react-medium-image-zoom) [![All Contributors](https://img.shields.io/badge/all_contributors-88-orange.svg)](#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

* [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)

## 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 = () => (

That Wanaka Tree, New Zealand by Laura Smetsers

)
```

## 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 = () => (

That Wanaka Tree, New Zealand by Laura Smetsers

)

//


export const MyDiv = () => (



)

//
export const MyPicture = () => (



A beautiful, serene setting in nature


)

//
export const MyFigure = () => (


That Wanaka Tree, New Zealand by Laura Smetsers

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 (

That wanaka tree, alone in the water near mountains

)
}

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 = () => (

That Wanaka Tree, New Zealand by Laura Smetsers

)

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
Robert Pearce

πŸ’» πŸ’¬ ⚠️ πŸ› πŸ’‘ 🎨 πŸ‘€ πŸ€” πŸ“–
Cameron Bothner
Cameron Bothner

πŸ’» πŸ“– πŸ› πŸ’‘ πŸ€” πŸ‘€ ⚠️
Jeremy Bini
Jeremy Bini

πŸ’» πŸ›
ismay
ismay

πŸ› πŸ€”
Rajit Singh
Rajit Singh

πŸ›
Roberto Saccon
Roberto Saccon

πŸ›
wtfdaemon
wtfdaemon

πŸ›


Josh Sloat
Josh Sloat

πŸ› πŸ’» πŸ’‘ πŸ‘€ πŸ€” πŸ“– 🎨 πŸ’¬
Aswin
Aswin

πŸ’¬
Alex Shelkovskiy
Alex Shelkovskiy

πŸ›
Adrian Bindiu
Adrian Bindiu

πŸ›
Kendall Buchanan
Kendall Buchanan

πŸ›
Kaycee
Kaycee

πŸ’»
Anuj
Anuj

πŸ› πŸ’¬


Ludwig Frank
Ludwig Frank

πŸ› πŸ’»
LX
LX

πŸ› πŸ€”
Rosen Tomov
Rosen Tomov

πŸ›
Tom Moor
Tom Moor

πŸ’» πŸ›
Johan Preynat
Johan Preynat

πŸ’» πŸ›
Rahul Gaba
Rahul Gaba

πŸ’» πŸ›
Spencer Davis
Spencer Davis

πŸ’» πŸ€” πŸ‘€ 🎨


dnlnvl
dnlnvl

πŸ’»
Madi
Madi

πŸ€”
Ben Hood
Ben Hood

πŸ€” πŸ› πŸ’‘ πŸ‘€
Navilan
Navilan

πŸ€”
13806
13806

πŸ›
Akshay Kadam (A2K)
Akshay Kadam (A2K)

πŸ› πŸ€”
Jake Stewart
Jake Stewart

πŸ› πŸ€”


hhh
hhh

πŸ›
@davalapar
@davalapar

πŸ›
Sun Knudsen
Sun Knudsen

πŸ’» πŸ› πŸ€” πŸ’‘ πŸ’¬ πŸ‘€ ⚠️ πŸ“–
Douglas Galdino
Douglas Galdino

πŸ’» πŸ“– πŸ› πŸ€” πŸ’‘ πŸ‘€ ⚠️
Mohammed Faragallah
Mohammed Faragallah

πŸ› πŸ€” πŸ’‘
Youngrok Kim
Youngrok Kim

πŸ’» πŸ›
Nandhagopal Ezhilmaran
Nandhagopal Ezhilmaran

πŸ›


Mattia Astorino
Mattia Astorino

πŸ›
Dan Wood
Dan Wood

πŸ“–
Zachery C Gentry
Zachery C Gentry

πŸ›
xmflsct
xmflsct

πŸ›
Will.iam
Will.iam

πŸ’» ⚠️
Gourav Goyal
Gourav Goyal

πŸ“–
Joshua Chen
Joshua Chen

πŸ› πŸ’»


David Edler
David Edler

πŸ› πŸ’»
rikusen0335
rikusen0335

πŸ€”
Surjith S M
Surjith S M

πŸ€”
developergunny
developergunny

πŸ›
Khan Mohsin
Khan Mohsin

πŸ’¬
Robin Goudeketting
Robin Goudeketting

πŸ›
Botros Toro
Botros Toro

πŸ€”


Christian Guevara
Christian Guevara

πŸ’¬
Johan Book
Johan Book

πŸ›
Paolo Di Bello
Paolo Di Bello

πŸ€”
Tommaso De Rossi
Tommaso De Rossi

πŸ“– πŸ›
Lezan
Lezan

πŸ› πŸ€”
Ibrahim H. Sluma
Ibrahim H. Sluma

πŸ›
Ben Gotow
Ben Gotow

πŸ›


Rubon72
Rubon72

πŸ›
wanderingme
wanderingme

πŸ›
Thomas Strobl
Thomas Strobl

πŸ› πŸ€” πŸ’‘ πŸ’¬ πŸ‘€
Songkeys
Songkeys

πŸ› πŸ€” πŸ’‘ πŸ’¬ πŸ‘€
AntoineS92
AntoineS92

πŸ›
Sindre Aubert
Sindre Aubert

πŸ›
mx
mx

πŸ›


Sander Heling
Sander Heling

πŸ›
Yida Zhang
Yida Zhang

πŸ› πŸ’»
Nir
Nir

πŸ›
hhatakeyama
hhatakeyama

πŸ›
Paco
Paco

πŸ› πŸ€”
LichLord91
LichLord91

πŸ›
just-small-potato
just-small-potato

πŸ€”


walmsles
walmsles

πŸ›
tenshin
tenshin

πŸ’¬
Steven Tey
Steven Tey

πŸ›
Sergey
Sergey

πŸ› πŸ’» πŸ“–
Diego Azevedo
Diego Azevedo

πŸ“–
Faizan Ahmad
Faizan Ahmad

πŸ›
Kunal L.
Kunal L.

πŸ›


Kevin Wang
Kevin Wang

πŸ€”
u3u
u3u

πŸ€” πŸ‘€
Hong
Hong

πŸ’»
Wojciech Rok
Wojciech Rok

πŸ’» πŸ€”
Matija
Matija

πŸ›
Jiayi Hu
Jiayi Hu

πŸ›
Zeit der Forschung
Zeit der Forschung

πŸ›


Andrei Barabas
Andrei Barabas

πŸ› πŸ€”
NΓ©meth Benedek
NΓ©meth Benedek

πŸ›
iMalFect
iMalFect

πŸ›
Karl Horky
Karl Horky

πŸ› πŸ€” πŸ‘€

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