Experience System

Image

Compound thumbnail preview — hover card in overlay mode or dialog in full-screen mode.

Nature landscapeLake landscape

Image is a compound component: compose ImageThumbnail, ImageFull, and optional ImageSkeleton under a root with mode="overlay" or mode="full-screen". Overlay mode uses DS HoverCard; full-screen mode uses DS Dialog.

Installation

The component is exported from @by/experience-system. Add the package with your package manager:

pnpm add @by/experience-system

In this monorepo, depend on the workspace package (for example via workspace:* or your catalog) so imports resolve to packages/experience-system.

Composition

Image (mode="overlay" | "full-screen")
├── ImageThumbnail   — thumbnail shown as the trigger
├── ImageFull        — full-size image in hover card or dialog
└── ImageSkeleton    — loading placeholder (required when loading={true})

Usage

import { Image, ImageThumbnail, ImageFull, ImageSkeleton } from '@by/experience-system';

Image is a client component ('use client'). Use it inside a Client Component or a dynamic import when using the Next.js App Router.

Overlay mode

Hovering (or tapping on touch devices) the thumbnail shows the full image in a hover card. Set placement on Image:

<Image mode="overlay" align="center" side="start" sideOffset={16}>
  <ImageThumbnail src="/thumb.jpg" alt="Product thumbnail" className="size-15" />
  <ImageFull
    src="/large.jpg"
    className="h-60 w-80 max-h-[80dvh] max-w-full"
  />
  <ImageSkeleton className="size-15" />
</Image>

Optional openDelay and closeDelay on Image tune hover card timing.

Full-screen mode

Clicking the thumbnail opens the full image in a modal dialog. An aria-label is required on Image:

<Image mode="full-screen" aria-label="Open full-size product image">
  <ImageThumbnail src="/thumb.jpg" alt="Product image" className="size-15" />
  <ImageFull src="/large.jpg" className="max-h-[80dvh] max-w-full" />
  <ImageSkeleton className="size-15" />
</Image>

Size images with className (Tailwind utilities such as size-15, w-10 h-10).

Examples

Overview

Hover the thumbnail to preview the full image in a hover card. Tune align, side, and sideOffset on Image.

Nature landscapeLake landscape

Full-screen

Click the thumbnail to open the full image in a dialog. A maximize icon appears on hover.

Loading

Pass loading={true} on Image while URLs resolve. Include an ImageSkeleton child sized to match the thumbnail.

API Reference

Image

Root container. Props depend on the mode discriminant.

Common props (both modes):

PropTypeDefault
mode'overlay' | 'full-screen'— (required)
loadingbooleanfalse
dataTestIdstring'by-es-image'
classNamestring
childrenReactNode— (required)

mode="overlay" additional props:

PropTypeDefault
openDelaynumber0
closeDelaynumber0
align'start' | 'center' | 'end''start'
side'bottom' | 'top' | 'start' | 'end''bottom'
sideOffsetnumber4
alignOffsetnumber

mode="full-screen" additional prop:

PropTypeDefault
aria-labelstring— (required)

ImageThumbnail

PropTypeDefault
srcstring— (required)
altstring''
classNamestring

Forwards standard <img> attributes.

ImageFull

PropTypeDefault
srcstring— (required)
altstring''
classNamestring

Forwards standard <img> attributes.

ImageSkeleton

PropTypeDefault
classNamestring

Wraps DS Skeleton. Use className for dimensions. Accepts data-testid for testing.

Data attributeValues
data-slotimage (root), image-thumbnail, image-full, image-skeleton, image-overlay-hover-card, image-hover-overlay, image-maximize-icon, image-dialog-content, image-dialog-full

Accessibility

  • Overlay — Radix HoverCard opens on hover and focus; tap toggles on touch devices. Provide meaningful alt text on ImageThumbnail.
  • Full-screen — The trigger has aria-label (required on Image). The dialog includes sr-only DialogTitle and DialogDescription. Keyboard: Enter/Space opens; Esc closes (Radix Dialog).

Keyboard interactions

KeyDescription
Tab / Shift+TabMoves focus to the thumbnail trigger.
Enter / SpaceOpens full-screen dialog when the trigger is focused.
EscCloses the full-screen dialog.

Source in the repo: packages/experience-system/src/components/Image/Image.tsx. Agent-oriented contracts: packages/experience-system/src/components/Image/Image.instructions.md.