@10xmedia/payload-folder-picker
v0.0.3
Published
A folder picker plugin for Payload CMS
Readme

@10xmedia/payload-folder-picker
A Payload CMS plugin that replaces the default upload field UI with a folder-aware file picker. Users browse their folder hierarchy directly inside a drawer, navigate into subfolders, search, and select files — without leaving the document they are editing.
[!NOTE] Early release (v0.0.1) — core functionality is stable but edge cases may not be fully covered. Bug reports and contributions are welcome.
Requirements
- Payload CMS 3.x
- Folders must be enabled in your Payload config (
folders: { ... }at the root level) - At least one collection must have
folders: true
Installation
npm install @10xmedia/payload-folder-picker
# or
pnpm add @10xmedia/payload-folder-pickerDemo
Single upload field — browse folders and select a single file.
https://github.com/user-attachments/assets/d6200827-a1bc-40e6-96b8-3607cfa37306
Multiple upload field (hasMany) — select multiple files across folders.
https://github.com/user-attachments/assets/d6357407-de25-436f-bfab-efcfe237777b
Polymorphic field (single) — pick from multiple folder-enabled collections in one field.
https://github.com/user-attachments/assets/91503262-a24f-45b2-8fc1-c28d57f6b0e0
Polymorphic field (hasMany) — select multiple files from multiple collections.
https://github.com/user-attachments/assets/bc408c45-804d-4ae4-8294-3b469c4ff8a3
Lexical rich text — folder picker replaces the native upload node picker inside the editor.
https://github.com/user-attachments/assets/e7184cb1-21f2-42ce-b632-0bd10b044454
Setup
1. Add the plugin to your Payload config
// payload.config.ts
import { payloadFolderPicker } from '@10xmedia/payload-folder-picker'
export default buildConfig({
folders: {
browseByFolder: true,
},
collections: [
{
slug: 'media',
upload: true,
folders: true, // enables folder support for this collection
fields: [],
},
],
plugins: [payloadFolderPicker({})],
})The plugin automatically patches every upload field in every collection whose relationTo includes at least one folder-enabled collection. No manual field changes are required.
2. (Optional) Enable the folder picker inside Lexical rich text
To replace the native upload picker inside Lexical editor nodes, add FolderUploadOverrideFeature to your editor's feature list. Import it from the /rsc entry point (server-only).
// payload.config.ts
import { lexicalEditor } from '@payloadcms/richtext-lexical'
import { FolderUploadOverrideFeature } from '@10xmedia/payload-folder-picker/rsc'
export default buildConfig({
editor: lexicalEditor({
features({ defaultFeatures }) {
return [...defaultFeatures, FolderUploadOverrideFeature()]
},
}),
// ...
})After adding the feature, run the import map generator so Payload registers the new client component:
pnpm payload generate:importmapHow it works
The plugin follows an opt-out approach: it patches all upload fields by default, and you disable it selectively where you don't want it.
For each upload field, the plugin checks whether any of the field's relationTo slugs belong to a folder-enabled collection. If at least one does, the field's admin component is replaced with the folder picker UI. If none do, the field is left untouched.
Opting out
On a single field
Add custom: { disableFolderPicker: true } directly to any upload field:
{
name: 'thumbnail',
type: 'upload',
relationTo: 'media',
custom: {
disableFolderPicker: true,
},
}On a container field (group, tab, row, etc.)
Setting disableFolderPicker on a parent container opts out all upload fields nested inside it. This works for group, row, collapsible, tabs, blocks, and any other field type that contains child fields:
{
name: 'legacyMedia',
type: 'group',
custom: {
disableFolderPicker: true,
},
fields: [
{
name: 'image',
type: 'upload',
relationTo: 'media',
},
{
name: 'video',
type: 'upload',
relationTo: 'media',
hasMany: true,
},
],
}Both image and video above will keep the native Payload upload UI.
Polymorphic upload fields
Upload fields with multiple relationTo slugs (polymorphic) are supported. However, only folder-enabled collections are shown in the picker. Collections that do not have folders: true are silently excluded from the drawer's browsable collections — they cannot be browsed or selected through the folder picker.
// 'media' and 'files' have folders: true → shown in the folder picker
// 'attachments' does not have folders: true → excluded from the picker
{
name: 'asset',
type: 'upload',
relationTo: ['media', 'files', 'attachments'],
}If none of the relationTo slugs belong to folder-enabled collections, the field is not patched at all and keeps the default Payload UI.
Files without an assigned folder
Files that have not been assigned to any folder will not appear in the picker drawer. This matches Payload's own native folder-browse behavior — the built-in "Browse by Folder" view also hides unassigned files. To make a file selectable via the folder picker, assign it to a folder first through the media library.
Plugin options
payloadFolderPicker({
disabled?: boolean // set to true to disable the plugin entirely (e.g. in certain environments)
})Exports
| Entry point | Contents |
|---|---|
| @10xmedia/payload-folder-picker | payloadFolderPicker plugin function |
| @10xmedia/payload-folder-picker/rsc | FolderUploadOverrideFeature (server-only, for Lexical) |
| @10xmedia/payload-folder-picker/client | FolderPickerField, FolderPickerInput, FolderUploadOverrideFeatureClient |
