Skip to content

Component ​

Suitable for complex scenarios involving custom toolbars or images in dynamically rendered Markdown or HTML whose content is not known in advance. By default, it watches additions, removals and attribute changes of <img> elements inside the component and automatically updates the gallery.

Upgrading from an older major version

The Vue 3 (5.x) line is a rewrite with breaking changes. You can now use Viewer.js props, events and methods directly on the component. The legacy options prop is retained for compatibility, but is deprecated. Existing options-based galleries can migrate gradually.

Playground ​

Playground

vue
<script setup>
import { ref } from 'vue'
import { Viewer } from 'v-viewer'
const sourceImages = [
  '/images/photo-01.jpg',
  '/images/photo-02.jpg',
  '/images/photo-03.jpg',
  '/images/photo-04.jpg',
  '/images/photo-05.jpg',
  '/images/photo-06.jpg',
  '/images/photo-07.jpg',
  '/images/photo-08.jpg',
  '/images/photo-09.jpg',
  '/images/photo-10.jpg',
].map((original) => ({
  src: original.replace('/images/', '/images/thumbnails/'),
  'data-source': original,
}))
const images = ref(sourceImages.slice(0, 5))
const toolbar = ref(true)
function onViewed(event) {
  console.log(event.detail.index)
}
const gallery = ref(null)
function show() {
  gallery.value.show()
}
function add() {
  images.value.push(sourceImages[images.value.length])
}
function remove() {
  images.value.pop()
}
</script>

<template>
  <main class="viewer-example">
    <div class="controls">
      <button :disabled="images.length === sourceImages.length" @click="add">
        Add image
      </button>
      <button :disabled="images.length === 0" @click="remove">
        Remove image
      </button>
      <button class="open" :disabled="images.length === 0" @click="show()">
        Show viewer
      </button>
      <div class="toolbar" role="group" aria-label="Toggle toolbar">
        <span>Toggle toolbar</span>
        <button
          :aria-pressed="toolbar ? 'true' : 'false'"
          @click="toolbar = true"
        >
          On
        </button>
        <button
          :aria-pressed="toolbar ? 'false' : 'true'"
          @click="toolbar = false"
        >
          Off
        </button>
      </div>
    </div>
    <Viewer
      ref="gallery"
      :toolbar="toolbar"
      url="data-source"
      @viewed="onViewed"
      class="gallery"
      ><img
        v-for="(image, index) in images"
        :key="image.src"
        :src="image.src"
        :data-source="image['data-source']"
        :alt="`Landscape ${index + 1}`"
    /></Viewer>
  </main>
</template>

Props ​

Viewer.js props ​

These props map to Viewer.js options; click a name for its full documentation. Availability and defaults follow the installed Viewer.js version. Changes, including nested values, rebuild the instance after DOM updates.

PropTypePurpose
backdropboolean / stringControl the modal backdrop; static keeps clicks on it from closing the viewer.
buttonbooleanShow the button in the upper-right corner.
classNamestringAdd custom classes to the viewer root.
containerstring / ElementChoose the modal container using an element or CSS selector.
filterfunctionInclude images for which the filter returns true; exclude the others.
fullscreenboolean / FullscreenOptionsRequest browser fullscreen during playback, optionally with Fullscreen API settings.
focusbooleanFocus the active thumbnail on initialization; requires keyboard.
inheritedAttributesarrayChoose additional source-image attributes to copy; src and alt are always copied.
initialCoveragenumberSet the initial image coverage, greater than 0 and at most 1.
initialViewIndexnumberChoose the starting image index, also used when view() receives no index.
inlinebooleanDisplay the viewer inline when enabled, or in modal mode when disabled.
autoplaybooleanAdvance slides automatically during playback.
intervalnumberSet the delay between slides in milliseconds.
keyboardbooleanAllow keyboard controls.
loadingbooleanDisplay a loading indicator while fetching an image.
loopbooleanWrap image navigation between the first and last images.
magnifierboolean / objectShow a hover magnifier in fullscreen view, with configurable size, ratio and opacity; unavailable on touch screens.
maxZoomRationumber / functionLimit magnification with a ratio or a function of the image and its data.
minHeightnumberSet the minimum inline viewer height in pixels.
minWidthnumberSet the minimum inline viewer width in pixels.
minZoomRationumber / functionLimit reduction with a ratio or a function of the image and its data.
movablebooleanAllow image movement.
navbarboolean / number / string / objectConfigure thumbnail visibility, size and position, with further layout settings in object form.
navigationboolean / number / objectConfigure the side navigation buttons, including individual visibility and size.
preloadbooleanLoad adjacent images before they are viewed.
rotatablebooleanAllow image rotation.
rotateOnGesturebooleanRotate through gesture events, such as two-finger gestures in Mac Safari.
rotateOnTouchbooleanRotate with two fingers on a touch screen.
scalablebooleanAllow axis scaling, including horizontal and vertical flips.
slideOnTouchbooleanNavigate between images with touch swipes.
slideOnWheelboolean / stringNavigate with the wheel, optionally requiring modifier keys; applies over thumbnails or when wheel zoom does not handle the event.
titleboolean / number / function / arrayConfigure title visibility and content; the default uses alt or the filename from the URL.
toggleOnDblclickbooleanSwitch between natural and initial image sizes on double-click.
toolbarboolean / number / objectConfigure toolbar placement and button visibility, size and click behavior.
tooltipbooleanDisplay the current zoom percentage while zooming.
transitionboolean / objectEnable CSS transitions, or disable selected action transitions using an object.
urlstring / functionRead the full image URL from a named image attribute or a function result.
zIndexnumberSet the modal viewer’s CSS stacking order.
zIndexInlinenumberSet the inline viewer’s CSS stacking order.
zoomOnGesturebooleanZoom through gesture events, such as pinch gestures in Mac Safari.
zoomOnTouchbooleanZoom through dragging gestures on a touch screen.
zoomOnWheelboolean / stringZoom with the wheel, optionally requiring one or more modifier keys.
zoomRationumberSet the ratio increment for wheel zoom.
zoomablebooleanAllow image zooming.

