Elements

Image gallery

A compact grid of returned images that opens each one in a shared lightbox.

fig. 01

Installation

npx shadcn@latest add "@assistant-ui/elements-image-gallery"
First time? Set up a runtime

Runtime components read their state from an assistant-ui runtime. Add one to an existing project:

npx assistant-ui@latest init

Then wrap your app in a runtime provider:

import { AssistantRuntimeProvider } from "@assistant-ui/react";
import { useChatRuntime, AssistantChatTransport } from "@assistant-ui/ai-sdk";

export default function App() {
  const runtime = useChatRuntime({
    transport: new AssistantChatTransport({ api: "/api/chat" }),
  });

  return (
    <AssistantRuntimeProvider runtime={runtime}>
      {/* your components */}
    </AssistantRuntimeProvider>
  );
}

The installation guide covers new projects, templates, and API routes.

Image gallery groups several images a tool returned, such as search results or generated variants, into a compact grid without making the transcript heavy.

Getting started

A backend tool can return its finished images as { images }. Its render function passes that result straight to ImageGallery, so a later tool result creates a separate gallery in the transcript.

Render the tool result

app/toolkit.tsx
"use client";

import {
  defineToolkit,
  type ToolCallMessagePartComponent,
} from "@assistant-ui/react";
import {
  ImageGallery,
  type GalleryImage,
} from "@/components/assistant-ui/elements/image-gallery";

type ImageSearchResult = { images: GalleryImage[] };

const ImageSearchToolUI: ToolCallMessagePartComponent<
  { query: string },
  ImageSearchResult
> = ({ result }) => <ImageGallery images={result?.images ?? []} />;

export const toolkit = defineToolkit({
  show_image_results: {
    type: "backend",
    render: ImageSearchToolUI,
  },
});

Anatomy

<div data-slot="image-gallery">
  <button aria-label="Open image: Sunlight through a redwood grove">
    <img loading="lazy" />
  </button>
  <div role="dialog" aria-modal="true">
    <img />
    <div>Caption, source, counter, and image controls</div>
  </div>
</div>

The grid uses two columns and grows to three when its container has room. It shows six images by default. When there are more, the final visible tile reads +N and opens at that image rather than hiding the rest of the gallery. The dialog keeps its place with previous and next controls, ArrowLeft and ArrowRight, and Escape.

Examples

Show an overflow tile

Set maxVisible when the surrounding layout needs a smaller grid. The final visible tile remains the next image in order.

<ImageGallery images={images} maxVisible={3} />

An image can carry a caption and source. The source becomes an external link only for a safe http, https, mailto, or relative URL.

<ImageGallery
  images={[
    {
      id: "river",
      src: "/results/river.jpg",
      alt: "A river seen from above",
      caption: "Reference photograph",
      source: {
        label: "National Park Service",
        url: "https://www.nps.gov/",
      },
    },
  ]}
/>

API reference

Tool result

FieldTypeDescription
result.imagesGalleryImage[]The tool result passed to the gallery after the backend call completes.
GalleryImage.idstringStable image identifier reported to onOpen.
GalleryImage.srcstringImage URL or data URI.
GalleryImage.altstringAccessible image description and tile label.
GalleryImage.captionstringOptional text in the lightbox caption row.
GalleryImage.source{ label?, url? }Optional source label, linked only when its URL is safe.