Customize the built-in lightbox
Change captions, actions, counters, or slide markup without rebuilding the lightbox from primitives.
Use this guide when you like Nuxt Photo's built-in lightbox behavior, but want different UI.
Use this focused customization path for:
- custom captions
- different top-bar actions
- a custom counter
- slide markup that still lives inside the built-in lightbox
If you need a different component structure, use the primitives guide.
1. Wrap the included lightbox
Create a component that renders <Lightbox> and overrides only the slots you need.
<script setup lang="ts">
import { Lightbox } from '@lupinum/nuxt-photo/app'
</script>
<template>
<Lightbox>
<template #counter="{ activeIndex, count }">
<div class="text-sm opacity-70">{{ activeIndex + 1 }} of {{ count }}</div>
</template>
<template #caption="{ photo, index }">
<div class="space-y-1">
<div class="text-xs uppercase tracking-wide opacity-60">Frame {{ index + 1 }}</div>
<h2 v-if="photo?.caption" class="text-lg font-medium">
{{ photo.caption }}
</h2>
<p v-if="photo?.description" class="text-sm opacity-80">
{{ photo.description }}
</p>
</div>
</template>
<template
#actions="{
activeIndex,
count,
prev,
next,
close,
toggleZoom,
isZoomedIn,
zoomAllowed,
controlsDisabled,
}"
>
<button :disabled="controlsDisabled || activeIndex <= 0" @click="prev">Prev</button>
<button :disabled="controlsDisabled || activeIndex >= count - 1" @click="next">Next</button>
<button :disabled="controlsDisabled || !zoomAllowed" @click="toggleZoom()">
{{ isZoomedIn ? 'Fit' : 'Zoom' }}
</button>
<button :disabled="controlsDisabled" @click="close">Close</button>
</template>
</Lightbox>
</template>That keeps the built-in gesture handling, transitions, focus behavior, and slide wiring. You only replace the visible pieces.
2. Use it on one component
Pass the wrapper through the lightbox prop on the ready-made component you want to customize.
PhotoAlbum
<script setup lang="ts">
import MyLightbox from '~/components/MyLightbox.vue'
</script>
<template>
<PhotoAlbum :photos="photos" :lightbox="MyLightbox" />
</template>PhotoGroup
<script setup lang="ts">
import MyLightbox from '~/components/MyLightbox.vue'
</script>
<template>
<PhotoGroup :photos="photos" :lightbox="MyLightbox">
<PhotoAlbum :photos="photos" />
</PhotoGroup>
</template>PhotoCarousel
<script setup lang="ts">
import MyLightbox from '~/components/MyLightbox.vue'
</script>
<template>
<PhotoCarousel :photos="photos" :lightbox="MyLightbox" />
</template>3. Customize slides only when you need to
The included <Lightbox> also supports a slide slot:
<script setup lang="ts">
import { Lightbox, PhotoImage } from '@lupinum/nuxt-photo/app'
</script>
<template>
<Lightbox>
<template #slide="{ photo }">
<figure class="relative h-full w-full">
<PhotoImage :photo="photo" context="slide" class="h-full w-full object-contain" />
<figcaption class="absolute right-4 bottom-4 rounded bg-black/70 px-3 py-2 text-white">
{{ photo.caption }}
</figcaption>
</figure>
</template>
</Lightbox>
</template>Use this when the built-in lightbox is still the right shell, but a photo needs an overlay or different image composition.
When this guide is enough
Stay on this path when:
- the built-in lightbox behavior is correct
- you only want different UI chrome
- you want to keep the existing lightbox behavior
Move to Build a lightbox from primitives when you need to compose the overlay, viewport, controls, and caption yourself.
Apply the lightbox globally
If most galleries in the app should use the same custom lightbox, set it once globally.
import { LightboxComponentKey } from '@lupinum/nuxt-photo/app'
import MyLightbox from '~/components/MyLightbox.vue'
export default defineNuxtPlugin((nuxtApp) => {
nuxtApp.vueApp.provide(LightboxComponentKey, MyLightbox)
})Ready-made components now use MyLightbox unless their lightbox prop provides a
different component. The global component does not enable a lightbox by itself.
Photo and PhotoCarousel still require lightbox to be enabled. An explicit
component passed through the lightbox prop takes precedence over the global
component.