v-viewer-specific props ​

PropTypePurpose
optionsViewerOptionsDefault {}. Deprecated compatibility entry; prefer direct props and Vue events.
rebuildbooleanfalse; rebuild instead of updating when images change.
observeboolean / numberDefault true (50ms); false disables observation; a non-negative number sets the batching window in milliseconds.

The component observes additions, removals and attribute changes of <img> elements inside it, including whole HTML subtree replacements. It calls update() by default, or recreates the instance when rebuild is enabled.

See automatic updates with observe for values, update timing and usage guidance.

Events ​

These are Viewer.js events exposed as Vue events. Click an event name for its original documentation.

Event handlers receive the original DOM event, with operation data in event.detail. Use @show.prevent or event.preventDefault() to cancel a cancelable operation.

NameWhen it fires / useful data
readyThe viewer UI is initialized. In modal mode this can happen on the first opening.
show / shownBefore opening / after the opening transition completes in modal mode.
hide / hiddenBefore closing / after the closing transition completes in modal mode.
view / viewedBefore displaying an image / after it is displayed. detail.index is zero-based; image and originalImage identify the preview and source images.
move / movedBefore / after moving. detail.x, y, oldX and oldY describe the position change.
rotate / rotatedBefore / after rotation. detail.degree and oldDegree describe the angle change.
scale / scaledBefore / after scaling or flipping. detail.scaleX, scaleY, oldScaleX and oldScaleY describe the change.
zoom / zoomedBefore / after zooming. detail.ratio and oldRatio contain the zoom ratios.
play / stopBefore starting / stopping a slideshow.
playingBefore showing each slide during playback.

Callbacks ​

The legacy options prop still accepts Viewer.js callbacks such as options.viewed. This compatibility entry is deprecated; prefer Vue events such as @viewed. Callbacks receive the same original DOM event as the component event. When both are supplied, both run.

Methods ​

Viewer.js methods ​

Call these through the component ref. Each name links to the corresponding Viewer.js method.

MethodPurpose
show(immediate?)Open the modal, immediately when passed true; modal mode only.
hide(immediate?)Close the modal, immediately when passed true; modal mode only.
view(index?)View the indexed image, defaulting to initialViewIndex; open the viewer first if hidden.
prev(loop?)View the previous image; loop allows wrapping to the last image and defaults to false.
next(loop?)View the next image; loop allows wrapping to the first image and defaults to false.
move(x, y?)Move by relative offsets; omitted y uses x.
moveTo(x, y?)Move to absolute coordinates; omitted y uses x.
rotate(degree)Rotate by a relative angle: positive turns right, negative turns left.
rotateTo(degree)Set an absolute rotation angle.
scale(scaleX, scaleY?)Scale both axes; omitted scaleY uses scaleX, and negative factors flip the image.
scaleX(scaleX)Scale horizontally; -1 flips the horizontal axis.
scaleY(scaleY)Scale vertically; -1 flips the vertical axis.
zoom(ratio, showTooltip?, pivot?)Zoom by a relative ratio: positive enlarges, negative reduces; optionally specify a tooltip and pivot.
zoomTo(ratio, showTooltip?, pivot?)Set an absolute zoom ratio, with 1 representing natural size; optionally specify a tooltip and pivot.
play(fullscreen?)Start image playback, optionally requesting browser fullscreen.
stop()End image playback.
full()Switch an inline viewer into modal mode.
exit()Return an expanded inline viewer from modal mode to inline display.
showTooltip()Display the current zoom percentage when tooltip is enabled; renamed from native tooltip() to avoid the prop collision.
toggle()Switch between the current and natural image sizes.
reset()Restore the image’s initial state.
update()Refresh the gallery after source images are added, removed or reordered.
destroy()Dispose of the viewer instance.

Wait for @viewed before manipulating an image. Except for update() and destroy(), the methods listed above return the Viewer.js instance, or undefined when none exists.

update() and destroy() return nothing. update() creates a missing instance and takes no options—change props to configure the component. destroy() also disconnects observation and clears the component’s instance reference, retaining the source images.

v-viewer-specific methods ​

