Media picker

A dialog that picks one or more files for a field: featured image, gallery blocks, company logo, profile photo, document attachment. Library, Upload and From URL tabs; new uploads are selected automatically; a selection tray, a pluralised confirm button, an optional alt-text check, and an imperative useMediaPicker() for code paths.

Radix Dialog + Tabs · Media library media/media-picker.tsx, media/media-library.tsxtheme · material · accent · density · font

Installation

$ pnpm add @vamos-ui/react

The whole kit as one package — get updates by bumping the version. Add the styles to globals.css: @import "@vamos-ui/react/styles.css";

Usage

import { MediaPicker } from "@vamos-ui/react/media";

<MediaPicker accept="image/*" confirmLabel="Set featured image" onSelect={([asset]) => setCover(asset)}>
  <Button>Set featured image</Button>
</MediaPicker>

Focus starts in the search field. The selection count is announced (“2 files selected”). Ctrl/⌘ + Enter confirms.

Files dropped on the Upload tab go to the library and are selected as they finish.

The embedded library is drawn flat inside the dialog, so the dialog stays the only glass layer.

Examples

Multiple with a limit (listing gallery)

multiple + max: tiles beyond the limit are disabled, the button reads “Insert 3 images”.

Imperative (CRM company logo)

const [asset] = await pick({ accept }) — resolves [] when cancelled. Needs MediaPickerProvider once.

Kalamış Yapı A.Ş.

From URL

Shown when the adapter implements sideload; the imported file is added to the library and selected.

Require alt text

Images without alt text get an inline field or Decorative before Insert is enabled; the text is saved to the library.

API

MediaPicker

PropTypeDefault
open / defaultOpen / onOpenChange
Controlled or uncontrolled; or pass a trigger as children.
boolean—
children
Trigger element (DialogTrigger asChild).
ReactNode—
onSelect
On confirm, in selection order.
(assets: MediaAsset[]) => void—
multiple / max
Several files, with an optional limit.
boolean · numberfalse
accept
"image/*": library filter and upload restriction; also switches copy to “image(s)”.
string—
value
Preselected asset ids (loaded with getMany).
string[]—
title / confirmLabel
Dialog title and confirm text. Default “Select image” / “Insert 2 images” (plural rules per locale).
string—
tabs
Tabs and their order.
("library" | "upload" | "url")[]library, upload (+ url with sideload)
requireAlt
Ask for alt text before confirming.
booleanfalse
size
720px · 1080px with the details panel · full screen.
"md" | "lg" | "full""lg"
adapter
Default: MediaProvider.
MediaAdapter—
labels / libraryLabels
Built-in strings (dictionary namespace mediaPicker).
Partial<MediaPickerLabels> · Partial<MediaLibraryLabels>—

MediaPickerProvider

PropTypeDefault
adapter
Optional; default MediaProvider.
MediaAdapter—
children
The app.
ReactNode—

useMediaPicker()

PropTypeDefault
→
Same options as MediaPicker without open/onSelect.
(options?: MediaPickOptions) => Promise<MediaAsset[]>—