Skip to content

MediaLibrary component

MediaLibrary is a grid of images and files to pick from, like the media screen of a CMS. It has search and type filters, one or many picks, Load more (also when scrolled into view), and uploading by a button or by dropping files. You supply the items and fetch more when asked; it does not load or store files itself. Put it in a Modal for an Insert image dialog.

Data Display15 propsAccessibility notes

Playground

Change a prop on the right and the preview updates. Switch to Code to copy what you see.

Picking an image

Each item is { id, name, thumbnail?, type?, size?, description? }. type is a MIME type and picks the icon and the type filter. By default the library filters items by the search text and the type itself. onAction runs on Enter or a double click, and onUpload adds an Upload button and accepts dropped files.

<MediaLibrary
  items={media}
  kinds={["image"]}
  onAction={(item) => insertImage(item)}
  onUpload={(files) => uploadAll(files)}
  accept="image/*"
/>

Many picks, filtered on a server

selectionMode multiple allows many picks (Shift+click for a range, Ctrl or Cmd+A for all). For a large library set filtering to none, listen to onSearchChange and onFilterChange, and pass the results as items with hasMore and onLoadMore for paging.

<MediaLibrary
  items={page.items}
  selectionMode="multiple"
  selectedKeys={picked}
  onSelectionChange={setPicked}
  filtering="none"
  onSearchChange={setQuery}
  onFilterChange={setKind}
  hasMore={page.hasMore}
  onLoadMore={fetchNext}
  isLoading={loading}
/>

Props

The full public API for MediaLibrary. Every prop is stable and intentionally typed.

Data

items

MediaItem[]

default: —

{ id, name, thumbnail?, type?, size?, description?, data? }. type is a MIME type; it picks the icon and the filter. size is in bytes.

selectedKeys / defaultSelectedKeys / onSelectionChange

string[] / (keys: string[]) => void

default: []

The picked item ids, controlled or not.

onAction

(item: MediaItem) => void

default: —

Enter or a double click on an item (use this one).

filtering

"local" | "none"

default: local

local: the library filters items by search and type. none: you filter on a server and pass the results.

search / defaultSearch / onSearchChange

string / (query) => void

default: ""

The search text.

filter / defaultFilter / onFilterChange

"all" | MediaKind

default: all

The chosen type filter.

hasMore / onLoadMore / isLoading

boolean / () => void / boolean

default: —

Shows Load more and calls onLoadMore when it is clicked or scrolls into view. isLoading shows placeholders.

onUpload

(files: File[]) => void

default: —

Adds an Upload button and lets files be dropped on the library.

accept

string

default: —

File types for uploads, like an input's accept.

Behavior & states

selectionMode

"single" | "multiple"

default: single

Pick one item or many. Shift+click picks a range.

Appearance

kinds

MediaKind[]

default: every kind

Type filters offered after All: image, video, audio, document. [] hides them.

size

"sm" | "md" | "lg"

default: md

Thumbnail size.

classNames

Partial<Record<slot, string>>

default: —

Class per part: base, toolbar, search, filters, grid, item, thumbnail, name, footer.

Content

emptyContent

ReactNode

default: No media yet

Shown when there are no items at all.

labels

Partial<MediaLibraryLabels>

default: English

library, search, filters, kinds, upload, dropFiles, loadMore, loading, empty, noResults(query), selected(count), clearSelection. Also set app-wide with LocaleProvider.

Accessibility

  • The grid is a listbox of options, multi-selectable in multiple mode, each named by its file name and detail (photo.jpg, 240 KB).
  • One tab stop for the grid. Arrow keys move in two directions (right-to-left pages swap left and right), Home and End go to the ends, Space toggles in multiple mode, Shift with arrows extends the pick, and Enter acts.
  • The type filters are toggle buttons in a named group; the search box is named. Loading is announced and the library is marked busy while it loads.
  • Uploading by dropping files also has the Upload button, so it never depends on dragging.

Best practices

  • Thumbnails must be http(s) or blob: URLs, paths starting with /, ./ or ../, or base64 data URLs of common image types; anything else is not loaded and the type icon is shown.
  • Give each item a unique, stable id.
  • Check uploaded files on your server too; accept only guides the file picker.
  • Translate the text with the labels prop or LocaleProvider.