---
title: Gallery
description: Gallery layouts for stills, projects, and visual work.
group: Blocks
order: 27
---

A few ways to give visual work some room. Replace the frames with your own images.

## Grid

An even image grid with two columns on narrow screens and three when wide.

```tsx
"use client";

import { cn } from "@/lib/utils";

type Gallery01Props = {
  className?: string;
};

const IMAGES = [
  "/assets/brand/demos/attachments/attachment-1.png",
  "/assets/brand/demos/attachments/attachment-2.png",
  "/assets/brand/demos/attachments/attachment-3.png",
  "/assets/brand/demos/attachments/attachment-4.png",
  "/assets/brand/demos/attachments/attachment-5.png",
  "/assets/brand/demos/attachments/attachment-1.png",
] as const;

export function Gallery01({ className }: Gallery01Props) {
  return (
    <section className={cn("@container w-full bg-background", className)}>
      <div className="mx-auto w-full max-w-4xl px-4 py-10 @[32rem]:px-6 @[32rem]:py-14">
        <div className="mx-auto max-w-md text-center">
          <h2 className="text-xl font-medium tracking-wide text-foreground @[32rem]:text-2xl">
            Gallery
          </h2>
          <p className="mt-2 text-sm tracking-wide text-muted-foreground">
            A simple grid of images — swap in your own shots.
          </p>
        </div>
        <ul className="mt-8 grid grid-cols-2 gap-2 @[40rem]:grid-cols-3 @[40rem]:gap-3">
          {IMAGES.map((src, index) => (
            <li
              key={`${src}-${index}`}
              className="aspect-square overflow-hidden rounded-xl bg-muted"
            >
              <img src={src} alt="" className="size-full object-cover" />
            </li>
          ))}
        </ul>
      </div>
    </section>
  );
}
```

### Installation

```bash
npx @arctis-sh/@arctis-sh/ui@latest add gallery-01
```

### Usage

```tsx
import { Gallery01 } from "@/components/blocks/gallery/gallery-01"
```

```tsx
<Gallery01 />
```

## Caption cards

A denser grid of filled image cards, each with a short caption.

```tsx
"use client";

import { cn } from "@/lib/utils";

type Gallery02Props = {
  className?: string;
};

const IMAGES = [
  {
    src: "/assets/brand/demos/attachments/attachment-1.png",
    caption: "Launch hero",
  },
  {
    src: "/assets/brand/demos/attachments/attachment-2.png",
    caption: "Token surfaces",
  },
  {
    src: "/assets/brand/demos/attachments/attachment-3.png",
    caption: "Detail shots",
  },
  {
    src: "/assets/brand/demos/attachments/attachment-4.png",
    caption: "Product UI",
  },
  {
    src: "/assets/brand/demos/attachments/attachment-5.png",
    caption: "Brand moments",
  },
  {
    src: "/assets/brand/demos/attachments/attachment-2.png",
    caption: "Dark mode",
  },
] as const;

export function Gallery02({ className }: Gallery02Props) {
  return (
    <section className={cn("@container w-full bg-background", className)}>
      <div className="mx-auto w-full max-w-4xl px-4 py-10 @[32rem]:px-6 @[32rem]:py-14">
        <div className="mx-auto max-w-md text-center">
          <h2 className="text-xl font-medium tracking-wide text-foreground @[32rem]:text-2xl">
            Selected frames
          </h2>
          <p className="mt-2 text-sm tracking-wide text-muted-foreground">
            Filled image cards with a short caption under each shot.
          </p>
        </div>
        <ul className="mt-8 grid grid-cols-1 gap-3 @[32rem]:grid-cols-2 @[40rem]:grid-cols-3">
          {IMAGES.map((image) => (
            <li
              key={image.caption}
              className="overflow-hidden rounded-xl bg-muted p-2"
            >
              <div className="aspect-[4/3] overflow-hidden rounded-lg bg-background">
                <img
                  src={image.src}
                  alt=""
                  className="size-full object-cover"
                />
              </div>
              <p className="px-1 pt-2.5 pb-1 text-xs tracking-wide text-muted-foreground">
                {image.caption}
              </p>
            </li>
          ))}
        </ul>
      </div>
    </section>
  );
}
```

### Installation

```bash
npx @arctis-sh/@arctis-sh/ui@latest add gallery-02
```

### Usage

```tsx
import { Gallery02 } from "@/components/blocks/gallery/gallery-02"
```

```tsx
<Gallery02 />
```

## Marquee

An infinite horizontal strip of frames that pauses when hovered.

```tsx
"use client";

import { cn } from "@/lib/utils";

type Gallery03Props = {
  className?: string;
};

const IMAGES = [
  "/assets/brand/demos/attachments/attachment-1.png",
  "/assets/brand/demos/attachments/attachment-2.png",
  "/assets/brand/demos/attachments/attachment-3.png",
  "/assets/brand/demos/attachments/attachment-4.png",
  "/assets/brand/demos/attachments/attachment-5.png",
] as const;

export function Gallery03({ className }: Gallery03Props) {
  const track = [...IMAGES, ...IMAGES];

  return (
    <section className={cn("w-full overflow-hidden bg-background", className)}>
      <style>{`
        @keyframes gallery-03-scroll {
          from { transform: translateX(0); }
          to { transform: translateX(-50%); }
        }
      `}</style>
      <div className="mx-auto w-full max-w-4xl px-4 py-10 sm:px-6 sm:py-14">
        <div className="mx-auto max-w-md text-center">
          <h2 className="text-xl font-medium tracking-wide text-foreground sm:text-2xl">
            In motion
          </h2>
          <p className="mt-2 text-sm tracking-wide text-muted-foreground">
            A slow horizontal strip of frames — pause by hovering the track.
          </p>
        </div>
      </div>
      <div
        className="w-full overflow-hidden pb-10 sm:pb-14"
        aria-hidden="true"
      >
        <div
          className="flex w-max gap-3 pr-3 hover:[animation-play-state:paused]"
          style={{ animation: "gallery-03-scroll 36s linear infinite" }}
        >
          {track.map((src, index) => (
            <div
              key={`${src}-${index}`}
              className="aspect-[4/3] w-[16rem] shrink-0 overflow-hidden rounded-xl bg-muted sm:w-[18rem]"
            >
              <img src={src} alt="" className="size-full object-cover" />
            </div>
          ))}
        </div>
      </div>
    </section>
  );
}
```

### Installation

```bash
npx @arctis-sh/@arctis-sh/ui@latest add gallery-03
```

### Usage

```tsx
import { Gallery03 } from "@/components/blocks/gallery/gallery-03"
```

```tsx
<Gallery03 />
```
