Responsive gallery of media thumbnails with keyboard navigation
Tags: component media data-display
MediaGrid lays out a list of media items as thumbnails and opens the Lightbox when one is chosen. It handles mixed media: video and audio tiles gain a play affordance and a duration badge, and items with no thumbnail fall back to a typed icon.
Import
<script>
import { MediaGrid } from '@classic-homes/theme-svelte';
</script>Basic Usage
<script>
const photos = [
{ id: '1', kind: 'image', src: '/one.jpg', alt: 'Front elevation' },
{ id: '2', kind: 'image', src: '/two.jpg', alt: 'Kitchen' },
{ id: '3', kind: 'video', src: '/tour.mp4', poster: '/tour.jpg', title: 'Walkthrough' },
];
</script>
<MediaGrid items={photos} label="Project photos" />Props
| Prop | Type | Default | Description |
|---|---|---|---|
items |
MediaItem[] |
required | Items to display |
label |
string |
'Media gallery' |
Accessible name for the gallery list |
variant |
'grid' | 'masonry' |
'grid' |
Uniform tiles, or natural heights via CSS columns |
columns |
MediaGridColumns |
{ base: 2, md: 3, lg: 4 } |
Column counts per breakpoint |
gap |
'none' | 'sm' | 'md' | 'lg' |
'md' |
Gap between tiles |
ratio |
'square' | 'video' | 'photo' | 'portrait' | 'wide' | number |
'square' |
Aspect ratio of each tile; ignored in masonry |
lightbox |
boolean |
true |
Open the built-in lightbox on selection |
singleTabStop |
boolean |
true |
Keep the gallery to one tab stop and move with the arrow keys |
onSelect |
(index: number, item: MediaItem) => void |
- | Called with the selected index and item |
class |
string |
- | Additional CSS classes |
Responsive Columns
columns takes a count per breakpoint. Omitted breakpoints inherit the one below:
<MediaGrid items={photos} columns={{ base: 2, sm: 3, md: 4, lg: 5, xl: 6 }} />Counts from 1 to 6 are supported at every breakpoint.
Masonry
masonry preserves each image's own height. Note that CSS columns fill top-to-bottom, so the visual order runs down each column rather than across each row — reach for it when the items have no meaningful sequence.
<MediaGrid items={photos} variant="masonry" columns={{ base: 2, md: 3 }} />Custom Selection Handling
Turn the built-in lightbox off to route selection somewhere else:
<MediaGrid items={photos} lightbox={false} onSelect={(index, item) => goto(`/photos/${item.id}`)} />Accessibility
- Renders a labelled list, so screen readers announce the gallery and its item count.
- Each tile is a real button named from the item's title or alt text.
- By default the gallery is a single tab stop; arrow keys move between tiles.
↓and↑move a full row, with the column count read from the live layout rather than thecolumnsprop. HomeandEndjump to the first and last tile.- Set
singleTabStop={false}for small galleries where a tab stop per tile is preferable.
Related Components
- Lightbox - The full-screen viewer MediaGrid opens
- MediaCarousel - One item at a time instead of a grid
- Image - Renders each tile's thumbnail
- AspectRatio - Holds each tile at a fixed ratio