Components/ImageGallery

ImageGallery

Thumbnail grid with a fullscreen lightbox preview, clamped start index, and bounded previous/next navigation.

VerifiedSince 0.3.4

Usage

Loading demo...

Clicking a thumbnail opens the current image in a fullscreen lightbox: the image is contained in the viewport with the title, page count, previous/next and close controls on top of it.

Track Preview Opens

<script setup lang="ts">
function onOpen({ index, item }: { index: number, item: { id: string } }) {
  analytics.track('gallery_open', { index, imageId: item.id })
}
</script>

<template>
  <TxImageGallery :items="images" @open="onOpen" @close="onClose" />
</template>

Controlled Starting Image

<template>
  <TxImageGallery :items="screenshots" :start-index="selectedIndex" />
</template>

startIndex is clamped whenever it changes. It chooses the initial/current preview index but does not open the lightbox by itself.

Best Practices

  • Use stable id values; do not use array indexes for long-lived gallery data.
  • Provide name for informative images so button labels, alt text, and preview titles are meaningful.
  • Keep the list size modest. This component renders all thumbnails; it is not virtualized.
  • Do not pass untrusted remote image URLs without normalizing or proxying them at your application boundary.
  • Use startIndex for selected preview context, not as a visibility control.
  • Use @open for analytics or detail-panel coordination; do not mutate items synchronously in a way that invalidates the opened image.

API Reference

Props

PropTypeDefaultDescription
itemsImageGalleryItem[]requiredImages rendered as thumbnails and openable in the fullscreen preview.
startIndexnumber0Initial/current preview index, clamped to the available item range.

ImageGalleryItem

FieldTypeDescription
idstringStable key for thumbnail rendering.
urlstringImage URL used by thumbnails and the preview image.
namestringOptional display name used for labels, alt text, and the preview title.

Events

EventPayloadDescription
open{ index: number, item: ImageGalleryItem }Emitted after a thumbnail opens the fullscreen preview.
closevoidEmitted when the preview closes.

Slots

No public slots are exposed.

Exposed Methods

No public instance methods are exposed.

Overview

  • The thumbnail grid renders one native button type="button" for each item.
  • Thumbnail buttons use aria-label="Open {label} preview", where label is item.name or a generated Image N fallback.
  • Thumbnail and preview image alt text use item.name; unnamed images intentionally use empty alt text.
  • Empty items render no thumbnail buttons and cannot emit open.
  • Clicking a thumbnail clamps the clicked index, opens the fullscreen preview, and emits open with { index, item }.
  • startIndex changes are clamped to 0..items.length - 1.
  • When items becomes empty, the preview closes and the index resets to 0.
  • Preview navigation is bounded: previous is disabled at the first image, next is disabled at the last image.
  • When a navigation button becomes disabled at a boundary, focus moves to the other enabled navigation button so Escape and Tab remain inside the preview.
  • The preview title is the current image name, falling back to Preview.
  • The preview fills the viewport: the image is contained (never cropped) inside the space left by the header and footer bars, so both axes stay visible on any viewport shape.
  • The preview reuses TxModal in fullscreen mode, so it teleports to body, traps Tab focus, closes on Escape or the close button, and restores focus to the thumbnail that opened it.
  • Closing emits close.

Technologies

  • Reviewed against packages/tuffex/packages/components/src/image-gallery/src/types.ts, TxImageGallery.vue, and image-gallery.test.ts.
  • startIndex is clamped and updates the current preview index, but it never opens the fullscreen preview by itself.
  • Unnamed images intentionally use empty image alt text while thumbnail buttons still receive generated open labels.
  • The lightbox is TxModal with its fullscreen prop rather than a second custom overlay, so the shared focus trap, Escape handling, z-index allocation and focus restore stay in one place.
  • max-height: 70vh on the preview image was rejected: it letterboxes a portrait image into the middle band of a tall viewport instead of using the space the header and footer leave.
  • Component source: packages/tuffex/packages/components/src/image-gallery/src/TxImageGallery.vue.
  • Types: packages/tuffex/packages/components/src/image-gallery/src/types.ts.
  • Verified coverage: Coverage: packages/tuffex/packages/components/src/image-gallery/__tests__/image-gallery.test.ts verifies thumbnail labels and alt text, open payloads, bounded previous / next navigation, empty-list no-op behavior, start-index clamping, and close-on-empty updates.
查看源码
packages/tuffex/packages/components/src/image-gallery/index.ts