MethodPurpose
createViewer()Create an instance if none exists, using current props and image DOM.
rebuildViewer()Destroy the current instance and recreate it using current props and image DOM; create one if absent.

For underlying instance data, read gallery.value.viewer.

Slots ​

Default slot ​

Render images and custom layouts in the default slot.

vue
<Viewer :toolbar="false">
  <img v-for="src in images" :key="src" :src="src" />
</Viewer>

Rendered HTML can also be used as the slot content:

vue
<Viewer>
  <article v-html="html" />
</Viewer>

Toolbar slots ​

Use Vue templates, icon components and event bindings to customize the toolbar.

SlotBehavior
toolbar-appendAdd content after the toolbar, including after a custom toolbar slot.
toolbarReplace all built-in toolbar buttons with custom icons, layout and interactions.

Both slots receive image (the current preview's HTMLImageElement, or undefined before it is viewed), index (zero-based), and the component's Viewer.js methods, such as zoom, rotate, reset and next. Slot parameters update with the preview state.

toolbar: false hides the entire toolbar, including its slots. Without a replacement slot, the existing toolbar configuration still determines which buttons are present.

Example code
vue
<script setup>
import { ref } from 'vue'
import { Viewer } from 'v-viewer'
const images = [
  '/images/photo-01.jpg',
  '/images/photo-02.jpg',
  '/images/photo-03.jpg',
  '/images/photo-04.jpg',
  '/images/photo-05.jpg',
]
const inline = ref(true)
const custom = ref(false)
</script>

<template>
  <main class="viewer-example toolbar-example">
    <div class="controls">
      <label><input v-model="inline" type="checkbox" /> Inline mode</label>
      <label
        ><input v-model="custom" type="checkbox" /> Replace the toolbar</label
      >
    </div>
    <div class="toolbar-stage" :class="{ 'is-inline': inline }">
      <Viewer :inline="inline" :focus="!inline" :min-height="320">
        <div v-show="!inline" class="gallery">
          <img
            v-for="(src, index) in images"
            :key="src"
            :src="src"
            :alt="'Landscape ' + (index + 1)"
          />
        </div>
        <template v-if="custom" #toolbar="{ zoom, rotate, reset }">
          <button
            type="button"
            class="viewer-slot-button viewer-custom-button"
            title="Zoom in"
            aria-label="Zoom in"
            @click="zoom(0.1)"
          >
            <svg
              width="20"
              height="20"
              viewBox="0 0 24 24"
              fill="none"
              stroke="currentColor"
              stroke-width="1.75"
              stroke-linecap="round"
              stroke-linejoin="round"
              aria-hidden="true"
            >
              <circle cx="10" cy="10" r="6.5" />
              <path d="m15 15 5.5 5.5M7 10h6m-3-3v6" />
            </svg>
          </button>
          <button
            type="button"
            class="viewer-slot-button viewer-custom-button"
            title="Rotate"
            aria-label="Rotate"
            @click="rotate(90)"
          >
            <svg
              width="20"
              height="20"
              viewBox="0 0 24 24"
              fill="none"
              stroke="currentColor"
              stroke-width="1.75"
              stroke-linecap="round"
              stroke-linejoin="round"
              aria-hidden="true"
            >
              <rect x="4" y="11" width="9" height="9" rx="1.5" />
              <path d="M5 7a9 9 0 0 1 15 7m0-5v5h-5" />
            </svg>
          </button>
          <button
            type="button"
            class="viewer-slot-button viewer-custom-button"
            title="Reset"
            aria-label="Reset"
            @click="reset()"
          >
            <svg
              width="20"
              height="20"
              viewBox="0 0 24 24"
              fill="none"
              stroke="currentColor"
              stroke-width="1.75"
              stroke-linecap="round"
              stroke-linejoin="round"
              aria-hidden="true"
            >
              <path
                d="M8 3H3v5m13-5h5v5M3 16v5h5m13-5v5h-5M8 12a4 4 0 1 0 1-2.6M8 7v3h3"
              />
            </svg>
          </button>
        </template>
        <template #toolbar-append="{ image, index }">
          <a
            v-if="image"
            class="viewer-slot-button"
            :class="{ 'viewer-custom-button': custom }"
            :href="image.src"
            :download="image.alt"
            :title="'Download image ' + (index + 1)"
            :aria-label="'Download image ' + (index + 1)"
          >
            <svg
              width="16"
              height="16"
              viewBox="0 0 20 20"
              fill="none"
              stroke="currentColor"
              stroke-width="2"
              aria-hidden="true"
            >
              <path d="M10 2v10m-4-4 4 4 4-4M3 12v5h14v-5" />
            </svg>
          </a>
        </template>
      </Viewer>
    </div>
  </main>
</template>

Migrating from older versions ​

vue
<!-- Legacy: supported, but deprecated -->
<Viewer :options="{ toolbar: false, viewed: onViewed }">
  <img src="/photo.jpg" />
</Viewer>

<!-- Recommended -->
<Viewer :toolbar="false" @viewed="onViewed">
  <img src="/photo.jpg" />
</Viewer>

Released under the MIT License.