# Media Picker

In-app photo and video grid for picking one item or several. Each pick flies into a tray with a numbered badge, and reaching the limit gives a gentle warning.

> Composed · Pro · Forms & Inputs — React Native, Expo Go compatible.

## Install

```bash
npx @lumioui/cli add pro/media-picker
```

## Import

```tsx
import { MediaPicker } from "@/components/ui/media-picker/media-picker";
```

## Variants

- `chat` — Chat attachment sheet: `npx @lumioui/cli add pro/media-picker-chat`
- `listing` — Listing photos with cover: `npx @lumioui/cli add pro/media-picker-listing`
- `post` — Create post, numbered picks: `npx @lumioui/cli add pro/media-picker-post`
- `profile` — Profile photo with crop circle: `npx @lumioui/cli add pro/media-picker-profile`

## Props

| Prop | Type | Notes |
| --- | --- | --- |
| `items` | `MediaPickerItem[]` | — |
| `selected?` | `string[]` | Controlled selection, in pick order. |
| `defaultSelected?` | `string[]` | Uncontrolled initial selection. |
| `onSelectedChange?` | `(ids: string[]) => void` | — |
| `mode?` | `"multiple" | "single"` | "multiple" numbers picks; "single" swaps one pick with a check. Default "multiple". |
| `max?` | `number` | Most items in a multiple pick. Default 10. |
| `columns?` | `number` | Grid columns. Default 3. |
| `gap?` | `number` | Gap between tiles in points. Default 2. |
| `onCameraPress?` | `() => void` | Show a camera tile first; fires onCameraPress. |
| `tray?` | `boolean` | Selected tray along the bottom. Default true in multiple mode. |
| `cover?` | `boolean` | First pick is the cover; tray thumbs get a promote-to-cover star. |
| `onMaxReached?` | `() => void` | Fires when a pick is refused because `max` is reached. |
| `trayAction?` | `React.ReactNode` | Right side of the tray (Next / Send button). |
| `trayLabel?` | `(count: number, max: number) => string` | Tray label. Default "{n} selected". |
| `trayThumbSize?` | `number` | Tray thumbnail edge in points. Default 56. |
| `gathered?` | `boolean` | Commit: the tray gathers into a fanned stack on the cover pick. |
| `onGathered?` | `(ids: string[]) => void` | Called once the gathered stack has been held (~650ms after it lands). |
| `gatheredLabel?` | `(count: number) => string` | Badge on the gathered stack. Default "{n} photos" / "{n} items". |
| `header?` | `React.ReactNode` | Rendered above the grid, inside the scroll view (album switcher, crop preview). |
| `className?` | `string` | — |
| `contentClassName?` | `string` | Classes for the scroll content (padding). |

## Icons rendered

- `play` — /icons.html?i=play
- `star` — /icons.html?i=star
- `check` — /icons.html?i=check
- `camera` — /icons.html?i=camera
- `x` — /icons.html?i=x

Source: https://lumioui.com/components/media-picker