Building a beautiful gallery component

When I built this page, I was searching for a gallery component that wasn't completely ugly. There are many I looked at that I didn't like.

Either the features were too poor or there was way too much JavaScript for the straightforward job. I wanted to have a gallery that....

  1. natively exists in vue/nuxt
  2. supports webp
  3. has keyboard shortcuts
  4. looks nice
  5. works with my cms prismic.io

My starting point and changes

Of all the components I looked at, only one had a convincing approach: vue-gallery-slideshow by KitchenStories

The design of it is not pretty, but the code is comprehensible - It is also very easy to use: just pass an array of images and an index to it and it builds the gallery magically. For me, the css was largely irrelevant. Moreover, I use tailwindcss in the rest of the application anyway. So I rewrote the original css in tailwindcss and made many adjustments for mobile and desktop.

For displaying the images I use Nuxt/Image. It is a wrapper module which automatically loads images from various service providers and CDN, among others prismic.io. Replacing the original standard image tag with the nuxt image module was easy. This way images are now optimized by pricmic and served as webp with an jpg/png fallback.

Even though I am very happy with the result so far, I miss a few features:

  • Firstly I miss is a loading indicator for slow internet speeds. Image loading can take up to a few seconds on large screens on mobile networks.
  • Scroll lock for the background is also missing.
  • Swipe gestures for mobile would also be great

Demo

Demo 2

How to use it

In the end the AppGallery component is a single file with just two props: images and index

<template>
  ...
  // The client-only tag prevents is from being renderd on server side with nuxt
  // you don't need it when using plain vue
  <client-only placeholder="Loading...">
    <AppGallery
      v-if="index !== null"
      :images="images"
      :index="index"
      @close="index = null"
    />
  </client-only>
</template>


<script>
import { ref } from '@nuxtjs/composition-api'

export default {
  setup() {
    const index = ref(null)
    const images =  ref([
      'https://unsplash.com/photos/9nya3cwmq2c',
      'https://unsplash.com/photos/9nya3cwmq2c',
      'https://unsplash.com/photos/9nya3cwmq2c',
      'https://unsplash.com/photos/9nya3cwmq2c',
    ])

    return { index, images }
  },
}
</script>

➜ Source code for the component is on GitHub (As is the rest of this page, too):
https://github.com/lennartzellmer/zellmer.dev/blob/10762477c7fdf7b6617e2f325925876315147557/components/AppGallery.vue