The original medium.com-inspired image zooming library for Svelte.
View the storybook examples
to see various usages.
Features:
<img />
, including all object-fit
values, any object-position
,
and loading="lazy"
<div>
and <span>
with any background-image
,
background-size
,
and background-position
<picture>
with <source />
and <img />
(coming)<figure>
with <img />
(coming)<svg>
(coming)dependencies
Requirements to know about:
<dialog>
element (caniuse dialog)ResizeObserver
(caniuse ResizeObserver)ESNext
. If you need to support older environments,
run this package through your build system.npm install --save svelte-medium-image-zoom
<script lang="ts">
import Zoom from 'svelte-medium-image-zoom';
import 'svelte-medium-image-zoom/dist/styles.css';
</script>
<Zoom>
<img
alt="That Wanaka Tree, New Zealand by Laura Smetsers"
src="/media/andres-iga.jpg"
width="500"
/>
</Zoom>
Note: component type props are rendered as snippets
, check this for more.
example use
export interface ZoomProps {
// Accessible label text for when you want to unzoom.
// Default: 'Minimize image'
a11y_name_button_unzoom?: string;
// Accessible label text for when you want to zoom.
// Default: 'Expand image'
a11y_name_button_zoom?: string;
// Your image (required).
children: Snippet<[]>;
// Custom CSS class to add to the unzoom and zoom buttons.
class_button?: string;
// Custom CSS class to add to the zoomed <dialog>.
class_dialog?: string;
// Transition duration for modal image and overlay elements.
// Default: 300ms
duration?: string | number;
// Provide your own unzoom button icon.
// Default: ICompress
icon_unzoom?: Snippet<[]>;
// Provide your own zoom button icon.
// Default: IEnlarge
icon_zoom?: Snippet<[]>;
// Tell the component whether or not it should be zoomed.
// Default: false
is_zoomed?: boolean;
// Listen for hints from the component about when you
// should zoom (`true` value) or unzoom (`false` value).
on_zoom_change?: (value: boolean) => void;
// 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'
wrap_element?: 'div' | 'span';
// Provide your own custom modal content component.
zoom_content?: Snippet<[{
img: Snippet<[]>;
button_unzoom: Snippet<[]>;
modal_state: IModalState;
handle_unzoom: () => void;
}]>;
// Offset in pixels the zoomed image should
// be from the window's boundaries.
// Default: 0
zoom_margin?: number;
}
Import the component and the CSS, wrap your image with the component, and the component will handle it's own state.
<script lang="ts">
import Zoom from 'svelte-medium-image-zoom';
import 'svelte-medium-image-zoom/dist/styles.css';
</script>
<!-- <img /> -->
<Zoom>
<img
alt="That Wanaka Tree, New Zealand by Laura Smetsers"
src="/path/to/thatwanakatree.jpg"
width="500"
/>
</Zoom>
<!-- <div> -->
<Zoom>
<div
aria-label="That Wanaka Tree, New Zealand by Laura Smetsers"
role="img"
class="div-img"
style="
background-color: #fff;
background-image: url(/media/laura-smetsers.jpg);
background-position: 50%;
background-repeat: no-repeat;
background-size: cover;
width: 500px;
height: 300px;
"
></div>
</Zoom>
Import the component and the CSS, wrap your image with the component, and then dictate the is_zoomed
with on_zoom_change
handler state to the component.
<script lang="ts">
import Zoom from 'svelte-medium-image-zoom';
import 'svelte-medium-image-zoom/dist/styles.css';
let is_zoomed = $state(false);
</script>
<Zoom
{is_zoomed}
on_zoom_change={(z) => (is_zoomed = z)}
wrap_element="span"
zoom_margin={25}
>
<img
alt="That Wanaka Tree, New Zealand by Laura Smetsers"
src="/path/to/thatwanakatree.jpg"
width="500"
decoding="async"
loading="lazy"
/>
</Zoom>
The on_zoom_change
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 svelte-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, 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: custom-modal-styles.
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
zoom_content
prop.
View the live example of custom zoom modal content.
Below is some example code that demonstrates how to use this feature.
<script lang="ts">
import Zoom from 'svelte-medium-image-zoom';
import 'svelte-medium-image-zoom/dist/styles.css';
</script>
<Zoom>
{#snippet zoom_content({ img, button_unzoom, modal_state })}
{@render button_unzoom()}
<figure>
{@render img()}
<figcaption
class="zoom-caption zoom-caption--bottom"
class:zoom-caption--loaded={modal_state === 'LOADED'}
>
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.
<cite className="zoom-caption-cite">
Wikipedia, <a
className="zoom-caption-link"
href="https://en.wikipedia.org/wiki/That_Wanaka_Tree"
>
That Wanaka Tree
</a>
</cite>
</figcaption>
</figure>
{/snippet}
<img
alt="That Wanaka Tree, New Zealand by Laura Smetsers"
src="/path/to/thatwanakatree.jpg"
width="500"
decoding="async"
loading="lazy"
/>
</Zoom>
This project is inspired from rpearce's react-medium-image-zoom
library.