Compare commits

..

2 Commits

Author SHA1 Message Date
Jacob Fletcher
e740cef308 fix slug 2025-01-16 11:39:55 -05:00
Jacob Fletcher
75041afe90 test: ensures api errors are hidden from rest responses when not using config.debug 2025-01-16 11:13:17 -05:00
1669 changed files with 30524 additions and 116026 deletions

54
.github/CODEOWNERS vendored
View File

@@ -1,37 +1,29 @@
# Order matters. The last matching pattern takes precedence.
# Approvals are not required currently but may be enabled in the future.
### Package Exports
### Package Exports ###
/**/exports/ @denolfe @jmikrut @DanRibbens
**/exports/ @denolfe @jmikrut @DanRibbens
### Packages ###
/packages/plugin-cloud*/src/ @denolfe
/packages/email-*/src/ @denolfe
/packages/storage-*/src/ @denolfe
/packages/create-payload-app/src/ @denolfe
/packages/eslint-*/ @denolfe @AlessioGr
### Packages
### Templates ###
/templates/_data/ @denolfe
/templates/_template/ @denolfe
/packages/plugin-cloud*/src/ @denolfe @jmikrut @DanRibbens
/packages/email-*/src/ @denolfe @jmikrut @DanRibbens
/packages/live-preview*/src/ @jacobsfletch
/packages/plugin-stripe/src/ @jacobsfletch
/packages/plugin-multi-tenant/src/ @JarrodMFlesch
/packages/richtext-*/src/ @AlessioGr
/packages/next/src/ @jmikrut @jacobsfletch @AlessioGr @JarrodMFlesch
/packages/ui/src/ @jmikrut @jacobsfletch @AlessioGr @JarrodMFlesch
/packages/storage-*/src/ @denolfe @jmikrut @DanRibbens
/packages/create-payload-app/src/ @denolfe @jmikrut @DanRibbens
/packages/eslint-*/ @denolfe @jmikrut @DanRibbens @AlessioGr
### Build Files ###
/tsconfig.json @denolfe
/**/tsconfig*.json @denolfe
/jest.config.js @denolfe
/**/jest.config.js @denolfe
### Templates
/templates/_data/ @denolfe @jmikrut @DanRibbens
/templates/_template/ @denolfe @jmikrut @DanRibbens
### Build Files
**/tsconfig*.json @denolfe @jmikrut @DanRibbens @AlessioGr
**/jest.config.js @denolfe @jmikrut @DanRibbens @AlessioGr
### Root
/package.json @denolfe @jmikrut @DanRibbens
/tools/ @denolfe @jmikrut @DanRibbens
/.husky/ @denolfe @jmikrut @DanRibbens
/.vscode/ @denolfe @jmikrut @DanRibbens @AlessioGr
/.github/ @denolfe @jmikrut @DanRibbens
### Root ###
/package.json @denolfe
/scripts/ @denolfe
/.husky/ @denolfe
/.vscode/ @denolfe @AlessioGr
/.github/ @denolfe

View File

@@ -28,6 +28,7 @@
"eslint": "^7.32.0",
"jest": "^29.7.0",
"prettier": "^3.3.3",
"ts-jest": "^26.5.6",
"typescript": "^4.9.5"
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -18,7 +18,7 @@
},
"devDependencies": {
"@octokit/webhooks-types": "^7.5.1",
"@swc/jest": "^0.2.37",
"@swc/jest": "^0.2.36",
"@types/jest": "^27.5.2",
"@types/node": "^20.16.5",
"@typescript-eslint/eslint-plugin": "^4.33.0",
@@ -28,6 +28,7 @@
"eslint": "^7.32.0",
"jest": "^29.7.0",
"prettier": "^3.3.3",
"ts-jest": "^26.5.6",
"typescript": "^4.9.5"
}
}

3648
.github/actions/triage/pnpm-lock.yaml generated vendored

File diff suppressed because it is too large Load Diff

114
.github/pnpm-lock.yaml generated vendored
View File

@@ -19,8 +19,8 @@ importers:
specifier: ^7.5.1
version: 7.5.1
'@swc/jest':
specifier: ^0.2.37
version: 0.2.37(@swc/core@1.7.26)
specifier: ^0.2.36
version: 0.2.36(@swc/core@1.7.26)
'@types/jest':
specifier: ^27.5.2
version: 27.5.2
@@ -48,6 +48,9 @@ importers:
prettier:
specifier: ^3.3.3
version: 3.3.3
ts-jest:
specifier: ^26.5.6
version: 26.5.6(jest@29.7.0(@types/node@20.16.5))(typescript@4.9.5)
typescript:
specifier: ^4.9.5
version: 4.9.5
@@ -65,8 +68,8 @@ importers:
specifier: ^7.5.1
version: 7.5.1
'@swc/jest':
specifier: ^0.2.37
version: 0.2.37(@swc/core@1.7.26)
specifier: ^0.2.36
version: 0.2.36(@swc/core@1.7.26)
'@types/jest':
specifier: ^27.5.2
version: 27.5.2
@@ -94,6 +97,9 @@ importers:
prettier:
specifier: ^3.3.3
version: 3.3.3
ts-jest:
specifier: ^26.5.6
version: 26.5.6(jest@29.7.0(@types/node@20.16.5))(typescript@4.9.5)
typescript:
specifier: ^4.9.5
version: 4.9.5
@@ -380,6 +386,10 @@ packages:
resolution: {integrity: sha512-ok/BTPFzFKVMwO5eOHRrvnBVHdRy9IrsrW1GpMaQ9MCnilNLXQKmAX8s1YXDFaai9xJpac2ySzV0YeRRECr2Vw==}
engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
'@jest/types@26.6.2':
resolution: {integrity: sha512-fC6QCp7Sc5sX6g8Tvbmj4XUTbyrik0akgRy03yjXbQaBWWNWGE7SGtJk98m0N8nzegD/7SggrUlivxo5ax4KWQ==}
engines: {node: '>= 10.14.2'}
'@jest/types@29.6.3':
resolution: {integrity: sha512-u3UPsIilWKOM3F9CXtrG8LEJmNxwoCQC/XVj4IKYXvvpx7QIi/Kg1LI5uDmDpKlac62NUtX7eLjRh+jVZcLOzw==}
engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
@@ -532,8 +542,8 @@ packages:
'@swc/counter@0.1.3':
resolution: {integrity: sha512-e2BR4lsJkkRlKZ/qCHPw9ZaSxc0MVUd7gtbtaB7aMvHeJVYe8sOB8DBZkP2DtISHGSku9sCK6T6cnY0CtXrOCQ==}
'@swc/jest@0.2.37':
resolution: {integrity: sha512-CR2BHhmXKGxTiFr21DYPRHQunLkX3mNIFGFkxBGji6r9uyIR5zftTOVYj1e0sFNMV2H7mf/+vpaglqaryBtqfQ==}
'@swc/jest@0.2.36':
resolution: {integrity: sha512-8X80dp81ugxs4a11z1ka43FPhP+/e+mJNXJSxiNYk8gIX/jPBtY4gQTrKu/KIoco8bzKuPI5lUxjfLiGsfvnlw==}
engines: {npm: '>= 7.0.0'}
peerDependencies:
'@swc/core': '*'
@@ -580,6 +590,9 @@ packages:
'@types/yargs-parser@21.0.3':
resolution: {integrity: sha512-I4q9QU9MQv4oEOz4tAHJtNz1cwuLxn2F3xcc2iV5WdqLPpUnj30aUuxt1mAxYTG+oe8CZMV/+6rU4S4gRDzqtQ==}
'@types/yargs@15.0.19':
resolution: {integrity: sha512-2XUaGVmyQjgyAZldf0D0c14vvo/yv0MhQBSTJcejMMaitsn3nxCB6TmH4G0ZQf+uxROOa9mpanoSm8h6SG/1ZA==}
'@types/yargs@17.0.33':
resolution: {integrity: sha512-WpxBCKWPLr4xSsHgz511rFJAM+wS28w2zEO1QDNY5zM/S8ok70NNfztH0xwhqKyaK0OHCbN98LDAZuy1ctxDkA==}
@@ -733,6 +746,10 @@ packages:
engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7}
hasBin: true
bs-logger@0.2.6:
resolution: {integrity: sha512-pd8DCoxmbgc7hyPKOvxtqNcjYoOsABPQdcCUjGp3d42VR2CX1ORhk2A87oqqu5R1kk+76nsxZupkmyd+MVtCog==}
engines: {node: '>= 6'}
bser@2.1.1:
resolution: {integrity: sha512-gQxTNE/GAfIIrmHLUE3oJyp5FO6HRBfhjnw4/wMmA63ZGDJnWBmgY/lyQBpnDUkGmAhbSe39tx2d/iTOAfglwQ==}
@@ -766,6 +783,9 @@ packages:
resolution: {integrity: sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw==}
engines: {node: '>=10'}
ci-info@2.0.0:
resolution: {integrity: sha512-5tK7EtrZ0N+OLFMthtqOj4fI2Jeb88C4CAZPu25LDVUgXJ0A3Js4PMGqrn0JU1W0Mh1/Z8wZzYPxqUrXeBboCQ==}
ci-info@3.9.0:
resolution: {integrity: sha512-NIxF55hv4nSqQswkAeiOi1r83xy8JldOFDTWiug55KBu9Jnblncd2U6ViHmYgHf01TPZS77NJBhBMKdWj9HQMQ==}
engines: {node: '>=8'}
@@ -1113,6 +1133,10 @@ packages:
is-arrayish@0.2.1:
resolution: {integrity: sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==}
is-ci@2.0.0:
resolution: {integrity: sha512-YfJT7rkpQB0updsdHLGWrvhBJfcfzNNawYDNIyQXJz0IViGf75O8EBPKSdvw2rF+LGCsX4FZ8tcr3b19LcZq4w==}
hasBin: true
is-core-module@2.15.1:
resolution: {integrity: sha512-z0vtXSwucUJtANQWldhbtbt7BnL0vxiFjIdDLAatwhDYty2bad6s+rijD6Ri4YuYJubLzIJLUidCh09e1djEVQ==}
engines: {node: '>= 0.4'}
@@ -1287,6 +1311,10 @@ packages:
resolution: {integrity: sha512-Rm0BMWtxBcioHr1/OX5YCP8Uov4riHvKPknOGs804Zg9JGZgmIBkbtlxJC/7Z4msKYVbIJtfU+tKb8xlYNfdkw==}
engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
jest-util@26.6.2:
resolution: {integrity: sha512-MDW0fKfsn0OI7MS7Euz6h8HNDXVQ0gaM9uW6RjfDmd1DAFcaxX9OqIakHIqhbnmF08Cf2DLDG+ulq8YQQ0Lp0Q==}
engines: {node: '>= 10.14.2'}
jest-util@29.7.0:
resolution: {integrity: sha512-z6EbKajIpqGKU56y5KBUgy1dt1ihhQJgWzUlZHArA/+X2ad7Cb5iF+AK1EWVL/Bo7Rz9uurpqw6SiBCefUbCGA==}
engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
@@ -1386,6 +1414,9 @@ packages:
resolution: {integrity: sha512-hXdUTZYIVOt1Ex//jAQi+wTZZpUpwBj/0QsOzqegb3rGMMeJiSEu5xLHnYfBrRV4RH2+OCSOO95Is/7x1WJ4bw==}
engines: {node: '>=10'}
make-error@1.3.6:
resolution: {integrity: sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==}
makeerror@1.0.12:
resolution: {integrity: sha512-JmqCvUhmt43madlpFzG4BQzG2Z3m6tvQDNKdClZnO3VbIudJYmxsT0FNJMeiB2+JTSlTQTSbU8QdesVmwJcmLg==}
@@ -1407,6 +1438,11 @@ packages:
minimatch@3.1.2:
resolution: {integrity: sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==}
mkdirp@1.0.4:
resolution: {integrity: sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==}
engines: {node: '>=10'}
hasBin: true
ms@2.1.3:
resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==}
@@ -1716,6 +1752,14 @@ packages:
resolution: {integrity: sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A==}
hasBin: true
ts-jest@26.5.6:
resolution: {integrity: sha512-rua+rCP8DxpA8b4DQD/6X2HQS8Zy/xzViVYfEs2OQu68tkCuKLV0Md8pmX55+W24uRIyAsf/BajRfxOs+R2MKA==}
engines: {node: '>= 10'}
hasBin: true
peerDependencies:
jest: '>=26 <27'
typescript: '>=3.8 <5.0'
tslib@1.14.1:
resolution: {integrity: sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==}
@@ -1819,6 +1863,10 @@ packages:
yallist@3.1.1:
resolution: {integrity: sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==}
yargs-parser@20.2.9:
resolution: {integrity: sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==}
engines: {node: '>=10'}
yargs-parser@21.1.1:
resolution: {integrity: sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==}
engines: {node: '>=12'}
@@ -2259,6 +2307,14 @@ snapshots:
transitivePeerDependencies:
- supports-color
'@jest/types@26.6.2':
dependencies:
'@types/istanbul-lib-coverage': 2.0.6
'@types/istanbul-reports': 3.0.4
'@types/node': 20.16.5
'@types/yargs': 15.0.19
chalk: 4.1.2
'@jest/types@29.6.3':
dependencies:
'@jest/schemas': 29.6.3
@@ -2421,7 +2477,7 @@ snapshots:
'@swc/counter@0.1.3': {}
'@swc/jest@0.2.37(@swc/core@1.7.26)':
'@swc/jest@0.2.36(@swc/core@1.7.26)':
dependencies:
'@jest/create-cache-key-function': 29.7.0
'@swc/core': 1.7.26
@@ -2482,6 +2538,10 @@ snapshots:
'@types/yargs-parser@21.0.3': {}
'@types/yargs@15.0.19':
dependencies:
'@types/yargs-parser': 21.0.3
'@types/yargs@17.0.33':
dependencies:
'@types/yargs-parser': 21.0.3
@@ -2682,6 +2742,10 @@ snapshots:
node-releases: 2.0.18
update-browserslist-db: 1.1.0(browserslist@4.23.3)
bs-logger@0.2.6:
dependencies:
fast-json-stable-stringify: 2.1.0
bser@2.1.1:
dependencies:
node-int64: 0.4.0
@@ -2709,6 +2773,8 @@ snapshots:
char-regex@1.0.2: {}
ci-info@2.0.0: {}
ci-info@3.9.0: {}
cjs-module-lexer@1.4.1: {}
@@ -3061,6 +3127,10 @@ snapshots:
is-arrayish@0.2.1: {}
is-ci@2.0.0:
dependencies:
ci-info: 2.0.0
is-core-module@2.15.1:
dependencies:
hasown: 2.0.2
@@ -3400,6 +3470,15 @@ snapshots:
transitivePeerDependencies:
- supports-color
jest-util@26.6.2:
dependencies:
'@jest/types': 26.6.2
'@types/node': 20.16.5
chalk: 4.1.2
graceful-fs: 4.2.11
is-ci: 2.0.0
micromatch: 4.0.8
jest-util@29.7.0:
dependencies:
'@jest/types': 29.6.3
@@ -3504,6 +3583,8 @@ snapshots:
dependencies:
semver: 7.6.3
make-error@1.3.6: {}
makeerror@1.0.12:
dependencies:
tmpl: 1.0.5
@@ -3523,6 +3604,8 @@ snapshots:
dependencies:
brace-expansion: 1.1.11
mkdirp@1.0.4: {}
ms@2.1.3: {}
natural-compare@1.4.0: {}
@@ -3776,6 +3859,21 @@ snapshots:
tree-kill@1.2.2: {}
ts-jest@26.5.6(jest@29.7.0(@types/node@20.16.5))(typescript@4.9.5):
dependencies:
bs-logger: 0.2.6
buffer-from: 1.1.2
fast-json-stable-stringify: 2.1.0
jest: 29.7.0(@types/node@20.16.5)
jest-util: 26.6.2
json5: 2.2.3
lodash: 4.17.21
make-error: 1.3.6
mkdirp: 1.0.4
semver: 7.6.3
typescript: 4.9.5
yargs-parser: 20.2.9
tslib@1.14.1: {}
tslib@2.7.0: {}
@@ -3861,6 +3959,8 @@ snapshots:
yallist@3.1.1: {}
yargs-parser@20.2.9: {}
yargs-parser@21.1.1: {}
yargs@17.7.2:

View File

@@ -17,7 +17,7 @@ jobs:
uses: dessant/lock-threads@v5
with:
process-only: 'issues'
issue-inactive-days: '7'
issue-inactive-days: '1'
exclude-any-issue-labels: 'status: awaiting-reply'
log-output: true
issue-comment: >

View File

@@ -254,11 +254,17 @@ jobs:
if: matrix.database == 'supabase'
- name: Integration Tests
run: pnpm test:int
uses: nick-fields/retry@v3
env:
NODE_OPTIONS: --max-old-space-size=8096
PAYLOAD_DATABASE: ${{ matrix.database }}
POSTGRES_URL: ${{ env.POSTGRES_URL }}
with:
retry_on: any
max_attempts: 5
timeout_minutes: 15
command: pnpm test:int
on_retry_command: pnpm clean:build && pnpm install --no-frozen-lockfile
tests-e2e:
runs-on: ubuntu-24.04
@@ -283,7 +289,6 @@ jobs:
- fields-relationship
- fields__collections__Array
- fields__collections__Blocks
- fields__collections__Blocks#config.blockreferences.ts
- fields__collections__Checkbox
- fields__collections__Collapsible
- fields__collections__ConditionalLogic
@@ -294,7 +299,6 @@ jobs:
- fields__collections__JSON
- fields__collections__Lexical__e2e__main
- fields__collections__Lexical__e2e__blocks
- fields__collections__Lexical__e2e__blocks#config.blockreferences.ts
- fields__collections__Number
- fields__collections__Point
- fields__collections__Radio
@@ -363,12 +367,6 @@ jobs:
if: steps.cache-playwright-browsers.outputs.cache-hit == 'true'
run: pnpm exec playwright install-deps chromium
- name: E2E Tests
run: PLAYWRIGHT_JSON_OUTPUT_NAME=results_${{ matrix.suite }}.json pnpm test:e2e:prod:ci ${{ matrix.suite }}
env:
PLAYWRIGHT_JSON_OUTPUT_NAME: results_${{ matrix.suite }}.json
NEXT_TELEMETRY_DISABLED: 1
- uses: actions/upload-artifact@v4
if: always()
with:
@@ -465,9 +463,7 @@ jobs:
- name: Build Template
run: |
pnpm run script:pack --dest templates/${{ matrix.template }}
pnpm run script:build-template-with-local-pkgs ${{ matrix.template }} $POSTGRES_URL
env:
NODE_OPTIONS: --max-old-space-size=8096
pnpm runts scripts/build-template-with-local-pkgs.ts ${{ matrix.template }} $POSTGRES_URL
tests-type-generation:
runs-on: ubuntu-24.04

View File

@@ -53,7 +53,6 @@ jobs:
plugin-cloud
plugin-cloud-storage
plugin-form-builder
plugin-multi-tenant
plugin-nested-docs
plugin-redirects
plugin-search

View File

@@ -28,7 +28,8 @@ jobs:
env:
NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
- name: Canary release script
run: pnpm release:canary
# dry run hard-coded to true for testing and no npm token provided
run: pnpm tsx ./scripts/publish-canary.ts
env:
NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
NPM_CONFIG_PROVENANCE: true

1
.npmrc
View File

@@ -1,4 +1,3 @@
symlink=true
node-linker=isolated
hoist-workspace-packages=false # the default in pnpm v9 is true, but that can break our runtime dependency checks
save-prefix=''

42
.vscode/settings.json vendored
View File

@@ -1,9 +1,34 @@
{
"npm.packageManager": "pnpm",
"editor.defaultFormatter": "esbenp.prettier-vscode",
"editor.formatOnSave": true,
"editor.codeActionsOnSave": {
"source.fixAll.eslint": "explicit"
"[typescript]": {
"editor.defaultFormatter": "esbenp.prettier-vscode",
"editor.formatOnSave": true,
"editor.codeActionsOnSave": {
"source.fixAll.eslint": "explicit"
}
},
"[typescriptreact]": {
"editor.defaultFormatter": "esbenp.prettier-vscode",
"editor.formatOnSave": true,
"editor.codeActionsOnSave": {
"source.fixAll.eslint": "explicit"
}
},
"[javascript]": {
"editor.defaultFormatter": "esbenp.prettier-vscode",
"editor.formatOnSave": true,
"editor.codeActionsOnSave": {
"source.fixAll.eslint": "explicit"
}
},
"[json]": {
"editor.defaultFormatter": "esbenp.prettier-vscode",
"editor.formatOnSave": true
},
"[jsonc]": {
"editor.defaultFormatter": "esbenp.prettier-vscode",
"editor.formatOnSave": true
},
"editor.formatOnSaveMode": "file",
"eslint.rules.customizations": [
@@ -18,11 +43,14 @@
"typescript.tsdk": "node_modules/typescript/lib",
// Load .git-blame-ignore-revs file
"gitlens.advanced.blame.customArguments": ["--ignore-revs-file", ".git-blame-ignore-revs"],
"[javascript][typescript][typescriptreact]": {
"editor.codeActionsOnSave": {
"source.fixAll.eslint": "explicit"
}
},
"files.insertFinalNewline": true,
"jestrunner.jestCommand": "pnpm exec cross-env NODE_OPTIONS=\"--no-deprecation\" node 'node_modules/jest/bin/jest.js'",
"jestrunner.changeDirectoryToWorkspaceRoot": false,
"jestrunner.debugOptions": {
"runtimeArgs": ["--no-deprecation"]
},
// Essentially disables bun test buttons
"bun.test.filePattern": "bun.test.ts"
}
}

View File

@@ -63,7 +63,7 @@ Each test directory is split up in this way specifically to reduce friction when
The following command will start Payload with your config: `pnpm dev my-test-dir`. Example: `pnpm dev fields` for the test/`fields` test suite. This command will start up Payload using your config and refresh a test database on every restart. If you're using VS Code, the most common run configs are automatically added to your editor - you should be able to find them in your VS Code launch tab.
By default, payload will [automatically log you in](https://payloadcms.com/docs/authentication/overview#auto-login) with the default credentials. To disable that, you can either pass in the --no-auto-login flag (example: `pnpm dev my-test-dir --no-auto-login`) or set the `PAYLOAD_PUBLIC_DISABLE_AUTO_LOGIN` environment variable to `false`.
By default, payload will [automatically log you in](https://payloadcms.com/docs/authentication/overview#admin-autologin) with the default credentials. To disable that, you can either pass in the --no-auto-login flag (example: `pnpm dev my-test-dir --no-auto-login`) or set the `PAYLOAD_PUBLIC_DISABLE_AUTO_LOGIN` environment variable to `false`.
The default credentials are `dev@payloadcms.com` as E-Mail and `test` as password. These are used in the auto-login.

View File

@@ -1,8 +1,8 @@
import configPromise from '@payload-config'
import { getPayload } from 'payload'
import { getPayloadHMR } from '@payloadcms/next/utilities'
export const Page = async ({ params, searchParams }) => {
const payload = await getPayload({
const payload = await getPayloadHMR({
config: configPromise,
})
return <div>test ${payload?.config?.collections?.length}</div>

View File

@@ -261,7 +261,7 @@ The following arguments are provided to the `delete` function:
If the Collection is used to access the [Admin Panel](../admin/overview#the-admin-user-collection), the `Admin` Access Control function determines whether or not the currently logged in user can access the admin UI.
To add Admin Access Control to a Collection, use the `admin` property in the [Collection Config](../configuration/collections):
To add Admin Access Control to a Collection, use the `admin` property in the [Collection Config](../collections/overview):
```ts
import type { CollectionConfig } from 'payload'

182
docs/admin/collections.mdx Normal file
View File

@@ -0,0 +1,182 @@
---
title: Collection Admin Config
label: Collections
order: 20
desc:
keywords: admin, components, custom, documentation, Content Management System, cms, headless, javascript, node, react, nextjs
---
The behavior of [Collections](../configuration/collections) within the [Admin Panel](./overview) can be fully customized to fit the needs of your application. This includes grouping or hiding their navigation links, adding [Custom Components](./components), selecting which fields to display in the List View, and more.
To configure Admin Options for Collections, use the `admin` property in your Collection Config:
```ts
import type { CollectionConfig } from 'payload'
export const MyCollection: CollectionConfig = {
// ...
admin: { // highlight-line
// ...
},
}
```
## Admin Options
The following options are available:
| Option | Description |
| -------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **`group`** | Text or localization object used to group Collection and Global links in the admin navigation. Set to `false` to hide the link from the navigation while keeping its routes accessible. |
| **`hidden`** | Set to true or a function, called with the current user, returning true to exclude this Collection from navigation and admin routing. |
| **`hooks`** | Admin-specific hooks for this Collection. [More details](../hooks/collections). |
| **`useAsTitle`** | Specify a top-level field to use for a document title throughout the Admin Panel. If no field is defined, the ID of the document is used as the title. A field with `virtual: true` cannot be used as the title. |
| **`description`** | Text to display below the Collection label in the List View to give editors more information. Alternatively, you can use the `admin.components.Description` to render a React component. [More details](#custom-components). |
| **`defaultColumns`** | Array of field names that correspond to which columns to show by default in this Collection's List View. |
| **`hideAPIURL`** | Hides the "API URL" meta field while editing documents within this Collection. |
| **`enableRichTextLink`** | The [Rich Text](../fields/rich-text) field features a `Link` element which allows for users to automatically reference related documents within their rich text. Set to `true` by default. |
| **`enableRichTextRelationship`** | The [Rich Text](../fields/rich-text) field features a `Relationship` element which allows for users to automatically reference related documents within their rich text. Set to `true` by default. |
| **`meta`** | Page metadata overrides to apply to this Collection within the Admin Panel. [More details](./metadata). |
| **`preview`** | Function to generate preview URLs within the Admin Panel that can point to your app. [More details](#preview). |
| **`livePreview`** | Enable real-time editing for instant visual feedback of your front-end application. [More details](../live-preview/overview). |
| **`components`** | Swap in your own React components to be used within this Collection. [More details](#custom-components). |
| **`listSearchableFields`** | Specify which fields should be searched in the List search view. [More details](#list-searchable-fields). |
| **`pagination`** | Set pagination-specific options for this Collection. [More details](#pagination). |
| **`baseListFilter`** | You can define a default base filter for this collection's List view, which will be merged into any filters that the user performs. |
### Custom Components
Collections can set their own [Custom Components](./components) which only apply to [Collection](../configuration/collections)-specific UI within the [Admin Panel](./overview). This includes elements such as the Save Button, or entire layouts such as the Edit View.
To override Collection Components, use the `admin.components` property in your [Collection Config](../configuration/collections):
```ts
import type { SanitizedCollectionConfig } from 'payload'
export const MyCollection: SanitizedCollectionConfig = {
// ...
admin: {
components: { // highlight-line
// ...
},
},
}
```
The following options are available:
| Path | Description |
| -------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------ |
| **`beforeList`** | An array of components to inject _before_ the built-in List View |
| **`beforeListTable`** | An array of components to inject _before_ the built-in List View's table |
| **`afterList`** | An array of components to inject _after_ the built-in List View |
| **`afterListTable`** | An array of components to inject _after_ the built-in List View's table |
| **`Description`** | A component to render below the Collection label in the List View. An alternative to the `admin.description` property. |
| **`edit.SaveButton`** | Replace the default Save Button with a Custom Component. [Drafts](../versions/drafts) must be disabled. |
| **`edit.SaveDraftButton`** | Replace the default Save Draft Button with a Custom Component. [Drafts](../versions/drafts) must be enabled and autosave must be disabled. |
| **`edit.PublishButton`** | Replace the default Publish Button with a Custom Component. [Drafts](../versions/drafts) must be enabled. |
| **`edit.PreviewButton`** | Replace the default Preview Button with a Custom Component. [Preview](#preview) must be enabled. |
| **`views`** | Override or create new views within the Admin Panel. [More details](./views). |
<Banner type="success">
**Note:**
For details on how to build Custom Components, see [Building Custom Components](./components#building-custom-components).
</Banner>
### Preview
It is possible to display a Preview Button within the Edit View of the Admin Panel. This will allow editors to visit the frontend of your app the corresponds to the document they are actively editing. This way they can preview the latest, potentially unpublished changes.
To configure the Preview Button, set the `admin.preview` property to a function in your [Collection Config](../configuration/collections):
```ts
import type { CollectionConfig } from 'payload'
export const Posts: CollectionConfig = {
// ...
admin: {
// highlight-start
preview: (doc, { locale }) => {
if (doc?.slug) {
return `/${doc.slug}?locale=${locale}`
}
return null
},
// highlight-end
},
}
```
The `preview` property resolves to a string that points to your front-end application with additional URL parameters. This can be an absolute URL or a relative path.
The preview function receives two arguments:
| Argument | Description |
| --- | --- |
| **`doc`** | The Document being edited. |
| **`ctx`** | An object containing `locale`, `token`, and `req` properties. The `token` is the currently logged-in user's JWT. |
If your application requires a fully qualified URL, such as within deploying to Vercel Preview Deployments, you can use the `req` property to build this URL:
```ts
preview: (doc, { req }) => `${req.protocol}//${req.host}/${doc.slug}` // highlight-line
```
<Banner type="success">
**Note:**
For fully working example of this, check of the official [Draft Preview Example](https://github.com/payloadcms/payload/tree/main/examples/draft-preview) in the [Examples Directory](https://github.com/payloadcms/payload/tree/main/examples).
</Banner>
### Pagination
All Collections receive their own List View which displays a paginated list of documents that can be sorted and filtered. The pagination behavior of the List View can be customized on a per-Collection basis, and uses the same [Pagination](../queries/pagination) API that Payload provides.
To configure pagination options, use the `admin.pagination` property in your [Collection Config](../configuration/collections):
```ts
import type { CollectionConfig } from 'payload'
export const Posts: CollectionConfig = {
// ...
admin: {
// highlight-start
pagination: {
defaultLimit: 10,
limits: [10, 20, 50],
},
// highlight-end
},
}
```
The following options are available:
| Option | Description |
| -------------- | --------------------------------------------------------------------------------------------------- |
| `defaultLimit` | Integer that specifies the default per-page limit that should be used. Defaults to 10. |
| `limits` | Provide an array of integers to use as per-page options for admins to choose from in the List View. |
### List Searchable Fields
In the List View, there is a "search" box that allows you to quickly find a document through a simple text search. By default, it searches on the ID field. If defined, the `admin.useAsTitle` field is used. Or, you can explicitly define which fields to search based on the needs of your application.
To define which fields should be searched, use the `admin.listSearchableFields` property in your [Collection Config](../configuration/collections):
```ts
import type { CollectionConfig } from 'payload'
export const Posts: CollectionConfig = {
// ...
admin: {
// highlight-start
listSearchableFields: ['title', 'slug'],
// highlight-end
},
}
```
<Banner type="warning">
**Tip:**
If you are adding `listSearchableFields`, make sure you index each of these fields so your admin queries can remain performant.
</Banner>

550
docs/admin/components.mdx Normal file
View File

@@ -0,0 +1,550 @@
---
title: Swap in your own React components
label: Custom Components
order: 40
desc: Fully customize your Admin Panel by swapping in your own React components. Add fields, remove views, update routes and change functions to sculpt your perfect Dashboard.
keywords: admin, components, custom, documentation, Content Management System, cms, headless, javascript, node, react, nextjs
---
The Payload [Admin Panel](./overview) is designed to be as minimal and straightforward as possible to allow for easy customization and full control over the UI. In order for Payload to support this level of customization, Payload provides a pattern for you to supply your own React components through your [Payload Config](../configuration/overview).
All Custom Components in Payload are [React Server Components](https://react.dev/reference/rsc/server-components) by default. This enables the use of the [Local API](../local-api/overview) directly on the front-end. Custom Components are available for nearly every part of the Admin Panel for extreme granularity and control.
<Banner type="success">
**Note:**
Client Components continue to be fully supported. To use Client Components in your app, simply include the `use client` directive. Payload will automatically detect and remove all default, [non-serializable props](https://react.dev/reference/rsc/use-client#serializable-types) before rendering your component. [More details](#client-components).
</Banner>
There are four main types of Custom Components in Payload:
- [Root Components](#root-components)
- [Collection Components](./collections#custom-components)
- [Global Components](./globals#custom-components)
- [Field Components](./fields#custom-components)
To swap in your own Custom Component, first consult the list of available components, determine the scope that corresponds to what you are trying to accomplish, then [author your React component(s)](#building-custom-components) accordingly.
## Defining Custom Components
As Payload compiles the Admin Panel, it checks your config for Custom Components. When detected, Payload either replaces its own default component with yours, or if none exists by default, renders yours outright. While are many places where Custom Components are supported in Payload, each is defined in the same way using [Component Paths](#component-paths).
To add a Custom Component, point to its file path in your Payload Config:
```ts
import { buildConfig } from 'payload'
const config = buildConfig({
// ...
admin: {
components: {
logout: {
Button: '/src/components/Logout#MyComponent' // highlight-line
}
}
},
})
```
<Banner type="success">
**Note:**
All Custom Components can be either Server Components or Client Components, depending on the presence of the `use client` directive at the top of the file.
</Banner>
### Component Paths
In order to ensure the Payload Config is fully Node.js compatible and as lightweight as possible, components are not directly imported into your config. Instead, they are identified by their file path for the Admin Panel to resolve on its own.
Component Paths, by default, are relative to your project's base directory. This is either your current working directory, or the directory specified in `config.admin.baseDir`. To simplify Component Paths, you can also configure the base directory using the `admin.importMap.baseDir` property.
Components using named exports are identified either by appending `#` followed by the export name, or using the `exportName` property. If the component is the default export, this can be omitted.
```ts
import { buildConfig } from 'payload'
import { fileURLToPath } from 'node:url'
import path from 'path'
const filename = fileURLToPath(import.meta.url)
const dirname = path.dirname(filename)
const config = buildConfig({
// ...
admin: {
importMap: {
baseDir: path.resolve(dirname, 'src'), // highlight-line
},
components: {
logout: {
Button: '/components/Logout#MyComponent' // highlight-line
}
}
},
})
```
In this example, we set the base directory to the `src` directory, and omit the `/src/` part of our component path string.
### Config Options
While Custom Components are usually defined as a string, you can also pass in an object with additional options:
```ts
import { buildConfig } from 'payload'
const config = buildConfig({
// ...
admin: {
components: {
logout: {
// highlight-start
Button: {
path: '/src/components/Logout',
exportName: 'MyComponent',
}
// highlight-end
}
}
},
})
```
The following options are available:
| Property | Description |
|---------------|-------------------------------------------------------------------------------------------------------------------------------|
| **`clientProps`** | Props to be passed to the Custom Components if it's a Client Component. [More details](#custom-props). |
| **`exportName`** | Instead of declaring named exports using `#` in the component path, you can also omit them from `path` and pass them in here. |
| **`path`** | File path to the Custom Component. Named exports can be appended to the end of the path, separated by a `#`. |
| **`serverProps`** | Props to be passed to the Custom Component if it's a Server Component. [More details](#custom-props). |
For more details on how to build Custom Components, see [Building Custom Components](#building-custom-components).
### Import Map
In order for Payload to make use of [Component Paths](#component-paths), an "Import Map" is automatically generated at `app/(payload)/admin/importMap.js`. This file contains every Custom Component in your config, keyed to their respective paths. When Payload needs to lookup a component, it uses this file to find the correct import.
The Import Map is automatically regenerated at startup and whenever Hot Module Replacement (HMR) runs, or you can run `payload generate:importmap` to manually regenerate it.
#### Custom Imports
If needed, custom items can be appended onto the Import Map. This is mostly only relevant for plugin authors who need to add a custom import that is not referenced in a known location.
To add a custom import to the Import Map, use the `admin.dependencies` property in your [Payload Config](../configuration/overview):
```ts
import { buildConfig } from 'payload'
export default buildConfig({
// ...
admin: {
// ...
dependencies: {
myTestComponent: { // myTestComponent is the key - can be anything
path: '/components/TestComponent.js#TestComponent',
type: 'component',
clientProps: {
test: 'hello',
},
},
},
}
}
```
## Building Custom Components
All Custom Components in Payload are [React Server Components](https://react.dev/reference/rsc/server-components) by default. This enables the use of the [Local API](../local-api/overview) directly on the front-end, among other things.
### Default Props
To make building Custom Components as easy as possible, Payload automatically provides common props, such as the [`payload`](../local-api/overview) class and the [`i18n`](../configuration/i18n) object. This means that when building Custom Components within the Admin Panel, you do not have to get these yourself.
Here is an example:
```tsx
import React from 'react'
const MyServerComponent = async ({
payload // highlight-line
}) => {
const page = await payload.findByID({
collection: 'pages',
id: '123',
})
return (
<p>{page.title}</p>
)
}
```
Each Custom Component receives the following props by default:
| Prop | Description |
| ------------------------- | ----------------------------------------------------------------------------------------------------- |
| `payload` | The [Payload](../local-api/overview) class. |
| `i18n` | The [i18n](../configuration/i18n) object. |
<Banner type="warning">
**Reminder:**
All Custom Components also receive various other props that are specific component being rendered. See [Root Components](#root-components), [Collection Components](./collections#custom-components), [Global Components](./globals#custom-components), or [Field Components](./fields#custom-components) for a complete list of all default props per component.
</Banner>
### Custom Props
To pass in custom props from the config, you can use either the `clientProps` or `serverProps` properties depending on whether your prop is [serializable](https://react.dev/reference/rsc/use-client#serializable-types), and whether your component is a Server or Client Component.
```ts
import { buildConfig } from 'payload'
const config = buildConfig({
// ...
admin: { // highlight-line
components: {
logout: {
Button: {
path: '/src/components/Logout#MyComponent',
clientProps: {
myCustomProp: 'Hello, World!' // highlight-line
},
}
}
}
},
})
```
```tsx
'use client'
import React from 'react'
export const MyComponent = ({ myCustomProp }: { myCustomProp: string }) => {
return (
<button>{myCustomProp}</button>
)
}
```
### Client Components
When [Building Custom Components](#building-custom-components), it's still possible to use client-side code such as `useState` or the `window` object. To do this, simply add the `use client` directive at the top of your file. Payload will automatically detect and remove all default, [non-serializable props](https://react.dev/reference/rsc/use-client#serializable-types) before rendering your component.
```tsx
'use client' // highlight-line
import React, { useState } from 'react'
export const MyClientComponent: React.FC = () => {
const [count, setCount] = useState(0)
return (
<button onClick={() => setCount(count + 1)}>
Clicked {count} times
</button>
)
}
```
<Banner type="warning">
**Reminder:**
Client Components cannot be passed [non-serializable props](https://react.dev/reference/rsc/use-client#serializable-types). If you are rendering your Client Component _from within_ a Server Component, ensure that its props are serializable.
</Banner>
### Accessing the Payload Config
From any Server Component, the [Payload Config](../configuration/overview) can be accessed directly from the `payload` prop:
```tsx
import React from 'react'
export default async function MyServerComponent({
payload: {
config // highlight-line
}
}) {
return (
<Link href={config.serverURL}>
Go Home
</Link>
)
}
```
But, the Payload Config is [non-serializable](https://react.dev/reference/rsc/use-client#serializable-types) by design. It is full of custom validation functions, React components, etc. This means that the Payload Config, in its entirety, cannot be passed directly to Client Components.
For this reason, Payload creates a Client Config and passes it into the Config Provider. This is a serializable version of the Payload Config that can be accessed from any Client Component via the [`useConfig`](./hooks#useconfig) hook:
```tsx
'use client'
import React from 'react'
import { useConfig } from '@payloadcms/ui'
export const MyClientComponent: React.FC = () => {
const { config: { serverURL } } = useConfig() // highlight-line
return (
<Link href={serverURL}>
Go Home
</Link>
)
}
```
<Banner type="success">
See [Using Hooks](#using-hooks) for more details.
</Banner>
All [Field Components](./fields) automatically receive their respective Field Config through props.
```tsx
import React from 'react'
import type { TextFieldServerComponent } from 'payload'
export const MyClientFieldComponent: TextFieldServerComponent = ({ field: { name } }) => {
return (
<p>
{`This field's name is ${name}`}
</p>
)
}
```
### Getting the Current Language
All Custom Components can support multiple languages to be consistent with Payload's [Internationalization](../configuration/i18n). To do this, first add your translation resources to the [I18n Config](../configuration/i18n).
From any Server Component, you can translate resources using the `getTranslation` function from `@payloadcms/translations`. All Server Components automatically receive the `i18n` object as a prop by default.
```tsx
import React from 'react'
import { getTranslation } from '@payloadcms/translations'
export default async function MyServerComponent({ i18n }) {
const translatedTitle = getTranslation(myTranslation, i18n) // highlight-line
return (
<p>{translatedTitle}</p>
)
}
```
The best way to do this within a Client Component is to import the `useTranslation` hook from `@payloadcms/ui`:
```tsx
'use client'
import React from 'react'
import { useTranslation } from '@payloadcms/ui'
export const MyClientComponent: React.FC = () => {
const { t, i18n } = useTranslation() // highlight-line
return (
<ul>
<li>{t('namespace1:key', { variable: 'value' })}</li>
<li>{t('namespace2:key', { variable: 'value' })}</li>
<li>{i18n.language}</li>
</ul>
)
}
```
<Banner type="success">
See the [Hooks](./hooks) documentation for a full list of available hooks.
</Banner>
### Getting the Current Locale
All [Custom Views](./views) can support multiple locales to be consistent with Payload's [Localization](../configuration/localization). They automatically receive the `locale` object as a prop by default. This can be used to scope API requests, etc.:
```tsx
import React from 'react'
export default async function MyServerComponent({ payload, locale }) {
const localizedPage = await payload.findByID({
collection: 'pages',
id: '123',
locale,
})
return (
<p>{localizedPage.title}</p>
)
}
```
The best way to do this within a Client Component is to import the `useLocale` hook from `@payloadcms/ui`:
```tsx
'use client'
import React from 'react'
import { useLocale } from '@payloadcms/ui'
const Greeting: React.FC = () => {
const locale = useLocale() // highlight-line
const trans = {
en: 'Hello',
es: 'Hola',
}
return (
<span>{trans[locale.code]}</span>
)
}
```
<Banner type="success">
See the [Hooks](./hooks) documentation for a full list of available hooks.
</Banner>
### Using Hooks
To make it easier to [build your Custom Components](#building-custom-components), you can use [Payload's built-in React Hooks](./hooks) in any Client Component. For example, you might want to interact with one of Payload's many React Contexts. To do this, you can one of the many hooks available depending on your needs.
```tsx
'use client'
import React from 'react'
import { useDocumentInfo } from '@payloadcms/ui'
export const MyClientComponent: React.FC = () => {
const { slug } = useDocumentInfo() // highlight-line
return (
<p>{`Entity slug: ${slug}`}</p>
)
}
```
<Banner type="success">
See the [Hooks](./hooks) documentation for a full list of available hooks.
</Banner>
### Adding Styles
Payload has a robust [CSS Library](./customizing-css) that you can use to style your Custom Components similarly to Payload's built-in styling. This will ensure that your Custom Components match the existing design system, and so that they automatically adapt to any theme changes that might occur.
To apply custom styles, simply import your own `.css` or `.scss` file into your Custom Component:
```tsx
import './index.scss'
export const MyComponent: React.FC = () => {
return (
<div className="my-component">
My Custom Component
</div>
)
}
```
Then to colorize your Custom Component's background, for example, you can use the following CSS:
```scss
.my-component {
background-color: var(--theme-elevation-500);
}
```
Payload also exports its [SCSS](https://sass-lang.com) library for reuse which includes mixins, etc. To use this, simply import it as follows into your `.scss` file:
```scss
@import '~@payloadcms/ui/scss';
.my-component {
@include mid-break {
background-color: var(--theme-elevation-900);
}
}
```
<Banner type="success">
**Note:**
You can also drill into Payload's own component styles, or easily apply global, app-wide CSS. More on that [here](./customizing-css).
</Banner>
## Root Components
Root Components are those that effect the [Admin Panel](./overview) generally, such as the logo or the main nav.
To override Root Components, use the `admin.components` property in your [Payload Config](../configuration/overview):
```ts
import { buildConfig } from 'payload'
export default buildConfig({
// ...
admin: {
// highlight-start
components: {
// ...
},
// highlight-end
},
})
```
_For details on how to build Custom Components, see [Building Custom Components](#building-custom-components)._
The following options are available:
| Path | Description |
|-----------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **`Nav`** | Contains the sidebar / mobile menu in its entirety. |
| **`beforeNavLinks`** | An array of Custom Components to inject into the built-in Nav, _before_ the links themselves. |
| **`afterNavLinks`** | An array of Custom Components to inject into the built-in Nav, _after_ the links. |
| **`beforeDashboard`** | An array of Custom Components to inject into the built-in Dashboard, _before_ the default dashboard contents. |
| **`afterDashboard`** | An array of Custom Components to inject into the built-in Dashboard, _after_ the default dashboard contents. |
| **`beforeLogin`** | An array of Custom Components to inject into the built-in Login, _before_ the default login form. |
| **`afterLogin`** | An array of Custom Components to inject into the built-in Login, _after_ the default login form. |
| **`logout.Button`** | The button displayed in the sidebar that logs the user out. |
| **`graphics.Icon`** | The simplified logo used in contexts like the the `Nav` component. |
| **`graphics.Logo`** | The full logo used in contexts like the `Login` view. |
| **`providers`** | Custom [React Context](https://react.dev/learn/scaling-up-with-reducer-and-context) providers that will wrap the entire Admin Panel. [More details](#custom-providers). |
| **`actions`** | An array of Custom Components to be rendered _within_ the header of the Admin Panel, providing additional interactivity and functionality. |
| **`header`** | An array of Custom Components to be injected above the Payload header. |
| **`views`** | Override or create new views within the Admin Panel. [More details](./views). |
<Banner type="success">
**Note:**
You can also use set [Collection Components](./collections#custom-components) and [Global Components](./globals#custom-components) in their respective configs.
</Banner>
### Custom Providers
As you add more and more Custom Components to your [Admin Panel](./overview), you may find it helpful to add additional [React Context](https://react.dev/learn/scaling-up-with-reducer-and-context)(s). Payload allows you to inject your own context providers in your app so you can export your own custom hooks, etc.
To add a Custom Provider, use the `admin.components.providers` property in your [Payload Config](../getting-started/overview):
```ts
import { buildConfig } from 'payload'
export default buildConfig({
// ...
admin: {
components: {
providers: ['/path/to/MyProvider'], // highlight-line
},
},
})
```
Then build your Custom Provider as follows:
```tsx
'use client'
import React, { createContext, useContext } from 'react'
const MyCustomContext = React.createContext(myCustomValue)
export const MyProvider: React.FC = ({ children }) => {
return (
<MyCustomContext.Provider value={myCustomValue}>
{children}
</MyCustomContext.Provider>
)
}
export const useMyCustomContext = () => useContext(MyCustomContext)
```
<Banner type="warning">
**Reminder:**React Context exists only within Client Components. This means they must include the `use client` directive at the top of their files and cannot contain server-only code. To use a Server Component here, simply _wrap_ your Client Component with it.
</Banner>

View File

@@ -1,7 +1,7 @@
---
title: Customizing CSS & SCSS
label: Customizing CSS
order: 60
order: 80
desc: Customize the Payload Admin Panel further by adding your own CSS or SCSS style sheet to the configuration, powerful theme and design options are waiting for you.
keywords: admin, css, scss, documentation, Content Management System, cms, headless, javascript, node, react, nextjs
---
@@ -30,7 +30,7 @@ Here is an example of how you might target the Dashboard View and change the bac
<Banner type="warning">
**Note:**
If you are building [Custom Components](../custom-components/overview), it is best to import your own stylesheets directly into your components, rather than using the global stylesheet. You can continue to use the [CSS library](#css-library) as needed.
If you are building [Custom Components](./components), it is best to import your own stylesheets directly into your components, rather than using the global stylesheet. You can continue to use the [CSS library](#css-library) as needed.
</Banner>
### Specificity rules

509
docs/admin/fields.mdx Normal file
View File

@@ -0,0 +1,509 @@
---
title: Customizing Fields
label: Customizing Fields
order: 60
desc:
keywords:
---
[Fields](../fields/overview) within the [Admin Panel](./overview) can be endlessly customized in their appearance and behavior without affecting their underlying data structure. Fields are designed to withstand heavy modification or even complete replacement through the use of [Custom Field Components](#custom-components), [Conditional Logic](#conditional-logic), [Custom Validations](../fields/overview#validation), and more.
For example, your app might need to render a specific interface that Payload does not inherently support, such as a color picker. To do this, you could replace the default [Text Field](../fields/text) input with your own user-friendly component that formats the data into a valid color value.
<Banner type="success">
**Tip:**
Don't see a built-in field type that you need? Build it! Using a combination of [Field Validations](../fields/overview#validation)
and [Custom Components](./components), you can override the entirety of how a component functions within the [Admin Panel](./overview) to effectively create your own field type.
</Banner>
## Admin Options
You can customize the appearance and behavior of fields within the [Admin Panel](./overview) through the `admin` property of any [Field Config](../fields/overview):
```ts
import type { CollectionConfig } from 'payload'
export const CollectionConfig: CollectionConfig = {
// ...
fields: [
// ...
{
name: 'myField',
type: 'text',
admin: { // highlight-line
// ...
},
}
]
}
```
The following options are available:
| Option | Description |
| ----------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **`condition`** | Programmatically show / hide fields based on other fields. [More details](../admin/fields#conditional-logic). |
| **`components`** | All Field Components can be swapped out for [Custom Components](../admin/components) that you define. [More details](../admin/fields). |
| **`description`** | Helper text to display alongside the field to provide more information for the editor. [More details](../admin/fields#description). |
| **`position`** | Specify if the field should be rendered in the sidebar by defining `position: 'sidebar'`. |
| **`width`** | Restrict the width of a field. You can pass any string-based value here, be it pixels, percentages, etc. This property is especially useful when fields are nested within a `Row` type where they can be organized horizontally. |
| **`style`** | [CSS Properties](https://developer.mozilla.org/en-US/docs/Web/CSS) to inject into the root element of the field. |
| **`className`** | Attach a [CSS class attribute](https://developer.mozilla.org/en-US/docs/Web/CSS/Class_selectors) to the root DOM element of a field. |
| **`readOnly`** | Setting a field to `readOnly` has no effect on the API whatsoever but disables the admin component's editability to prevent editors from modifying the field's value. |
| **`disabled`** | If a field is `disabled`, it is completely omitted from the [Admin Panel](../admin/overview) entirely. |
| **`disableBulkEdit`** | Set `disableBulkEdit` to `true` to prevent fields from appearing in the select options when making edits for multiple documents. Defaults to `true` for UI fields. |
| **`disableListColumn`** | Set `disableListColumn` to `true` to prevent fields from appearing in the list view column selector. |
| **`disableListFilter`** | Set `disableListFilter` to `true` to prevent fields from appearing in the list view filter options. |
| **`hidden`** | Will transform the field into a `hidden` input type. Its value will still submit with requests in the Admin Panel, but the field itself will not be visible to editors. |
## Field Descriptions
Field Descriptions are used to provide additional information to the editor about a field, such as special instructions. Their placement varies from field to field, but typically are displayed with subtle style differences beneath the field inputs.
A description can be configured in three ways:
- As a string.
- As a function which returns a string. [More details](#description-functions).
- As a React component. [More details](#description).
To add a Custom Description to a field, use the `admin.description` property in your [Field Config](../fields/overview):
```ts
import type { SanitizedCollectionConfig } from 'payload'
export const MyCollectionConfig: SanitizedCollectionConfig = {
// ...
fields: [
// ...
{
name: 'myField',
type: 'text',
admin: {
description: 'Hello, world!' // highlight-line
},
},
]
}
```
<Banner type="warning">
**Reminder:**
To replace the Field Description with a [Custom Component](./components), use the `admin.components.Description` property. [More details](#description).
</Banner>
#### Description Functions
Custom Descriptions can also be defined as a function. Description Functions are executed on the server and can be used to format simple descriptions based on the user's current [Locale](../configuration/localization).
To add a Description Function to a field, set the `admin.description` property to a _function_ in your [Field Config](../fields/overview):
```ts
import type { SanitizedCollectionConfig } from 'payload'
export const MyCollectionConfig: SanitizedCollectionConfig = {
// ...
fields: [
// ...
{
name: 'myField',
type: 'text',
admin: {
description: ({ t }) => `${t('Hello, world!')}` // highlight-line
},
},
]
}
```
All Description Functions receive the following arguments:
| Argument | Description |
| -------------- | ---------------------------------------------------------------- |
| **`t`** | The `t` function used to internationalize the Admin Panel. [More details](../configuration/i18n) |
<Banner type="info">
**Note:**
If you need to subscribe to live updates within your form, use a Description Component instead. [More details](#description).
</Banner>
## Conditional Logic
You can show and hide fields based on what other fields are doing by utilizing conditional logic on a field by field basis. The `condition` property on a field's admin config accepts a function which takes three arguments:
- `data` - the entire document's data that is currently being edited
- `siblingData` - only the fields that are direct siblings to the field with the condition
- `{ user }` - the final argument is an object containing the currently authenticated user
The `condition` function should return a boolean that will control if the field should be displayed or not.
**Example:**
```ts
{
fields: [
{
name: 'enableGreeting',
type: 'checkbox',
defaultValue: false,
},
{
name: 'greeting',
type: 'text',
admin: {
// highlight-start
condition: (data, siblingData, { user }) => {
if (data.enableGreeting) {
return true
} else {
return false
}
},
// highlight-end
},
},
]
}
```
## Custom Components
Within the [Admin Panel](./overview), fields are represented in three distinct places:
- [Field](#field) - The actual form field rendered in the Edit View.
- [Cell](#cell) - The table cell component rendered in the List View.
- [Filter](#filter) - The filter component rendered in the List View.
To swap in Field Components with your own, use the `admin.components` property in your [Field Config](../fields/overview):
```ts
import type { CollectionConfig } from 'payload'
export const CollectionConfig: CollectionConfig = {
// ...
fields: [
// ...
{
// ...
admin: {
components: { // highlight-line
// ...
},
},
}
]
}
```
The following options are available:
| Component | Description |
| ---------- | --------------------------------------------------------------------------------------------------------------------------- |
| **`Field`** | The form field rendered of the Edit View. [More details](#field). |
| **`Cell`** | The table cell rendered of the List View. [More details](#cell). |
| **`Filter`** | The filter component rendered in the List View. [More details](#filter). |
| **`Label`** | Override the default Label of the Field Component. [More details](#label). |
| **`Error`** | Override the default Error of the Field Component. [More details](#error). |
| **`Description`** | Override the default Description of the Field Component. [More details](#description). |
| **`beforeInput`** | An array of elements that will be added before the input of the Field Component. [More details](#afterinput-and-beforeinput).|
| **`afterInput`** | An array of elements that will be added after the input of the Field Component. [More details](#afterinput-and-beforeinput). |
### Field
The Field Component is the actual form field rendered in the Edit View. This is the input that user's will interact with when editing a document.
To swap in your own Field Component, use the `admin.components.Field` property in your [Field Config](../fields/overview):
```ts
import type { CollectionConfig } from 'payload'
export const CollectionConfig: CollectionConfig = {
// ...
fields: [
// ...
{
// ...
admin: {
components: {
Field: '/path/to/MyFieldComponent', // highlight-line
},
},
}
]
}
```
_For details on how to build Custom Components, see [Building Custom Components](./components#building-custom-components)._
<Banner type="warning">
Instead of replacing the entire Field Component, you can alternately replace or slot-in only specific parts by using the [`Label`](#label), [`Error`](#error), [`beforeInput`](#afterinput-and-beforinput), and [`afterInput`](#afterinput-and-beforinput) properties.
</Banner>
#### Default Props
All Field Components receive the following props by default:
| Property | Description |
| -------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **`docPreferences`** | An object that contains the [Preferences](./preferences) for the document. |
| **`field`** | In Client Components, this is the sanitized Client Field Config. In Server Components, this is the original Field Config. Server Components will also receive the sanitized field config through the`clientField` prop (see below). |
| **`locale`** | The locale of the field. [More details](../configuration/localization). |
| **`readOnly`** | A boolean value that represents if the field is read-only or not. |
| **`user`** | The currently authenticated user. [More details](../authentication/overview). |
| **`validate`** | A function that can be used to validate the field. |
| **`path`** | A string representing the direct, dynamic path to the field at runtime, i.e. `myGroup.myArray.0.myField`. |
| **`schemaPath`** | A string representing the direct, static path to the [Field Config](../fields/overview), i.e. `posts.myGroup.myArray.myField`. |
| **`indexPath`** | A hyphen-notated string representing the path to the field _within the nearest named ancestor field_, i.e. `0-0` |
In addition to the above props, all Server Components will also receive the following props:
| Property | Description |
| ----------------- | ----------------------------------------------------------------------------- |
| **`clientField`** | The serializable Client Field Config. |
| **`field`** | The Field Config. [More details](../fields/overview). |
| **`data`** | The current document being edited. |
| **`i18n`** | The [i18n](../configuration/i18n) object. |
| **`payload`** | The [Payload](../local-api/overview) class. |
| **`permissions`** | The field permissions based on the currently authenticated user. |
| **`siblingData`** | The data of the field's siblings. |
| **`user`** | The currently authenticated user. [More details](../authentication/overview). |
| **`value`** | The value of the field at render-time. |
#### Sending and receiving values from the form
When swapping out the `Field` component, you are responsible for sending and receiving the field's `value` from the form itself.
To do so, import the [`useField`](./hooks#usefield) hook from `@payloadcms/ui` and use it to manage the field's value:
```tsx
'use client'
import { useField } from '@payloadcms/ui'
export const CustomTextField: React.FC = () => {
const { value, setValue } = useField() // highlight-line
return (
<input
onChange={(e) => setValue(e.target.value)}
value={value}
/>
)
}
```
<Banner type="success">
For a complete list of all available React hooks, see the [Payload React Hooks](./hooks) documentation. For additional help, see [Building Custom Components](./components#building-custom-components).
</Banner>
#### TypeScript
When building Custom Field Components, you can import the client field props to ensure type safety in your component. There is an explicit type for the Field Component, one for every [Field Type](../fields/overview) and server/client environment. The convention is to prepend the field type onto the target type, i.e. `TextFieldClientComponent`:
```tsx
import type {
TextFieldClientComponent,
TextFieldServerComponent,
TextFieldClientProps,
TextFieldServerProps,
// ...and so on for each Field Type
} from 'payload'
```
### Cell
The Cell Component is rendered in the table of the List View. It represents the value of the field when displayed in a table cell.
To swap in your own Cell Component, use the `admin.components.Cell` property in your [Field Config](../fields/overview):
```ts
import type { Field } from 'payload'
export const myField: Field = {
name: 'myField',
type: 'text',
admin: {
components: {
Cell: '/path/to/MyCustomCellComponent', // highlight-line
},
},
}
```
All Cell Components receive the same [Default Field Component Props](#field), plus the following:
| Property | Description |
| ---------------- | ----------------------------------------------------------------- |
| **`link`** | A boolean representing whether this cell should be wrapped in a link. |
| **`onClick`** | A function that is called when the cell is clicked. |
For details on how to build Custom Components themselves, see [Building Custom Components](./components#building-custom-components).
### Filter
The Filter Component is the actual input element rendered within the "Filter By" dropdown of the List View used to represent this field when building filters.
To swap in your own Filter Component, use the `admin.components.Filter` property in your [Field Config](../fields/overview):
```ts
import type { Field } from 'payload'
export const myField: Field = {
name: 'myField',
type: 'text',
admin: {
components: {
Filter: '/path/to/MyCustomFilterComponent', // highlight-line
},
},
}
```
All Custom Filter Components receive the same [Default Field Component Props](#field).
For details on how to build Custom Components themselves, see [Building Custom Components](./components#building-custom-components).
### Label
The Label Component is rendered anywhere a field needs to be represented by a label. This is typically used in the Edit View, but can also be used in the List View and elsewhere.
To swap in your own Label Component, use the `admin.components.Label` property in your [Field Config](../fields/overview):
```ts
import type { Field } from 'payload'
export const myField: Field = {
name: 'myField',
type: 'text',
admin: {
components: {
Label: '/path/to/MyCustomLabelComponent', // highlight-line
},
},
}
```
All Custom Label Components receive the same [Default Field Component Props](#field).
For details on how to build Custom Components themselves, see [Building Custom Components](./components#building-custom-components).
#### TypeScript
When building Custom Label Components, you can import the component types to ensure type safety in your component. There is an explicit type for the Label Component, one for every [Field Type](../fields/overview) and server/client environment. The convention is to append `LabelServerComponent` or `LabelClientComponent` to the type of field, i.e. `TextFieldLabelClientComponent`.
```tsx
import type {
TextFieldLabelServerComponent,
TextFieldLabelClientComponent,
// ...and so on for each Field Type
} from 'payload'
```
### Description
Alternatively to the [Description Property](#field-descriptions), you can also use a [Custom Component](./components) as the Field Description. This can be useful when you need to provide more complex feedback to the user, such as rendering dynamic field values or other interactive elements.
To add a Description Component to a field, use the `admin.components.Description` property in your [Field Config](../fields/overview):
```ts
import type { SanitizedCollectionConfig } from 'payload'
export const MyCollectionConfig: SanitizedCollectionConfig = {
// ...
fields: [
// ...
{
name: 'myField',
type: 'text',
admin: {
components: {
Description: '/path/to/MyCustomDescriptionComponent', // highlight-line
}
}
}
]
}
```
All Custom Description Components receive the same [Default Field Component Props](#field).
For details on how to build a Custom Components themselves, see [Building Custom Components](./components#building-custom-components).
#### TypeScript
When building Custom Description Components, you can import the component props to ensure type safety in your component. There is an explicit type for the Description Component, one for every [Field Type](../fields/overview) and server/client environment. The convention is to append `DescriptionServerComponent` or `DescriptionClientComponent` to the type of field, i.e. `TextFieldDescriptionClientComponent`.
```tsx
import type {
TextFieldDescriptionServerComponent,
TextFieldDescriptionClientComponent,
// And so on for each Field Type
} from 'payload'
```
### Error
The Error Component is rendered when a field fails validation. It is typically displayed beneath the field input in a visually-compelling style.
To swap in your own Error Component, use the `admin.components.Error` property in your [Field Config](../fields/overview):
```ts
import type { Field } from 'payload'
export const myField: Field = {
name: 'myField',
type: 'text',
admin: {
components: {
Error: '/path/to/MyCustomErrorComponent', // highlight-line
},
},
}
```
All Error Components receive the [Default Field Component Props](#field).
For details on how to build Custom Components themselves, see [Building Custom Components](./components#building-custom-components).
#### TypeScript
When building Custom Error Components, you can import the component types to ensure type safety in your component. There is an explicit type for the Error Component, one for every [Field Type](../fields/overview) and server/client environment. The convention is to append `ErrorServerComponent` or `ErrorClientComponent` to the type of field, i.e. `TextFieldErrorClientComponent`.
```tsx
import type {
TextFieldErrorServerComponent,
TextFieldErrorClientComponent,
// And so on for each Field Type
} from 'payload'
```
### afterInput and beforeInput
With these properties you can add multiple components _before_ and _after_ the input element, as their name suggests. This is useful when you need to render additional elements alongside the field without replacing the entire field component.
To add components before and after the input element, use the `admin.components.beforeInput` and `admin.components.afterInput` properties in your [Field Config](../fields/overview):
```ts
import type { SanitizedCollectionConfig } from 'payload'
export const MyCollectionConfig: SanitizedCollectionConfig = {
// ...
fields: [
// ...
{
name: 'myField',
type: 'text',
admin: {
components: {
// highlight-start
beforeInput: ['/path/to/MyCustomComponent'],
afterInput: ['/path/to/MyOtherCustomComponent'],
// highlight-end
}
}
}
]
}
```
All `afterInput` and `beforeInput` Components receive the same [Default Field Component Props](#field).
For details on how to build Custom Components, see [Building Custom Components](./components#building-custom-components).

107
docs/admin/globals.mdx Normal file
View File

@@ -0,0 +1,107 @@
---
title: Global Admin Config
label: Globals
order: 30
desc:
keywords: admin, components, custom, documentation, Content Management System, cms, headless, javascript, node, react, nextjs
---
The behavior of [Globals](../configuration/globals) within the [Admin Panel](./overview) can be fully customized to fit the needs of your application. This includes grouping or hiding their navigation links, adding [Custom Components](./components), setting page metadata, and more.
To configure Admin Options for Globals, use the `admin` property in your Global Config:
```ts
import { GlobalConfig } from 'payload'
export const MyGlobal: GlobalConfig = {
// ...
admin: { // highlight-line
// ...
},
}
```
## Admin Options
The following options are available:
| Option | Description |
| ----------------- | --------------------------------------------------------------------------------------------------------------------------------- |
| **`group`** | Text or localization object used to group Collection and Global links in the admin navigation. Set to `false` to hide the link from the navigation while keeping its routes accessible. |
| **`hidden`** | Set to true or a function, called with the current user, returning true to exclude this Global from navigation and admin routing. |
| **`components`** | Swap in your own React components to be used within this Global. [More details](#custom-components). |
| **`preview`** | Function to generate a preview URL within the Admin Panel for this Global that can point to your app. [More details](#preview). |
| **`livePreview`** | Enable real-time editing for instant visual feedback of your front-end application. [More details](../live-preview/overview). |
| **`hideAPIURL`** | Hides the "API URL" meta field while editing documents within this collection. |
| **`meta`** | Page metadata overrides to apply to this Global within the Admin Panel. [More details](./metadata). |
### Custom Components
Globals can set their own [Custom Components](./components) which only apply to [Global](../configuration/globals)-specific UI within the [Admin Panel](./overview). This includes elements such as the Save Button, or entire layouts such as the Edit View.
To override Global Components, use the `admin.components` property in your [Global Config](../configuration/globals):
```ts
import type { SanitizedGlobalConfig } from 'payload'
export const MyGlobal: SanitizedGlobalConfig = {
// ...
admin: {
components: { // highlight-line
// ...
},
},
}
```
The following options are available:
| Path | Description |
| ------------------------------ | ---------------------------------------------------------------------------------------------------------------------- |
| **`elements.SaveButton`** | Replace the default Save Button with a Custom Component. [Drafts](../versions/drafts) must be disabled. |
| **`elements.SaveDraftButton`** | Replace the default Save Draft Button with a Custom Component. [Drafts](../versions/drafts) must be enabled and autosave must be disabled. |
| **`elements.PublishButton`** | Replace the default Publish Button with a Custom Component. [Drafts](../versions/drafts) must be enabled. |
| **`elements.PreviewButton`** | Replace the default Preview Button with a Custom Component. [Preview](#preview) must be enabled. |
| **`views`** | Override or create new views within the Admin Panel. [More details](./views). |
<Banner type="success">
**Note:**
For details on how to build Custom Components, see [Building Custom Components](./components#building-custom-components).
</Banner>
### Preview
It is possible to display a Preview Button within the Edit View of the Admin Panel. This will allow editors to visit the frontend of your app the corresponds to the document they are actively editing. This way they can preview the latest, potentially unpublished changes.
To configure the Preview Button, set the `admin.preview` property to a function in your Global Config:
```ts
import { GlobalConfig } from 'payload'
export const MainMenu: GlobalConfig = {
// ...
admin: {
// highlight-start
preview: (doc, { locale }) => {
if (doc?.slug) {
return `/${doc.slug}?locale=${locale}`
}
return null
},
// highlight-end
},
}
```
The preview function receives two arguments:
| Argument | Description |
| --- | --- |
| **`doc`** | The Document being edited. |
| **`ctx`** | An object containing `locale` and `token` properties. The `token` is the currently logged-in user's JWT. |
<Banner type="success">
**Note:**
For fully working example of this, check of the official [Draft Preview Example](https://github.com/payloadcms/payload/tree/main/examples/draft-preview) in the [Examples Directory](https://github.com/payloadcms/payload/tree/main/examples).
</Banner>

View File

@@ -1,21 +1,21 @@
---
title: React Hooks
label: React Hooks
order: 60
order: 70
desc: Make use of all of the powerful React hooks that Payload provides.
keywords: admin, components, custom, documentation, Content Management System, cms, headless, javascript, node, react, nextjs
---
Payload provides a variety of powerful [React Hooks](https://react.dev/reference/react-dom/hooks) that can be used within your own [Custom Components](../custom-components/overview), such as [Custom Fields](../fields/overview#custom-components). With them, you can interface with Payload itself to build just about any type of complex customization you can think of.
Payload provides a variety of powerful [React Hooks](https://react.dev/reference/react-dom/hooks) that can be used within your own [Custom Components](./components), such as [Custom Fields](./fields). With them, you can interface with Payload itself to build just about any type of complex customization you can think of.
<Banner type="warning">
**Reminder:**
All Custom Components are [React Server Components](https://react.dev/reference/rsc/server-components) by default. Hooks, on the other hand, are only available in client-side environments. To use hooks, [ensure your component is a client component](../custom-components/overview#client-components).
All Custom Components are [React Server Components](https://react.dev/reference/rsc/server-components) by default. Hooks, on the other hand, are only available in client-side environments. To use hooks, [ensure your component is a client component](./components#client-components).
</Banner>
## useField
The `useField` hook is used internally within all field components. It manages sending and receiving a field's state from its parent form. When you build a [Custom Field Component](../fields/overview#custom-components), you will be responsible for sending and receiving the field's `value` to and from the form yourself.
The `useField` hook is used internally within all field components. It manages sending and receiving a field's state from its parent form. When you build a [Custom Field Component](./fields), you will be responsible for sending and receiving the field's `value` to and from the form yourself.
To do so, import the `useField` hook as follows:
@@ -386,7 +386,7 @@ The `useForm` hook returns an object with the following properties:
\`\`\`tsx
import { useForm } from "@payloadcms/ui"
import { useForm } from "payload/components/forms";
export const CustomArrayManager = () => {
const { addFieldRow } = useForm()
@@ -488,7 +488,7 @@ const ExampleCollection = {
\`\`\`tsx
import { useForm } from "@payloadcms/ui"
import { useForm } from "payload/components/forms";
export const CustomArrayManager = () => {
const { removeFieldRow } = useForm()
@@ -589,7 +589,7 @@ const ExampleCollection = {
\`\`\`tsx
import { useForm } from "@payloadcms/ui"
import { useForm } from "payload/components/forms";
export const CustomArrayManager = () => {
const { replaceFieldRow } = useForm()
@@ -654,26 +654,6 @@ const ExampleCollection = {
]}
/>
## useDocumentForm
The `useDocumentForm` hook works the same way as the [useForm](#useform) hook, but it always gives you access to the top-level `Form` of a document. This is useful if you need to access the document's `Form` context from within a child `Form`.
An example where this could happen would be custom components within lexical blocks, as lexical blocks initialize their own child `Form`.
```tsx
'use client'
import { useDocumentForm } from '@payloadcms/ui'
const MyComponent: React.FC = () => {
const { fields: parentDocumentFields } = useDocumentForm()
return (
<p>The document's Form has ${Object.keys(parentDocumentFields).length} fields</p>
)
}
```
## useCollapsible
The `useCollapsible` hook allows you to control parent collapsibles:
@@ -784,45 +764,6 @@ The `useListQuery` hook returns an object with the following properties:
| **`handleWhereChange`** | A method to handle where changes in the List View. |
| **`query`** | The current query that is being used to fetch the data in the List View. |
## useSelection
The `useSelection` hook provides information on the selected rows in the List view as well as helper methods to simplify selection. The `useSelection` hook returns an object with the following properties:
| Property | Description |
| -------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **`count`** | The number of currently selected rows. |
| **`getQueryParams`** | A function that generates a query string based on the current selection state and optional additional filtering parameters. |
| **`selectAll`** | An enum value representing the selection range: `'allAvailable'`, `'allInPage'`, `'none'`, and `'some'`. The enum, `SelectAllStatus`, is exported for easier comparisons. |
| **`selected`** | A map of document id keys and boolean values representing their selection status. |
| **`setSelection`** | A function that toggles the selection status of a document row. |
| **`toggleAll`** | A function that toggles selection for all documents on the current page or selects all available documents when passed `true`. |
| **`totalDocs`** | The number of total documents in the collection. |
**Example:**
```tsx
'use client'
import { useSelection } from '@payloadcms/ui'
const MyComponent: React.FC = () => {
// highlight-start
const { count, toggleAll, totalDocs } = useSelection()
// highlight-end
return (
<>
<span>Selected {count} out of {totalDocs} docs!</span>
<button
type="button"
onClick={() => toggleAll(true)}
>
Toggle All Selections
</button>
</>
)
}
```
## useLocale
In any Custom Component you can get the selected locale object with the `useLocale` hook. `useLocale` gives you the full locale object, consisting of a `label`, `rtl`(right-to-left) property, and then `code`. Here is a simple example:
@@ -875,7 +816,7 @@ const Greeting: React.FC = () => {
## useConfig
Used to retrieve the Payload [Client Config](../custom-components/overview#accessing-the-payload-config).
Used to retrieve the Payload [Client Config](./components#accessing-the-payload-config).
```tsx
'use client'
@@ -890,22 +831,6 @@ const MyComponent: React.FC = () => {
}
```
If you need to retrieve a specific collection or global config by its slug, `getEntityConfig` is the most efficient way to do so:
```tsx
'use client'
import { useConfig } from '@payloadcms/ui'
const MyComponent: React.FC = () => {
// highlight-start
const { getEntityConfig } = useConfig()
const mediaConfig = getEntityConfig({ collectionSlug: 'media'})
// highlight-end
return <span>The media collection has {mediaConfig.fields.length} fields.</span>
}
```
## useEditDepth
Sends back how many editing levels "deep" the current component is. Edit depth is relevant while adding new documents / editing documents in modal windows and other cases.
@@ -1007,146 +932,3 @@ const ListenForUpdates: React.FC = () => {
Right now the `useDocumentEvents` hook only tracks recently updated documents, but in the future
it will track more document-related events as needed, such as document creation, deletion, etc.
</Banner>
## useStepNav
The `useStepNav` hook provides a way to change the step-nav breadcrumb links in the app header.
| Property | Description |
| ---------------- | --------------------------------------------------------------------------------- |
| **`setStepNav`** | A state setter function which sets the `stepNav` array. |
| **`stepNav`** | A `StepNavItem` array where each `StepNavItem` has a label and optionally a url. |
**Example:**
```tsx
'use client'
import { type StepNavItem, useStepNav } from '@payloadcms/ui'
import { useEffect } from 'react'
export const MySetStepNavComponent: React.FC<{
nav: StepNavItem[]
}> = ({ nav }) => {
const { setStepNav } = useStepNav()
useEffect(() => {
setStepNav(nav)
}, [setStepNav, nav])
return null
}
```
## usePayloadAPI
The `usePayloadAPI` hook is a useful tool for making REST API requests to your Payload instance and handling responses reactively. It allows you to fetch and interact with data while automatically updating when parameters change.
This hook returns an array with two elements:
1. An object containing the API response.
2. A set of methods to modify request parameters.
**Example:**
```tsx
'use client'
import { usePayloadAPI } from '@payloadcms/ui'
const MyComponent: React.FC = () => {
// Fetch data from a collection item using its ID
const [{ data, isError, isLoading }, { setParams }] = usePayloadAPI(
'/api/posts/123',
{ initialParams: { depth: 1 } }
)
if (isLoading) return <p>Loading...</p>
if (isError) return <p>Error occurred while fetching data.</p>
return (
<div>
<h1>{data?.title}</h1>
<button onClick={() => setParams({ cacheBust: Date.now() })}>
Refresh Data
</button>
</div>
)
}
```
**Arguments:**
| Property | Description |
| ------------- | ----------------------------------------------------------------------------------------------- |
| **`url`** | The API endpoint to fetch data from. Relative URLs will be prefixed with the Payload API route. |
| **`options`** | An object containing initial request parameters and initial state configuration. |
The `options` argument accepts the following properties:
| Property | Description |
| ------------------- | --------------------------------------------------------------------------------------------------- |
| **`initialData`** | Uses this data instead of making an initial request. If not provided, the request runs immediately. |
| **`initialParams`** | Defines the initial parameters to use in the request. Defaults to an empty object `{}`. |
**Returned Value:**
The first item in the returned array is an object containing the following properties:
| Property | Description |
| --------------- | -------------------------------------------------------- |
| **`data`** | The API response data. |
| **`isError`** | A boolean indicating whether the request failed. |
| **`isLoading`** | A boolean indicating whether the request is in progress. |
The second item is an object with the following methods:
| Property | Description |
| --------------- | ----------------------------------------------------------- |
| **`setParams`** | Updates request parameters, triggering a refetch if needed. |
#### Updating Data
The `setParams` function can be used to update the request and trigger a refetch:
```tsx
setParams({ depth: 2 })
```
This is useful for scenarios where you need to trigger another fetch regardless of the `url` argument changing.
## useRouteTransition
Route transitions are useful in showing immediate visual feedback to the user when navigating between pages. This is especially useful on slow networks when navigating to data heavy or process intensive pages.
By default, any instances of `Link` from `@payloadcms/ui` will trigger route transitions dy default.
```tsx
import { Link } from '@payloadcms/ui'
const MyComponent = () => {
return (
<Link href="/somewhere">
Go Somewhere
</Link>
)
}
```
You can also trigger route transitions programmatically, such as when using `router.push` from `next/router`. To do this, wrap your function calls with the `startRouteTransition` method provided by the `useRouteTransition` hook.
```ts
'use client'
import React, { useCallback } from 'react'
import { useTransition } from '@payloadcms/ui'
import { useRouter } from 'next/navigation'
const MyComponent: React.FC = () => {
const router = useRouter()
const { startRouteTransition } = useRouteTransition()
const redirectSomewhere = useCallback(() => {
startRouteTransition(() => router.push('/somewhere'))
}, [startRouteTransition, router])
// ...
}
```

View File

@@ -1,80 +0,0 @@
---
title: List View
label: List View
order: 50
desc:
keywords: admin, components, custom, documentation, Content Management System, cms, headless, javascript, node, react, nextjs
---
The List View is where users interact with a list of [Collection](../collections/overview) Documents within the [Admin Panel](../admin/overview). This is where they can view, sort, filter, and paginate their documents to find exactly what they're looking for. This is also where users can perform bulk operations on multiple documents at once, such as deleting, editing, or publishing many.
## List filters
List Filters are used to filter the documents displayed in a Collection's List View. Filters can be used to narrow down the list of documents based on specific criteria, such as a date range, status, or other custom fields.
List Filters are simply [Queries](../queries) under the hood. Within the Admin Panel, List Filters are displayed within a "Where Builder" interface, allowing users to generate complex queries through an easy-to-use GUI.
### Base List Filter
You can define a default base filter for this collection's List view, which will be merged into any filters that the user performs.
## Searchable Fields
Specify which fields should be searched in the List search view.
## Default Columns
Array of field names that correspond to which columns to show by default in this Collection's List View.
## Pagination
All Collections receive their own List View which displays a paginated list of documents that can be sorted and filtered. The pagination behavior of the List View can be customized on a per-Collection basis, and uses the same [Pagination](../queries/pagination) API that Payload provides.
To configure pagination options, use the `admin.pagination` property in your Collection Config:
```ts
import type { CollectionConfig } from 'payload'
export const Posts: CollectionConfig = {
// ...
admin: {
// highlight-start
pagination: {
defaultLimit: 10,
limits: [10, 20, 50],
},
// highlight-end
},
}
```
The following options are available:
| Option | Description |
| -------------- | --------------------------------------------------------------------------------------------------- |
| `defaultLimit` | Integer that specifies the default per-page limit that should be used. Defaults to 10. |
| `limits` | Provide an array of integers to use as per-page options for admins to choose from in the List View. |
## List Searchable Fields
In the List View, there is a "search" box that allows you to quickly find a document through a simple text search. By default, it searches on the ID field. If defined, the `admin.useAsTitle` field is used. Or, you can explicitly define which fields to search based on the needs of your application.
To define which fields should be searched, use the `admin.listSearchableFields` property in your Collection Config:
```ts
import type { CollectionConfig } from 'payload'
export const Posts: CollectionConfig = {
// ...
admin: {
// highlight-start
listSearchableFields: ['title', 'slug'],
// highlight-end
},
}
```
<Banner type="warning">
**Tip:**
If you are adding `listSearchableFields`, make sure you index each of these fields so your admin queries can remain performant.
</Banner>

View File

@@ -1,7 +1,7 @@
---
title: Document Locking
label: Document Locking
order: 40
order: 90
desc: Ensure your documents are locked during editing to prevent concurrent changes from multiple users and maintain data integrity.
keywords: locking, document locking, edit locking, document, concurrency, Payload, headless, Content Management System, cms, javascript, react, node, nextjs
---

View File

@@ -1,7 +1,7 @@
---
title: Page Metadata
label: Metadata
order: 80
order: 70
desc: Customize the metadata of your pages within the Admin Panel
keywords: admin, components, custom, documentation, Content Management System, cms, headless, javascript, node, react, nextjs
---
@@ -58,7 +58,7 @@ The following options are available for Root Metadata:
<Banner type="success">
**Reminder:**
These are the _root-level_ options for the Admin Panel. You can also customize metadata on the [Collection](../configuration/collections), [Global](../configuration/globals), and Document levels through their respective configs.
These are the _root-level_ options for the Admin Panel. You can also customize [Collection Metadata](./collections), [Global Metadata](./globals), and [Document Metadata](./documents) in their respective configs.
</Banner>
### Icons
@@ -194,7 +194,7 @@ The Global Meta config has the same options as the [Root Metadata](#root-metadat
## View Metadata
View Metadata is the metadata that is applied to specific [Views](../custom-components/custom-views) within the Admin Panel. This metadata is used to customize the title and description of a specific view, overriding any metadata set at the [Root](#root-metadata), [Collection](#collection-metadata), or [Global](#global-metadata) level.
View Metadata is the metadata that is applied to specific [Views](./views) within the Admin Panel. This metadata is used to customize the title and description of a specific view, overriding any metadata set at the [Root](#root-metadata), [Collection](#collection-metadata), or [Global](#global-metadata) level.
To customize View Metadata, use the `meta` key within your View Config:

View File

@@ -6,14 +6,14 @@ desc: Manage your data and customize the Payload Admin Panel by swapping in your
keywords: admin, components, custom, customize, documentation, Content Management System, cms, headless, javascript, node, react, nextjs
---
Payload dynamically generates a beautiful, [fully type-safe](../typescript/overview) Admin Panel to manage your users and data. It is highly performant, even with 100+ fields, and is translated in over 30 languages. Within the Admin Panel you can manage content, [render your site](../live-preview/overview), [preview drafts](./preview), [diff versions](../versions/overview), and so much more.
Payload dynamically generates a beautiful, [fully type-safe](../typescript/overview) Admin Panel to manage your users and data. It is highly performant, even with 100+ fields, and is translated in over 30 languages. Within the Admin Panel you can manage content, [render your site](../live-preview/overview), preview drafts, [diff versions](../versions/overview), and so much more.
The Admin Panel is designed to [white-label your brand](https://payloadcms.com/blog/white-label-admin-ui). You can endlessly customize and extend the Admin UI by swapping in your own [Custom Components](../custom-components/overview)—everything from simple field labels to entire views can be modified or replaced to perfectly tailor the interface for your editors.
The Admin Panel is designed to [white-label your brand](https://payloadcms.com/blog/white-label-admin-ui). You can endlessly customize and extend the Admin UI by swapping in your own [Custom Components](./components)—everything from simple field labels to entire views can be modified or replaced to perfectly tailor the interface for your editors.
The Admin Panel is written in [TypeScript](https://www.typescriptlang.org) and built with [React](https://react.dev) using the [Next.js App Router](https://nextjs.org/docs/app). It supports [React Server Components](https://react.dev/reference/rsc/server-components), enabling the use of the [Local API](/docs/local-api/overview) on the front-end. You can install Payload into any [existing Next.js app in just one line](../getting-started/installation) and [deploy it anywhere](../production/deployment).
<Banner type="success">
The Payload Admin Panel is designed to be as minimal and straightforward as possible to allow easy customization and control. [Learn more](../custom-components/overview).
The Payload Admin Panel is designed to be as minimal and straightforward as possible to allow easy customization and control. [Learn more](./components).
</Banner>
<LightDarkImage
@@ -57,7 +57,7 @@ The `admin` directory contains all the _pages_ related to the interface itself,
<Banner type="warning">
**Note:**
If you don't intend to use the Admin Panel, [REST API](../rest-api/overview), or [GraphQL API](../graphql/overview), you can opt-out by simply deleting their corresponding directories within your Next.js app. The overhead, however, is completely constrained to these routes, and will not slow down or affect Payload outside when not in use.
If you don't intend to use the Admin Panel, [REST API](../rest/overview), or [GraphQL API](../graphql/overview), you can opt-out by simply deleting their corresponding directories within your Next.js app. The overhead, however, is completely constrained to these routes, and will not slow down or affect Payload outside when not in use.
</Banner>
Finally, the `custom.scss` file is where you can add or override globally-oriented styles in the Admin Panel, such as modify the color palette. Customizing the look and feel through CSS alone is a powerful feature of the Admin Panel, [more on that here](./customizing-css).
@@ -91,7 +91,7 @@ The following options are available:
| **`avatar`** | Set account profile picture. Options: `gravatar`, `default` or a custom React component. |
| **`autoLogin`** | Used to automate log-in for dev and demonstration convenience. [More details](../authentication/overview). |
| **`buildPath`** | Specify an absolute path for where to store the built Admin bundle used in production. Defaults to `path.resolve(process.cwd(), 'build')`. |
| **`components`** | Component overrides that affect the entirety of the Admin Panel. [More details](../custom-components/overview). |
| **`components`** | Component overrides that affect the entirety of the Admin Panel. [More details](./components). |
| **`custom`** | Any custom properties you wish to pass to the Admin Panel. |
| **`dateFormat`** | The date format that will be used for all dates within the Admin Panel. Any valid [date-fns](https://date-fns.org/) format pattern can be used. |
| **`livePreview`** | Enable real-time editing for instant visual feedback of your front-end application. [More details](../live-preview/overview). |
@@ -99,12 +99,11 @@ The following options are available:
| **`routes`** | Replace built-in Admin Panel routes with your own custom routes. [More details](#customizing-routes). |
| **`suppressHydrationWarning`** | If set to `true`, suppresses React hydration mismatch warnings during the hydration of the root `<html>` tag. Defaults to `false`. |
| **`theme`** | Restrict the Admin Panel theme to use only one of your choice. Default is `all`. |
| **`timezones`** | Configure the timezone settings for the admin panel. [More details](#timezones) |
| **`user`** | The `slug` of the Collection that you want to allow to login to the Admin Panel. [More details](#the-admin-user-collection). |
<Banner type="success">
**Reminder:**
These are the _root-level_ options for the Admin Panel. You can also customize [Collection Admin Options](../configuration/collections#admin-options) and [Global Admin Options](../configuration/globals#admin-options) through their respective `admin` keys.
These are the _root-level_ options for the Admin Panel. You can also customize [Collection Admin Options](./collections) and [Global Admin Options](./globals) through their respective `admin` keys.
</Banner>
### The Admin User Collection
@@ -178,7 +177,7 @@ The following options are available:
<Banner type="success">
**Tip:**
You can easily add _new_ routes to the Admin Panel through [Custom Endpoints](../rest-api/overview#custom-endpoints) and [Custom Views](../custom-components/custom-views).
You can easily add _new_ routes to the Admin Panel through [Custom Endpoints](../rest-api/overview#custom-endpoints) and [Custom Views](./views).
</Banner>
#### Customizing Root-level Routes
@@ -233,7 +232,7 @@ The following options are available:
<Banner type="success">
**Note:**
You can also swap out entire _views_ out for your own, using the `admin.views` property of the Payload Config. See [Custom Views](../custom-components/custom-views) for more information.
You can also swap out entire _views_ out for your own, using the `admin.views` property of the Payload Config. See [Custom Views](./views) for more information.
</Banner>
## I18n
@@ -243,21 +242,3 @@ The Payload Admin Panel is translated in over [30 languages and counting](https:
## Light and Dark Modes
Users in the Admin Panel have the ability to choose between light mode and dark mode for their editing experience. Users can select their preferred theme from their account page. Once selected, it is saved to their user's preferences and persisted across sessions and devices. If no theme was selected, the Admin Panel will automatically detect the operation system's theme and use that as the default.
## Timezones
The `admin.timezones` configuration allows you to configure timezone settings for the Admin Panel. You can customise the available list of timezones and in the future configure the default timezone for the Admin Panel and for all users.
The following options are available:
| Option | Description |
| ----------------- | ----------------------------------------------- |
| `supportedTimezones` | An array of label/value options for selectable timezones where the value is the IANA name eg. `America/Detroit` |
| `defaultTimezone` | The `value` of the default selected timezone. eg. `America/Los_Angeles` |
We validate the supported timezones array by checking the value against the list of IANA timezones supported via the Intl API, specifically `Intl.supportedValuesOf('timeZone')`.
<Banner type="info">
**Important**
You must enable timezones on each individual date field via `timezone: true`. See [Date Fields](../fields/overview#date) for more information.
</Banner>

View File

@@ -81,7 +81,7 @@ import { usePreferences } from '@payloadcms/ui'
const lastUsedColorsPreferenceKey = 'last-used-colors';
export function CustomComponent() {
const CustomComponent = (props) => {
const { getPreference, setPreference } = usePreferences();
// Store the last used colors in local state
@@ -154,6 +154,8 @@ export function CustomComponent() {
</Fragment>
)}
</div>
)
}
);
};
export default CustomComponent;
```

View File

@@ -1,217 +0,0 @@
---
title: Preview
label: Preview
order: 30
desc: Enable links to your front-end to preview published or draft content.
keywords: admin, components, preview, documentation, Content Management System, cms, headless, javascript, node, react, nextjs
---
Preview is a feature that allows you to generate a direct link to your front-end application. When enabled, a "preview" button will appear on the Edit View within the [Admin Panel](./overview) with an href pointing to the URL you provide. This will provide your editors with a quick way of navigating to the front-end application where that Document's data is represented. Otherwise, they'd have to determine that URL themselves which is not always straightforward especially in complex apps.
The Preview feature can also be used to achieve something known as "Draft Preview". With Draft Preview, you can navigate to your front-end application and enter "draft mode", where your queries are modified to fetch draft content instead of published content. This is useful for seeing how your content will look before being published. [More details](#draft-preview).
<Banner type="warning">
**Note:**
Preview is different than [Live Preview](../live-preview/overview). Live Preview loads your app within an iframe and renders it in the Admin Panel allowing you to see changes in real-time. Preview, on the other hand, allows you to generate a direct link to your front-end application.
</Banner>
To add Preview, pass a function to the `admin.preview` property in any [Collection Config](../configuration/collections#admin-options) or [Global Config](../configuration/globals#admin-options):
```ts
import type { CollectionConfig } from 'payload'
export const Pages: CollectionConfig = {
slug: 'pages',
admin: {
preview: ({ slug }) => `http://localhost:3000/${slug}`,
},
fields: [
{
name: 'slug',
type: 'text',
}
],
}
```
## Options
The `preview` function resolves to a string that points to your front-end application with additional URL parameters. This can be an absolute URL or a relative path, and can run async if needed.
The following arguments are provided to the `preview` function:
| Path | Description |
| ------------------ | ----------------------------------------------------------------------------------------------------------------- |
| **`doc`** | The data of the Document being edited. This includes changes that have not yet been saved. |
| **`options`** | An object with additional properties. |
The `options` object contains the following properties:
| Path | Description |
| ------------------ | ----------------------------------------------------------------------------------------------------------------- |
| **`locale`** | The current locale of the Document being edited. |
| **`req`** | The Payload Request object. |
| **`token`** | The JWT token of the currently authenticated in user. |
If your application requires a fully qualified URL, such as within deploying to Vercel Preview Deployments, you can use the `req` property to build this URL:
```ts
preview: (doc, { req }) => `${req.protocol}//${req.host}/${doc.slug}` // highlight-line
```
## Draft Preview
The Preview feature can be used to achieve "Draft Preview". After clicking the preview button from the Admin Panel, you can enter into "draft mode" within your front-end application. This will allow you to adjust your page queries to include the `draft: true` param. When this param is present on the request, Payload will send back a draft document as opposed to a published one based on the document's `_status` field.
To enter draft mode, the URL provided to the `preview` function can point to a custom endpoint in your front-end application that sets a cookie or session variable to indicate that draft mode is enabled. This is framework specific, so the mechanisms here very from framework to framework although the underlying concept is the same.
### Next.js
If you're using Next.js, you can do the following code to enter [Draft Mode](https://nextjs.org/docs/app/building-your-application/configuring/draft-mode).
#### Step 1: Format the Preview URL
First, format your `admin.preview` function to point to a custom endpoint that you'll open on your front-end. This URL should include a few key query search params:
```ts
import type { CollectionConfig } from 'payload'
export const Pages: CollectionConfig = {
slug: 'pages',
admin: {
preview: ({ slug, collection }) => {
const encodedParams = new URLSearchParams({
slug,
collection,
path: `/${slug}`,
previewSecret: process.env.PREVIEW_SECRET || ''
})
return `/preview?${encodedParams.toString()}` // highlight-line
}
},
fields: [
{
name: 'slug',
type: 'text',
}
],
}
```
#### Step 2: Create the Preview Route
Then, create an API route that verifies the preview secret, authenticates the user, and enters draft mode:
`/app/preview/route.ts`
```ts
import type { CollectionSlug, PayloadRequest } from 'payload'
import { getPayload } from 'payload'
import { draftMode } from 'next/headers'
import { redirect } from 'next/navigation'
import configPromise from '@payload-config'
export async function GET(
req: {
cookies: {
get: (name: string) => {
value: string
}
}
} & Request,
): Promise<Response> {
const payload = await getPayload({ config: configPromise })
const { searchParams } = new URL(req.url)
const path = searchParams.get('path')
const collection = searchParams.get('collection') as CollectionSlug
const slug = searchParams.get('slug')
const previewSecret = searchParams.get('previewSecret')
if (previewSecret !== process.env.PREVIEW_SECRET) {
return new Response('You are not allowed to preview this page', { status: 403 })
}
if (!path || !collection || !slug) {
return new Response('Insufficient search params', { status: 404 })
}
if (!path.startsWith('/')) {
return new Response('This endpoint can only be used for relative previews', { status: 500 })
}
let user
try {
user = await payload.auth({
req: req as unknown as PayloadRequest,
headers: req.headers,
})
} catch (error) {
payload.logger.error({ err: error }, 'Error verifying token for live preview')
return new Response('You are not allowed to preview this page', { status: 403 })
}
const draft = await draftMode()
if (!user) {
draft.disable()
return new Response('You are not allowed to preview this page', { status: 403 })
}
// You can add additional checks here to see if the user is allowed to preview this page
draft.enable()
redirect(path)
}
```
#### Step 3: Query Draft Content
Finally, in your front-end application, you can detect draft mode and adjust your queries to include drafts:
`/app/[slug]/page.tsx`
```ts
export default async function Page({ params: paramsPromise }) {
const { slug = 'home' } = await paramsPromise
const { isEnabled: isDraftMode } = await draftMode()
const payload = await getPayload({ config })
const page = await payload.find({
collection: 'pages',
depth: 0,
draft: isDraftMode, // highlight-line
limit: 1,
overrideAccess: isDraftMode,
where: {
slug: {
equals: slug,
},
},
})?.then(({ docs }) => docs?.[0])
if (page === null) {
return notFound()
}
return (
<main>
<h1>{page?.title}</h1>
</main>
)
}
```
<Banner type="success">
**Note:**
For fully working example of this, check of the official [Draft Preview Example](https://github.com/payloadcms/payload/tree/main/examples/draft-preview) in the [Examples Directory](https://github.com/payloadcms/payload/tree/main/examples).
</Banner>

375
docs/admin/views.mdx Normal file
View File

@@ -0,0 +1,375 @@
---
title: Customizing Views
label: Customizing Views
order: 50
desc:
keywords:
---
Views are the individual pages that make up the [Admin Panel](./overview), such as the Dashboard, List, and Edit views. One of the most powerful ways to customize the Admin Panel is to create Custom Views. These are [Custom Components](./components) that can either replace built-in views or can be entirely new.
There are four types of views within the Admin Panel:
- [Root Views](#root-views)
- [Collection Views](#collection-views)
- [Global Views](#global-views)
- [Document Views](#document-views)
To swap in your own Custom View, first consult the list of available components, determine the scope that corresponds to what you are trying to accomplish, then [author your React component(s)](#building-custom-views) accordingly.
## Root Views
Root Views are the main views of the [Admin Panel](./overview). These are views that are scoped directly under the `/admin` route, such as the Dashboard or Account views.
To swap Root Views with your own, or to [create entirely new ones](#adding-new-views), use the `admin.components.views` property of your root [Payload Config](../configuration/overview):
```ts
import { buildConfig } from 'payload'
const config = buildConfig({
// ...
admin: {
components: {
views: {
customView: {
Component: '/path/to/MyCustomView#MyCustomView', // highlight-line
path: '/my-custom-view',
}
},
},
},
})
```
Your Custom Root Views can optionally use one of the templates that Payload provides. The most common of these is the Default Template which provides the basic layout and navigation. Here is an example of what that might look like:
```tsx
import type { AdminViewProps } from 'payload'
import { DefaultTemplate } from '@payloadcms/next/templates'
import { Gutter } from '@payloadcms/ui'
import React from 'react'
export const MyCustomView: React.FC<AdminViewProps> = ({
initPageResult,
params,
searchParams,
}) => {
return (
<DefaultTemplate
i18n={initPageResult.req.i18n}
locale={initPageResult.locale}
params={params}
payload={initPageResult.req.payload}
permissions={initPageResult.permissions}
searchParams={searchParams}
user={initPageResult.req.user || undefined}
visibleEntities={initPageResult.visibleEntities}
>
<Gutter>
<h1>Custom Default Root View</h1>
<p>This view uses the Default Template.</p>
</Gutter>
</DefaultTemplate>
)
}
```
_For details on how to build Custom Views, including all available props, see [Building Custom Views](#building-custom-views)._
The following options are available:
| Property | Description |
| --------------- | ----------------------------------------------------------------------------- |
| **`account`** | The Account view is used to show the currently logged in user's Account page. |
| **`dashboard`** | The main landing page of the [Admin Panel](./overview). |
For more granular control, pass a configuration object instead. Payload exposes the following properties for each view:
| Property | Description |
| ------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| **`Component`** * | Pass in the component path that should be rendered when a user navigates to this route. |
| **`path`** * | Any valid URL path or array of paths that [`path-to-regexp`](https://www.npmjs.com/package/path-to-regex) understands. |
| **`exact`** | Boolean. When true, will only match if the path matches the `usePathname()` exactly. |
| **`strict`** | When true, a path that has a trailing slash will only match a `location.pathname` with a trailing slash. This has no effect when there are additional URL segments in the pathname. |
| **`sensitive`** | When true, will match if the path is case sensitive.|
| **`meta`** | Page metadata overrides to apply to this view within the Admin Panel. [More details](./metadata). |
_* An asterisk denotes that a property is required._
### Adding New Views
To add a _new_ views to the [Admin Panel](./overview), simply add your own key to the `views` object with at least a `path` and `Component` property. For example:
```ts
import { buildConfig } from 'payload'
const config = buildConfig({
// ...
admin: {
components: {
views: {
// highlight-start
myCustomView: {
// highlight-end
Component: '/path/to/MyCustomView#MyCustomViewComponent',
path: '/my-custom-view',
},
},
},
},
})
```
The above example shows how to add a new [Root View](#root-views), but the pattern is the same for [Collection Views](#collection-views), [Global Views](#global-views), and [Document Views](#document-views). For help on how to build your own Custom Views, see [Building Custom Views](#building-custom-views).
<Banner type="warning">
**Note:**
Routes are cascading, so unless explicitly given the `exact` property, they will
match on URLs that simply _start_ with the route's path. This is helpful when creating catch-all
routes in your application. Alternatively, define your nested route _before_ your parent
route.
</Banner>
<Banner type="warning">
**Custom views are public**
Custom views are public by default. If your view requires a user to be logged in or to have certain access rights, you should handle that within your view component yourself.
</Banner>
## Collection Views
Collection Views are views that are scoped under the `/collections` route, such as the Collection List and Document Edit views.
To swap out Collection Views with your own, or to [create entirely new ones](#adding-new-views), use the `admin.components.views` property of your [Collection Config](../collections/overview):
```ts
import type { SanitizedCollectionConfig } from 'payload'
export const MyCollectionConfig: SanitizedCollectionConfig = {
// ...
admin: {
components: {
views: {
edit: {
root: {
Component: '/path/to/MyCustomEditView', // highlight-line
}
// other options include:
// default
// versions
// version
// api
// livePreview
// [key: string]
// See "Document Views" for more details
},
list: {
Component: '/path/to/MyCustomListView',
}
},
},
},
}
```
_For details on how to build Custom Views, including all available props, see [Building Custom Views](#building-custom-views)._
<Banner type="warning">
**Note:**
The `root` property will replace the _entire_ Edit View, including the title, tabs, etc., _as well as all nested [Document Views](#document-views)_, such as the API, Live Preview, and Version views. To replace only the Edit View precisely, use the `edit.default` key instead.
</Banner>
The following options are available:
| Property | Description |
| ---------- | ----------------------------------------------------------------------------------------------------------------- |
| **`edit`** | The Edit View is used to edit a single document for any given Collection. [More details](#document-views). |
| **`list`** | The List View is used to show a list of documents for any given Collection. |
<Banner type="success">
**Note:**
You can also add _new_ Collection Views to the config by adding a new key to the `views` object with at least a `path` and `Component` property. See [Adding New Views](#adding-new-views) for more information.
</Banner>
## Global Views
Global Views are views that are scoped under the `/globals` route, such as the Document Edit View.
To swap out Global Views with your own or [create entirely new ones](#adding-new-views), use the `admin.components.views` property in your [Global Config](../configuration/globals):
```ts
import type { SanitizedGlobalConfig } from 'payload'
export const MyGlobalConfig: SanitizedGlobalConfig = {
// ...
admin: {
components: {
views: {
edit: {
root: {
Component: '/path/to/MyCustomEditView', // highlight-line
}
// other options include:
// default
// versions
// version
// api
// livePreview
// [key: string]
},
},
},
},
}
```
_For details on how to build Custom Views, including all available props, see [Building Custom Views](#building-custom-views)._
<Banner type="warning">
**Note:**
The `root` property will replace the _entire_ Edit View, including the title, tabs, etc., _as well as all nested [Document Views](#document-views)_, such as the API, Live Preview, and Version views. To replace only the Edit View precisely, use the `edit.default` key instead.
</Banner>
The following options are available:
| Property | Description |
| ---------- | ------------------------------------------------------------------- |
| **`edit`** | The Edit View is used to edit a single document for any given Global. [More details](#document-views). |
<Banner type="success">
**Note:**
You can also add _new_ Global Views to the config by adding a new key to the `views` object with at least a `path` and `Component` property. See [Adding New Views](#adding-new-views) for more information.
</Banner>
## Document Views
Document Views are views that are scoped under the `/collections/:collectionSlug/:id` or the `/globals/:globalSlug` route, such as the Edit View or the API View. All Document Views keep their overall structure across navigation changes, such as their title and tabs, and replace only the content below.
To swap out Document Views with your own, or to [create entirely new ones](#adding-new-views), use the `admin.components.views.Edit[key]` property in your [Collection Config](../collections/overview) or [Global Config](../configuration/globals):
```ts
import type { SanitizedCollectionConfig } from 'payload'
export const MyCollectionOrGlobalConfig: SanitizedCollectionConfig = {
// ...
admin: {
components: {
views: {
edit: {
api: {
Component: '/path/to/MyCustomAPIViewComponent', // highlight-line
},
},
},
},
},
}
```
_For details on how to build Custom Views, including all available props, see [Building Custom Views](#building-custom-views)._
<Banner type="warning">
**Note:**
If you need to replace the _entire_ Edit View, including _all_ nested Document Views, use the `root` key. See [Custom Collection Views](#collection-views) or [Custom Global Views](#global-views) for more information.
</Banner>
The following options are available:
| Property | Description |
| ----------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **`root`** | The Root View overrides all other nested views and routes. No document controls or tabs are rendered when this key is set. |
| **`default`** | The Default View is the primary view in which your document is edited. It is rendered within the "Edit" tab. |
| **`versions`** | The Versions View is used to navigate the version history of a single document. It is rendered within the "Versions" tab. [More details](../versions/overview). |
| **`version`** | The Version View is used to edit a single version of a document. It is rendered within the "Version" tab. [More details](../versions/overview). |
| **`api`** | The API View is used to display the REST API JSON response for a given document. It is rendered within the "API" tab. |
| **`livePreview`** | The LivePreview view is used to display the Live Preview interface. It is rendered within the "Live Preview" tab. [More details](../live-preview/overview). |
### Document Tabs
Each Document View can be given a new tab in the Edit View, if desired. Tabs are highly configurable, from as simple as changing the label to swapping out the entire component, they can be modified in any way. To add or customize tabs in the Edit View, use the `tab` key:
```ts
import type { SanitizedCollectionConfig } from 'payload'
export const MyCollection: SanitizedCollectionConfig = {
slug: 'my-collection',
admin: {
components: {
views: {
edit: {
myCustomTab: {
Component: '/path/to/MyCustomTab',
path: '/my-custom-tab',
tab: {
Component: '/path/to/MyCustomTabComponent' // highlight-line
}
},
anotherCustomTab: {
Component: '/path/to/AnotherCustomView',
path: '/another-custom-view',
// highlight-start
tab: {
label: 'Another Custom View',
href: '/another-custom-view',
}
// highlight-end
},
},
},
},
},
}
```
<Banner type="warning">
**Note:**
This applies to _both_ Collections _and_ Globals.
</Banner>
## Building Custom Views
Custom Views are just [Custom Components](./components) rendered at the page-level. To understand how to build Custom Views, first review the [Building Custom Components](./components#building-custom-components) guide. Once you have a Custom Component ready, you can use it as a Custom View.
```ts
import type { SanitizedCollectionConfig } from 'payload'
export const MyCollectionConfig: SanitizedCollectionConfig = {
// ...
admin: {
components: {
views: {
edit: {
Component: '/path/to/MyCustomView' // highlight-line
}
},
},
},
}
```
### Default Props
Your Custom Views will be provided with the following props:
| Prop | Description |
| ------------------------- | ---------------------------------------------------------------------------------------------------------------------------------- |
| **`initPageResult`** | An object containing `req`, `payload`, `permissions`, etc. |
| **`clientConfig`** | The Client Config object. [More details](../admin/components#accessing-the-payload-config). |
| **`importMap`** | The import map object. |
| **`params`** | An object containing the [Dynamic Route Parameters](https://nextjs.org/docs/app/building-your-application/routing/dynamic-routes). |
| **`searchParams`** | An object containing the [Search Parameters](https://developer.mozilla.org/docs/Learn/Common_questions/What_is_a_URL#parameters). |
| **`doc`** | The document being edited. Only available in Document Views. [More details](#document-views). |
<Banner type="success">
**Reminder:**
All [Custom Server Components](./components) receive `payload` and `i18n` by default. See [Building Custom Components](./components#building-custom-components) for more details.
</Banner>
<Banner type="warning">
**Important:**
It's up to you to secure your custom views. If your view requires a user to be logged in or to
have certain access rights, you should handle that within your view component yourself.
</Banner>

View File

@@ -312,7 +312,7 @@ Payload comes with built-in forgot password functionality. Submitting an email a
The link to reset the user's password contains a token which is what allows the user to securely reset their password.
By default, the Forgot Password operations send users to the [Admin Panel](../admin/overview) to reset their password, but you can customize the generated email to send users to the frontend of your app instead by [overriding the email HTML](/docs/authentication/email#forgot-password).
By default, the Forgot Password operations send users to the [Admin Panel](../admin/overview) to reset their password, but you can customize the generated email to send users to the frontend of your app instead by [overriding the email HTML](/docs/authentication/overview#forgot-password).
**Example REST API Forgot Password**:
@@ -348,9 +348,7 @@ const token = await payload.forgotPassword({
})
```
<Banner type="info">
**Note:** if you do not have a `config.serverURL` set, Payload will attempt to create one for you if the `forgot-password` operation was triggered via REST or GraphQL by looking at the incoming `req`. But this is not supported if you are calling `payload.forgotPassword()` via the Local API. If you do not have a `serverURL` set, you may want to override your `auth.forgotPassword.generateEmailHTML` function to provide a full URL to link the user to a proper reset-password page.
</Banner>
**Note:** if you do not have a `config.serverURL` set, Payload will attempt to create one for you if the `forgot-password` operation was triggered via REST or GraphQL by looking at the incoming `req`. But this is not supported if you are calling `payload.forgotPassword()` via the Local API. If you do not have a `serverURL` set, you may want to override your `auth.forgotPassword.generateEmailHTML` function to provide a full URL to link the user to a proper reset-password page.
<Banner type="success">
**Tip:**

View File

@@ -132,7 +132,7 @@ If set to `true`, an email address is required when creating a new user. If set
For testing and demo purposes you may want to skip forcing the user to login in order to access your application. Typically, all users should be required to login, however, you can speed up local development time by enabling auto-login.
To enable auto-login, set the `autoLogin` property in the [Payload Config](../admin/overview#admin-options):
To enable auto-login, set the `autoLogin` property in the [Admin Config](../configuration/admin):
```ts
import { buildConfig } from 'payload'

View File

@@ -32,7 +32,7 @@ export default buildConfig({
## Config Options
It's often best practice to write your Collections in separate files and then import them into the main [Payload Config](./overview).
It's often best practice to write your Collections in separate files and then import them into the main [Payload Config](../overview).
Here is what a simple Collection Config might look like:
@@ -59,25 +59,25 @@ The following options are available:
| Option | Description |
| ---------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `admin` | The configuration options for the Admin Panel. [More details](#admin-options). |
| `access` | Provide Access Control functions to define exactly who should be able to do what with Documents in this Collection. [More details](../access-control/collections). |
| `auth` | Specify options if you would like this Collection to feature authentication. [More details](../authentication/overview). |
| `custom` | Extension point for adding custom data (e.g. for plugins) |
| `disableDuplicate` | When true, do not show the "Duplicate" button while editing documents within this Collection and prevent `duplicate` from all APIs. |
| `defaultSort` | Pass a top-level field to sort by default in the Collection List View. Prefix the name of the field with a minus symbol ("-") to sort in descending order. Multiple fields can be specified by using a string array. |
| `dbName` | Custom table or Collection name depending on the Database Adapter. Auto-generated from slug if not defined. |
| `endpoints` | Add custom routes to the REST API. Set to `false` to disable routes. [More details](../rest-api/overview#custom-endpoints). |
| `fields` * | Array of field types that will determine the structure and functionality of the data stored within this Collection. [More details](../fields/overview). |
| `graphQL` | Manage GraphQL-related properties for this collection. [More](#graphql) |
| `hooks` | Entry point for Hooks. [More details](../hooks/overview#collection-hooks). |
| `labels` | Singular and plural labels for use in identifying this Collection throughout Payload. Auto-generated from slug if not defined. |
| `lockDocuments` | Enables or disables document locking. By default, document locking is enabled. Set to an object to configure, or set to `false` to disable locking. [More details](../admin/locked-documents). |
| `slug` * | Unique, URL-friendly string that will act as an identifier for this Collection. |
| `timestamps` | Set to false to disable documents' automatically generated `createdAt` and `updatedAt` timestamps. |
| `typescript` | An object with property `interface` as the text used in schema generation. Auto-generated from slug if not defined. |
| `upload` | Specify options if you would like this Collection to support file uploads. For more, consult the [Uploads](../upload/overview) documentation. |
| `versions` | Set to true to enable default options, or configure with object properties. [More details](../versions/overview#collection-config). |
| `defaultPopulate` | Specify which fields to select when this Collection is populated from another document. [More Details](../queries/select#defaultpopulate-collection-config-property). |
| **`admin`** | The configuration options for the Admin Panel. [More details](../admin/collections). |
| **`access`** | Provide Access Control functions to define exactly who should be able to do what with Documents in this Collection. [More details](../access-control/collections). |
| **`auth`** | Specify options if you would like this Collection to feature authentication. [More details](../authentication/overview). |
| **`custom`** | Extension point for adding custom data (e.g. for plugins) |
| **`disableDuplicate`** | When true, do not show the "Duplicate" button while editing documents within this Collection and prevent `duplicate` from all APIs. |
| **`defaultSort`** | Pass a top-level field to sort by default in the Collection List View. Prefix the name of the field with a minus symbol ("-") to sort in descending order. Multiple fields can be specified by using a string array. |
| **`dbName`** | Custom table or Collection name depending on the Database Adapter. Auto-generated from slug if not defined. |
| **`endpoints`** | Add custom routes to the REST API. Set to `false` to disable routes. [More details](../rest-api/overview#custom-endpoints). |
| **`fields`** * | Array of field types that will determine the structure and functionality of the data stored within this Collection. [More details](../fields/overview). |
| **`graphQL`** | Manage GraphQL-related properties for this collection. [More](#graphql) |
| **`hooks`** | Entry point for Hooks. [More details](../hooks/overview#collection-hooks). |
| **`labels`** | Singular and plural labels for use in identifying this Collection throughout Payload. Auto-generated from slug if not defined. |
| **`lockDocuments`** | Enables or disables document locking. By default, document locking is enabled. Set to an object to configure, or set to `false` to disable locking. [More details](../admin/locked-documents). |
| **`slug`** * | Unique, URL-friendly string that will act as an identifier for this Collection. |
| **`timestamps`** | Set to false to disable documents' automatically generated `createdAt` and `updatedAt` timestamps. |
| **`typescript`** | An object with property `interface` as the text used in schema generation. Auto-generated from slug if not defined. |
| **`upload`** | Specify options if you would like this Collection to support file uploads. For more, consult the [Uploads](../upload/overview) documentation. |
| **`versions`** | Set to true to enable default options, or configure with object properties. [More details](../versions/overview#collection-config). |
| **`defaultPopulate`** | Specify which fields to select when this Collection is populated from another document. [More Details](../queries/select#defaultpopulate-collection-config-property). |
_* An asterisk denotes that a property is required._
@@ -93,43 +93,9 @@ Fields define the schema of the Documents within a Collection. To learn more, go
[Collection Hooks](../hooks/collections) allow you to tie into the lifecycle of your Documents so you can execute your own logic during specific events. To learn more, go to the [Hooks](../hooks/overview) documentation.
## Admin Options
### Admin Options
The behavior of Collections within the [Admin Panel](../admin/overview) can be fully customized to fit the needs of your application. This includes grouping or hiding their navigation links, adding [Custom Components](../custom-components/overview), selecting which fields to display in the List View, and more.
To configure Admin Options for Collections, use the `admin` property in your Collection Config:
```ts
import type { CollectionConfig } from 'payload'
export const MyCollection: CollectionConfig = {
// ...
admin: { // highlight-line
// ...
},
}
```
The following options are available:
| Option | Description |
| -------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `group` | Text or localization object used to group Collection and Global links in the admin navigation. Set to `false` to hide the link from the navigation while keeping its routes accessible. |
| `hidden` | Set to true or a function, called with the current user, returning true to exclude this Collection from navigation and admin routing. |
| `hooks` | Admin-specific hooks for this Collection. [More details](../hooks/collections). |
| `useAsTitle` | Specify a top-level field to use for a document title throughout the Admin Panel. If no field is defined, the ID of the document is used as the title. A field with `virtual: true` cannot be used as the title. |
| `description` | Text to display below the Collection label in the List View to give editors more information. Alternatively, you can use the `admin.components.Description` to render a React component. [More details](../custom-components#list-view). |
| `defaultColumns` | Array of field names that correspond to which columns to show by default in this Collection's List View. |
| `hideAPIURL` | Hides the "API URL" meta field while editing documents within this Collection. |
| `enableRichTextLink` | The [Rich Text](../fields/rich-text) field features a `Link` element which allows for users to automatically reference related documents within their rich text. Set to `true` by default. |
| `enableRichTextRelationship` | The [Rich Text](../fields/rich-text) field features a `Relationship` element which allows for users to automatically reference related documents within their rich text. Set to `true` by default. |
| `meta` | Page metadata overrides to apply to this Collection within the Admin Panel. [More details](../admin/metadata). |
| `preview` | Function to generate preview URLs within the Admin Panel that can point to your app. [More details](../admin/preview). |
| `livePreview` | Enable real-time editing for instant visual feedback of your front-end application. [More details](../live-preview/overview). |
| `components` | Swap in your own React components to be used within this Collection. [More details](../custom-components/overview). |
| `listSearchableFields` | Specify which fields should be searched in the List search view. [More details](../admin/list-view#list-searchable-fields). |
| `pagination` | Set pagination-specific options for this Collection. [More details](../admin/list-view#pagination). |
| `baseListFilter` | You can define a default base filter for this collection's List view, which will be merged into any filters that the user performs. [More details](../admin/list-view#base-list-filter). |
You can customize the way that the [Admin Panel](../admin/overview) behaves on a Collection-by-Collection basis. To learn more, go to the [Collection Admin Options](../admin/collections) documentation.
## GraphQL
@@ -139,10 +105,10 @@ You can also pass an object to the collection's `graphQL` property, which allows
| Option | Description |
| ---------------------- | ----------------------------------------------------------------------------------- |
| `singularName` | Override the "singular" name that will be used in GraphQL schema generation. |
| `pluralName` | Override the "plural" name that will be used in GraphQL schema generation. |
| `disableQueries` | Disable all GraphQL queries that correspond to this collection by passing `true`. |
| `disableMutations` | Disable all GraphQL mutations that correspond to this collection by passing `true`. |
| **`singularName`** | Override the "singular" name that will be used in GraphQL schema generation. |
| **`pluralName`** | Override the "plural" name that will be used in GraphQL schema generation. |
| **`disableQueries`** | Disable all GraphQL queries that correspond to this collection by passing `true`. |
| **`disableMutations`** | Disable all GraphQL mutations that correspond to this collection by passing `true`. |
## TypeScript

View File

@@ -42,7 +42,7 @@ export default buildConfig({
For security and safety reasons, the [Admin Panel](../admin/overview) does **not** include Environment Variables in its _client-side_ bundle by default. But, Next.js provides a mechanism to expose Environment Variables to the client-side bundle when needed.
If you are building a [Custom Component](../custom-components/overview) and need to access Environment Variables from the client-side, you can do so by prefixing them with `NEXT_PUBLIC_`.
If you are building a [Custom Component](../admin/components) and need to access Environment Variables from the client-side, you can do so by prefixing them with `NEXT_PUBLIC_`.
<Banner type="warning">
**Important:**

View File

@@ -6,7 +6,7 @@ desc: Set up your Global config for your needs by defining fields, adding slugs
keywords: globals, config, configuration, documentation, Content Management System, cms, headless, javascript, node, react, nextjs
---
Globals are in many ways similar to [Collections](./collections), except that they correspond to only a single Document. You can define as many Globals as your application needs. Each Global Document is stored in the [Database](../database/overview) based on the [Fields](../fields/overview) that you define, and automatically generates a [Local API](../local-api/overview), [REST API](../rest-api/overview), and [GraphQL API](../graphql/overview) used to manage your Documents.
Globals are in many ways similar to [Collections](../configuration/collections), except that they correspond to only a single Document. You can define as many Globals as your application needs. Each Global Document is stored in the [Database](../database/overview) based on the [Fields](../fields/overview) that you define, and automatically generates a [Local API](../local-api/overview), [REST API](../rest-api/overview), and [GraphQL API](../graphql/overview) used to manage your Documents.
Globals are the primary way to structure singletons in Payload, such as a header navigation, site-wide banner alerts, or app-wide localized strings. Each Global can have its own unique [Access Control](../access-control/overview), [Hooks](../hooks/overview), [Admin Options](#admin-options), and more.
@@ -25,7 +25,7 @@ export default buildConfig({
<Banner type="success">
**Tip:**
If you have more than one Global that share the same structure, consider using a [Collection](./collections) instead.
If you have more than one Global that share the same structure, consider using a [Collection](../configuration/collections) instead.
</Banner>
## Config Options
@@ -67,20 +67,20 @@ The following options are available:
| Option | Description |
| ------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `access` | Provide Access Control functions to define exactly who should be able to do what with this Global. [More details](../access-control/globals). |
| `admin` | The configuration options for the Admin Panel. [More details](#admin-options). |
| `custom` | Extension point for adding custom data (e.g. for plugins) |
| `dbName` | Custom table or collection name for this Global depending on the Database Adapter. Auto-generated from slug if not defined. |
| `description` | Text or React component to display below the Global header to give editors more information. |
| `endpoints` | Add custom routes to the REST API. [More details](../rest-api/overview#custom-endpoints). |
| `fields` * | Array of field types that will determine the structure and functionality of the data stored within this Global. [More details](../fields/overview). |
| `graphQL` | Manage GraphQL-related properties related to this global. [More details](#graphql) |
| `hooks` | Entry point for Hooks. [More details](../hooks/overview#global-hooks). |
| `label` | Text for the name in the Admin Panel or an object with keys for each language. Auto-generated from slug if not defined. |
| `lockDocuments` | Enables or disables document locking. By default, document locking is enabled. Set to an object to configure, or set to `false` to disable locking. [More details](../admin/locked-documents). |
| `slug` * | Unique, URL-friendly string that will act as an identifier for this Global. |
| `typescript` | An object with property `interface` as the text used in schema generation. Auto-generated from slug if not defined. |
| `versions` | Set to true to enable default options, or configure with object properties. [More details](../versions/overview#global-config). |
| **`access`** | Provide Access Control functions to define exactly who should be able to do what with this Global. [More details](../access-control/globals). |
| **`admin`** | The configuration options for the Admin Panel. [More details](../admin/globals). |
| **`custom`** | Extension point for adding custom data (e.g. for plugins) |
| **`dbName`** | Custom table or collection name for this Global depending on the Database Adapter. Auto-generated from slug if not defined. |
| **`description`** | Text or React component to display below the Global header to give editors more information. |
| **`endpoints`** | Add custom routes to the REST API. [More details](../rest-api/overview#custom-endpoints). |
| **`fields`** * | Array of field types that will determine the structure and functionality of the data stored within this Global. [More details](../fields/overview). |
| **`graphQL`** | Manage GraphQL-related properties related to this global. [More details](#graphql) |
| **`hooks`** | Entry point for Hooks. [More details](../hooks/overview#global-hooks). |
| **`label`** | Text for the name in the Admin Panel or an object with keys for each language. Auto-generated from slug if not defined. |
| **`lockDocuments`** | Enables or disables document locking. By default, document locking is enabled. Set to an object to configure, or set to `false` to disable locking. [More details](../admin/locked-documents). |
| **`slug`** * | Unique, URL-friendly string that will act as an identifier for this Global. |
| **`typescript`** | An object with property `interface` as the text used in schema generation. Auto-generated from slug if not defined. |
| **`versions`** | Set to true to enable default options, or configure with object properties. [More details](../versions/overview#globals-config). |
_* An asterisk denotes that a property is required._
@@ -96,34 +96,9 @@ Fields define the schema of the Global. To learn more, go to the [Fields](../fie
[Global Hooks](../hooks/globals) allow you to tie into the lifecycle of your Documents so you can execute your own logic during specific events. To learn more, go to the [Hooks](../hooks/overview) documentation.
## Admin Options
### Admin Options
The behavior of Globals within the [Admin Panel](../admin/overview) can be fully customized to fit the needs of your application. This includes grouping or hiding their navigation links, adding [Custom Components](../custom-components/overview), setting page metadata, and more.
To configure Admin Options for Globals, use the `admin` property in your Global Config:
```ts
import { GlobalConfig } from 'payload'
export const MyGlobal: GlobalConfig = {
// ...
admin: { // highlight-line
// ...
},
}
```
The following options are available:
| Option | Description |
| ----------------- | --------------------------------------------------------------------------------------------------------------------------------- |
| `group` | Text or localization object used to group Collection and Global links in the admin navigation. Set to `false` to hide the link from the navigation while keeping its routes accessible. |
| `hidden` | Set to true or a function, called with the current user, returning true to exclude this Global from navigation and admin routing. |
| `components` | Swap in your own React components to be used within this Global. [More details](../custom-components/overview). |
| `preview` | Function to generate a preview URL within the Admin Panel for this Global that can point to your app. [More details](../admin/preview). |
| `livePreview` | Enable real-time editing for instant visual feedback of your front-end application. [More details](../live-preview/overview). |
| `hideAPIURL` | Hides the "API URL" meta field while editing documents within this collection. |
| `meta` | Page metadata overrides to apply to this Global within the Admin Panel. [More details](../admin/metadata). |
You can customize the way that the [Admin Panel](../admin/overview) behaves on a Global-by-Global basis. To learn more, go to the [Global Admin Options](../admin/globals) documentation.
## GraphQL
@@ -133,9 +108,9 @@ You can also pass an object to the global's `graphQL` property, which allows you
| Option | Description |
| ---------------------- | ----------------------------------------------------------------------------------- |
| `name` | Override the name that will be used in GraphQL schema generation. |
| `disableQueries` | Disable all GraphQL queries that correspond to this global by passing `true`. |
| `disableMutations` | Disable all GraphQL mutations that correspond to this global by passing `true`. |
| **`name`** | Override the name that will be used in GraphQL schema generation. |
| **`disableQueries`** | Disable all GraphQL queries that correspond to this global by passing `true`. |
| **`disableMutations`** | Disable all GraphQL mutations that correspond to this global by passing `true`. |
## TypeScript

View File

@@ -10,13 +10,7 @@ The [Admin Panel](../admin/overview) is translated in over [30 languages and cou
By default, Payload comes preinstalled with English, but you can easily load other languages into your own application. Languages are automatically detected based on the request. If no language is detected, or if the user's language is not yet supported by your application, English will be chosen.
To add I18n to your project, you first need to install the `@payloadcms/translations` package:
```bash
pnpm install @payloadcms/translations
```
Once installed, it can be configured using the `i18n` key in your [Payload Config](./overview):
To configure I18n, use the `i18n` key in your [Payload Config](./overview):
```ts
import { buildConfig } from 'payload'
@@ -55,9 +49,9 @@ The following options are available:
| Option | Description |
| --------------------- | --------------------------------|
| `fallbackLanguage` | The language to fall back to if the user's preferred language is not supported. Default is `'en'`. |
| `translations` | An object containing the translations. The keys are the language codes and the values are the translations. |
| `supportedLanguages` | An object containing the supported languages. The keys are the language codes and the values are the translations. |
| **`fallbackLanguage`** | The language to fall back to if the user's preferred language is not supported. Default is `'en'`. |
| **`translations`** | An object containing the translations. The keys are the language codes and the values are the translations. |
| **`supportedLanguages`** | An object containing the supported languages. The keys are the language codes and the values are the translations. |
## Adding Languages
@@ -172,11 +166,7 @@ export const Articles: CollectionConfig = {
}
```
## Changing Languages
Users can change their preferred language in their account settings or by otherwise manipulating their [User Preferences](../admin/preferences).
## Node.js#node
## Node
Payload's backend sets the language on incoming requests before they are handled. This allows backend validation to return error messages in the user's own language or system generated emails to be sent using the correct translation. You can make HTTP requests with the `accept-language` header and Payload will use that language.
@@ -184,7 +174,7 @@ Anywhere in your Payload app that you have access to the `req` object, you can a
## TypeScript
In order to use [Custom Translations](#custom-translations) in your project, you need to provide the types for the translations.
In order to use custom translations in your project, you need to provide the types for the translations.
Here we create a shareable translations object. We will import this in both our custom components and in our Payload config.
@@ -227,7 +217,7 @@ export default buildConfig({
})
```
Import the shared translation types to use in your [Custom Component](../custom-components/overview):
Import the shared translation types to use in your [Custom Component](../admin/components):
```ts
// <rootDir>/components/MyComponent.tsx
@@ -263,3 +253,4 @@ const field: Field = {
) => t('fields:addLabel'),
}
```

View File

@@ -77,12 +77,11 @@ export default buildConfig({
The following options are available:
| Option | Description |
|------------------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| **`locales`** | Array of all the languages that you would like to support. [More details](#locales) |
| **`defaultLocale`** | Required string that matches one of the locale codes from the array provided. By default, if no locale is specified, documents will be returned in this locale. |
| **`fallback`** | Boolean enabling "fallback" locale functionality. If a document is requested in a locale, but a field does not have a localized value corresponding to the requested locale, then if this property is enabled, the document will automatically fall back to the fallback locale value. If this property is not enabled, the value will not be populated unless a fallback is explicitly provided in the request. True by default. |
| **`filterAvailableLocales`** | A function that is called with the array of `locales` and the `req`, it should return locales to show in admin UI selector. [See more](#filter-available-options). |
| Option | Description |
| -------------- | ------------------------------------------------------------------------------------------------------------------------------ |
| **`locales`** | Array of all the languages that you would like to support. [More details](#locales) |
| **`defaultLocale`** | Required string that matches one of the locale codes from the array provided. By default, if no locale is specified, documents will be returned in this locale. |
| **`fallback`** | Boolean enabling "fallback" locale functionality. If a document is requested in a locale, but a field does not have a localized value corresponding to the requested locale, then if this property is enabled, the document will automatically fall back to the fallback locale value. If this property is not enabled, the value will not be populated unless a fallback is explicitly provided in the request. True by default. |
### Locales
@@ -101,35 +100,6 @@ The locale codes do not need to be in any specific format. It's up to you to def
_* An asterisk denotes that a property is required._
#### Filter Available Options
In some projects you may want to filter the available locales shown in the admin UI selector. You can do this by providing a `filterAvailableLocales` function in your Payload Config. This is called on the server side and is passed the array of locales. This means that you can determine what locales are visible in the localizer selection menu at the top of the admin panel. You could do this per user, or implement a function that scopes these to tenants and more. Here is an example using request headers in a multi-tenant application:
```ts
// ... rest of payload config
localization: {
defaultLocale: 'en',
locales: ['en', 'es'],
filterAvailableLocales: async ({ req, locales }) => {
if (getTenantFromCookie(req.headers, 'text')) {
const fullTenant = await req.payload.findByID({
id: getTenantFromCookie(req.headers, 'text') as string,
collection: 'tenants',
req,
})
if (fullTenant && fullTenant.supportedLocales?.length) {
return locales.filter((locale) => {
return fullTenant.supportedLocales?.includes(locale.code as 'en' | 'es')
})
}
}
return locales
},
}
```
Since the filtering happens at the root level of the application and its result is not calculated every time you navigate to a new page, you may want to call `router.refresh` in a custom component that watches when values that affect the result change. In the example above, you would want to do this when `supportedLocales` changes on the tenant document.
## Field Localization
Payload Localization works on a **field** level—not a document level. In addition to configuring the base Payload Config to support Localization, you need to specify each field that you would like to localize.

View File

@@ -24,7 +24,7 @@ The Payload Config is strongly typed and ties directly into Payload's TypeScript
<Banner type="success">
**Tip:**
The location of your Payload Config can be customized. [More details](#customizing-the-config-location).
The location of your Payload Config can be customized. [More details](#customizing--automating-config-location-detection).
</Banner>
## Config Options
@@ -73,7 +73,7 @@ The following options are available:
| **`collections`** | An array of Collections for Payload to manage. [More details](./collections). |
| **`compatibility`** | Compatibility flags for earlier versions of Payload. [More details](#compatibility-flags). |
| **`globals`** | An array of Globals for Payload to manage. [More details](./globals). |
| **`cors`** | Cross-origin resource sharing (CORS) is a mechanism that accept incoming requests from given domains. You can also customize the `Access-Control-Allow-Headers` header. [More details](#cors). |
| **`cors`** | Cross-origin resource sharing (CORS) is a mechanism that accept incoming requests from given domains. You can also customize the `Access-Control-Allow-Headers` header. [More details](#cross-origin-resource-sharing-cors). |
| **`localization`** | Opt-in to translate your content into multiple locales. [More details](./localization). |
| **`logger`** | Logger options, logger options with a destination stream, or an instantiated logger instance. [More details](https://getpino.io/#/docs/api?id=options). |
| **`loggingLevels`** | An object to override the level to use in the logger for Payload's errors. |
@@ -87,9 +87,9 @@ The following options are available:
| **`upload`** | Base Payload upload configuration. [More details](../upload/overview#payload-wide-upload-options). |
| **`routes`** | Control the routing structure that Payload binds itself to. [More details](../admin/overview#root-level-routes). |
| **`email`** | Configure the Email Adapter for Payload to use. [More details](../email/overview). |
| **`onInit`** | A function that is called immediately following startup that receives the Payload instance as its only argument. |
| **`debug`** | Enable to expose more detailed error information. |
| **`telemetry`** | Disable Payload telemetry by passing `false`. [More details](#telemetry). |
| **`rateLimit`** | Control IP-based rate limiting for all Payload resources. Used to prevent DDoS attacks, etc. [More details](../production/preventing-abuse#rate-limiting-requests). |
| **`hooks`** | An array of Root Hooks. [More details](../hooks/overview). |
| **`plugins`** | An array of Plugins. [More details](../plugins/overview). |
| **`endpoints`** | An array of Custom Endpoints added to the Payload router. [More details](../rest-api/overview#custom-endpoints). |
@@ -103,12 +103,12 @@ _* An asterisk denotes that a property is required._
<Banner type="warning">
**Note:**
Some properties are removed from the client-side bundle. [More details](../custom-components/overview#accessing-the-payload-config).
Some properties are removed from the client-side bundle. [More details](../admin/components#accessing-the-payload-config).
</Banner>
### Typescript Config
Payload exposes a variety of TypeScript settings that you can leverage. These settings are used to auto-generate TypeScript interfaces for your [Collections](./collections) and [Globals](./globals), and to ensure that Payload uses your [Generated Types](../typescript/overview) for all [Local API](../local-api/overview) methods.
Payload exposes a variety of TypeScript settings that you can leverage. These settings are used to auto-generate TypeScript interfaces for your [Collections](../configuration/collections) and [Globals](../configuration/globals), and to ensure that Payload uses your [Generated Types](../typescript/overview) for all [Local API](../local-api/overview) methods.
To customize the TypeScript settings, use the `typescript` property in your Payload Config:
@@ -181,7 +181,7 @@ If none was in either location, Payload will finally check the `dist` directory.
### Customizing the Config Location
In addition to the above automated detection, you can specify your own location for the Payload Config. This can be useful in situations where your config is not in a standard location, or you wish to switch between multiple configurations. To do this, Payload exposes an [Environment Variable](../configuration/environment-vars) to bypass all automatic config detection.
In addition to the above automated detection, you can specify your own location for the Payload Config. This can be useful in situations where your config is not in a standard location, or you wish to switch between multiple configurations. To do this, Payload exposes an [Environment Variable](..environment-variables) to bypass all automatic config detection.
To use a custom config location, set the `PAYLOAD_CONFIG_PATH` environment variable:

View File

@@ -1,49 +0,0 @@
---
title: Swap in your own React Context providers
label: Custom Providers
order: 30
desc:
keywords: admin, components, custom, documentation, Content Management System, cms, headless, javascript, node, react, nextjs
---
As you add more and more [Custom Components](./overview) to your [Admin Panel](../admin/overview), you may find it helpful to add additional [React Context](https://react.dev/learn/scaling-up-with-reducer-and-context)(s) to your app. Payload allows you to inject your own context providers where you can export your own custom hooks, etc.
To add a Custom Provider, use the `admin.components.providers` property in your [Payload Config](../configuration/overview):
```ts
import { buildConfig } from 'payload'
export default buildConfig({
// ...
admin: {
components: {
providers: ['/path/to/MyProvider'], // highlight-line
},
},
})
```
Then build your Custom Provider as follows:
```tsx
'use client'
import React, { createContext, useContext } from 'react'
const MyCustomContext = React.createContext(myCustomValue)
export function MyProvider({ children }: { children: React.ReactNode }) {
return (
<MyCustomContext.Provider value={myCustomValue}>
{children}
</MyCustomContext.Provider>
)
}
export const useMyCustomContext = () => useContext(MyCustomContext)
```
_For details on how to build Custom Components, see [Building Custom Components](./overview#building-custom-components)._
<Banner type="warning">
**Reminder:** React Context exists only within Client Components. This means they must include the `use client` directive at the top of their files and cannot contain server-only code. To use a Server Component here, simply _wrap_ your Client Component with it.
</Banner>

View File

@@ -1,364 +0,0 @@
---
title: Customizing Views
label: Customizing Views
order: 40
desc:
keywords:
---
Views are the individual pages that make up the [Admin Panel](../admin/overview), such as the Dashboard, [List View](./list-view), and [Edit View](./edit-view). One of the most powerful ways to customize the Admin Panel is to create Custom Views. These are [Custom Components](./overview) that can either replace built-in views or be entirely new.
There are four types of views within the Admin Panel:
- [Root Views](#root-views)
- [Collection Views](#collection-views)
- [Global Views](#global-views)
- [Document Views](./document-views)
To swap in your own Custom View, first determine the scope that corresponds to what you are trying to accomplish, consult the list of available components, then [author your React component(s)](#building-custom-views) accordingly.
## Configuration
### Replacing Views
To customize views, use the `admin.components.views` property in your [Payload Config](../configuration/overview). This is an object with keys for each view you want to customize. Each key corresponds to the view you want to customize.
The exact list of available keys depends on the scope of the view you are customizing, depending on whether it's a [Root View](#root-views), [Collection View](#collection-views), or [Global View](#global-views). Regardless of the scope, the principles are the same.
Here is an example of how to swap out a built-in view:
```ts
import { buildConfig } from 'payload'
const config = buildConfig({
// ...
admin: {
components: {
views: {
// highlight-start
dashboard: {
Component: '/path/to/MyCustomDashboard',
}
// highlight-end
}
}
}
})
```
For more granular control, pass a configuration object instead. Payload exposes the following properties for each view:
| Property | Description |
| ------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `Component` * | Pass in the component path that should be rendered when a user navigates to this route. |
| `path` * | Any valid URL path or array of paths that [`path-to-regexp`](https://www.npmjs.com/package/path-to-regex) understands. |
| `exact` | Boolean. When true, will only match if the path matches the `usePathname()` exactly. |
| `strict` | When true, a path that has a trailing slash will only match a `location.pathname` with a trailing slash. This has no effect when there are additional URL segments in the pathname. |
| `sensitive` | When true, will match if the path is case sensitive.|
| `meta` | Page metadata overrides to apply to this view within the Admin Panel. [More details](./metadata). |
_* An asterisk denotes that a property is required._
### Adding New Views
To add a _new_ view to the [Admin Panel](../admin/overview), simply add your own key to the `views` object. This is true for all view scopes.
New views require at least the `Component` and `path` properties:
```ts
import { buildConfig } from 'payload'
const config = buildConfig({
// ...
admin: {
components: {
views: {
// highlight-start
myCustomView: {
Component: '/path/to/MyCustomView#MyCustomViewComponent',
path: '/my-custom-view',
},
// highlight-end
},
},
},
})
```
<Banner type="warning">
**Note:**
Routes are cascading, so unless explicitly given the `exact` property, they will
match on URLs that simply _start_ with the route's path. This is helpful when creating catch-all
routes in your application. Alternatively, define your nested route _before_ your parent
route.
</Banner>
## Building Custom Views
Custom Views are simply [Custom Components](./overview) rendered at the page-level. Custom Views can either [replace existing views](#replacing-views) or [add entirely new ones](#adding-new-views). The process is generally the same regardless of the type of view you are customizing.
To understand how to build Custom Views, first review the [Building Custom Components](./overview#building-custom-components) guide. Once you have a Custom Component ready, you can use it as a Custom View.
```ts
import type { CollectionConfig } from 'payload'
export const MyCollectionConfig: CollectionConfig = {
// ...
admin: {
components: {
views: {
// highlight-start
edit: {
Component: '/path/to/MyCustomView' // highlight-line
}
// highlight-end
},
},
},
}
```
### Default Props
Your Custom Views will be provided with the following props:
| Prop | Description |
| ------------------------- | ---------------------------------------------------------------------------------------------------------------------------------- |
| `initPageResult` | An object containing `req`, `payload`, `permissions`, etc. |
| `clientConfig` | The Client Config object. [More details](./overview#accessing-the-payload-config). |
| `importMap` | The import map object. |
| `params` | An object containing the [Dynamic Route Parameters](https://nextjs.org/docs/app/building-your-application/routing/dynamic-routes). |
| `searchParams` | An object containing the [Search Parameters](https://developer.mozilla.org/docs/Learn/Common_questions/What_is_a_URL#parameters). |
| `doc` | The document being edited. Only available in Document Views. [More details](./document-views). |
| `i18n` | The [i18n](../configuration/i18n) object. |
| `payload` | The [Payload](../local-api/overview) class. |
<Banner type="warning">
**Note:**
Some views may receive additional props, such as [Collection Views](#collection-views) and [Global Views](#global-views). See the relevant section for more details.
</Banner>
Here is an example of a Custom View component:
```tsx
import type { AdminViewServerProps } from 'payload'
import { Gutter } from '@payloadcms/ui'
import React from 'react'
export function MyCustomView(props: AdminViewServerProps) {
return (
<Gutter>
<h1>Custom Default Root View</h1>
<p>This view uses the Default Template.</p>
</Gutter>
)
}
```
<Banner type="success">
**Tip:**
For consistent layout and navigation, you may want to wrap your Custom View with one of the built-in [Template](./overview#templates).
</Banner>
### View Templates
Your Custom Root Views can optionally use one of the templates that Payload provides. The most common of these is the Default Template which provides the basic layout and navigation.
Here is an example of how to use the Default Template in your Custom View:
```tsx
import type { AdminViewServerProps } from 'payload'
import { DefaultTemplate } from '@payloadcms/next/templates'
import { Gutter } from '@payloadcms/ui'
import React from 'react'
export function MyCustomView({
initPageResult,
params,
searchParams,
}: AdminViewServerProps) {
return (
<DefaultTemplate
i18n={initPageResult.req.i18n}
locale={initPageResult.locale}
params={params}
payload={initPageResult.req.payload}
permissions={initPageResult.permissions}
searchParams={searchParams}
user={initPageResult.req.user || undefined}
visibleEntities={initPageResult.visibleEntities}
>
<Gutter>
<h1>Custom Default Root View</h1>
<p>This view uses the Default Template.</p>
</Gutter>
</DefaultTemplate>
)
}
```
### Securing Custom Views
All Custom Views are public by default. It's up to you to secure your custom views. If your view requires a user to be logged in or to have certain access rights, you should handle that within your view component yourself.
Here is how you might secure a Custom View:
```tsx
import type { AdminViewServerProps } from 'payload'
import { Gutter } from '@payloadcms/ui'
import React from 'react'
export function MyCustomView({
initPageResult
}: AdminViewServerProps) {
const {
req: {
user
}
} = initPageResult
if (!user) {
return <p>You must be logged in to view this page.</p>
}
return (
<Gutter>
<h1>Custom Default Root View</h1>
<p>This view uses the Default Template.</p>
</Gutter>
)
}
```
## Root Views
Root Views are the main views of the [Admin Panel](../admin/overview). These are views that are scoped directly under the `/admin` route, such as the Dashboard or Account views.
To [swap out](#replacing-views) Root Views with your own, or to [create entirely new ones](#adding-new-views), use the `admin.components.views` property at the root of your [Payload Config](../configuration/overview):
```ts
import { buildConfig } from 'payload'
const config = buildConfig({
// ...
admin: {
components: {
views: {
// highlight-start
dashboard: {
Component: '/path/to/Dashboard',
}
// highlight-end
// Other options include:
// - account
// - [key: string]
// See below for more details
},
},
},
})
```
_For details on how to build Custom Views, including all available props, see [Building Custom Views](#building-custom-views)._
The following options are available:
| Property | Description |
| --------------- | ----------------------------------------------------------------------------- |
| `account` | The Account view is used to show the currently logged in user's Account page. |
| `dashboard` | The main landing page of the Admin Panel. |
| `[key]` | Any other key can be used to add a completely new Root View. [More details](#adding-new-views). |
## Collection Views
Collection Views are views that are scoped under the `/collections` route, such as the Collection List and Document Edit views.
To [swap out](#replacing-views) Collection Views with your own, or to [create entirely new ones](#adding-new-views), use the `admin.components.views` property of your [Collection Config](../configuration/collections):
```ts
import type { CollectionConfig } from 'payload'
export const MyCollectionConfig: CollectionConfig = {
// ...
admin: {
components: {
views: {
// highlight-start
edit: {
default: {
Component: '/path/to/MyCustomCollectionView',
}
}
// highlight-end
// Other options include:
// - list
// - [key: string]
// See below for more details
},
},
},
}
```
<Banner type="success">
**Reminder:**
The `edit` key is comprised of various nested views, known as Document Views, that relate to the same Collection Document. [More details](./document-views).
</Banner>
The following options are available:
| Property | Description |
| ---------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `edit` | The Edit View corresponds to a single Document for any given Collection and consists of various nested views. [More details](./document-views). |
| `list` | The List View is used to show a list of Documents for any given Collection. [More details](#list-view). |
| `[key]` | Any other key can be used to add a completely new Collection View. [More details](#adding-new-views). |
_For details on how to build Custom Views, including all available props, see [Building Custom Views](#building-custom-views)._
## Global Views
Global Views are views that are scoped under the `/globals` route, such as the Edit View.
To [swap out](#replacing-views) Global Views with your own or [create entirely new ones](#adding-new-views), use the `admin.components.views` property in your [Global Config](../configuration/globals):
```ts
import type { SanitizedGlobalConfig } from 'payload'
export const MyGlobalConfig: SanitizedGlobalConfig = {
// ...
admin: {
components: {
views: {
// highlight-start
edit: {
default: {
Component: '/path/to/MyCustomGlobalView',
}
}
// highlight-end
// Other options include:
// - [key: string]
// See below for more details
},
},
},
}
```
<Banner type="success">
**Reminder:**
The `edit` key is comprised of various nested views, known as Document Views, that relate to the same Global Document. [More details](./document-views).
</Banner>
The following options are available:
| Property | Description |
| ---------- | ----------------------------------------------------------------------------------------------------------------------------------------------- |
| `edit` | The Edit View represents a single Document for any given Global and consists of various nested views. [More details](./document-views). |
| `[key]` | Any other key can be used to add a completely new Global View. [More details](#adding-new-views). |
_For details on how to build Custom Views, including all available props, see [Building Custom Views](#building-custom-views)._

View File

@@ -1,186 +0,0 @@
---
title: Document Views
label: Document Views
order: 50
desc:
keywords:
---
Document Views consist of multiple, individual views that together represent any single [Collection](../configuration/collections) or [Global](../configuration/globals) Document. All Document Views and are scoped under the `/collections/:collectionSlug/:id` or the `/globals/:globalSlug` route, respectively.
There are a number of default Document Views, such as the [Edit View](./edit-view) and API View, but you can also create [entirely new views](./custom-views#adding-new-views) as needed. All Document Views share a layout and can be given their own tab-based navigation, if desired.
To customize Document Views, use the `admin.components.views.edit[key]` property in your [Collection Config](../configuration/collections) or [Global Config](../configuration/globals):
```ts
import type { CollectionConfig } from 'payload'
export const MyCollectionOrGlobalConfig: CollectionConfig = {
// ...
admin: {
components: {
views: {
// highlight-start
edit: {
default: {
Component: '/path/to/MyCustomEditView',
},
// Other options include:
// - root
// - api
// - versions
// - version
// - livePreview
// - [key: string]
// See below for more details
},
// highlight-end
},
},
},
}
```
## Config Options
The following options are available:
| Property | Description |
| ----------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `root` | The Root View overrides all other nested views and routes. No document controls or tabs are rendered when this key is set. [More details](#document-root). |
| `default` | The Default View is the primary view in which your document is edited. It is rendered within the "Edit" tab. [More details](./edit-view). |
| `versions` | The Versions View is used to navigate the version history of a single document. It is rendered within the "Versions" tab. [More details](../versions/overview). |
| `version` | The Version View is used to edit a single version of a document. It is rendered within the "Version" tab. [More details](../versions/overview). |
| `api` | The API View is used to display the REST API JSON response for a given document. It is rendered within the "API" tab. |
| `livePreview` | The LivePreview view is used to display the Live Preview interface. It is rendered within the "Live Preview" tab. [More details](../live-preview/overview). |
| `[key]` | Any other key can be used to add a completely new Document View. |
_For details on how to build Custom Views, including all available props, see [Building Custom Views](./custom-views#building-custom-views)._
### Document Root
The Document Root is mounted on the top-level route for a Document. Setting this property will completely take over the entire Document View layout, including the title, [Document Tabs](#ocument-tabs), _and all other nested Document Views_ including the [Edit View](./edit-view), API View, etc.
When setting a Document Root, you are responsible for rendering all necessary components and controls, as no document controls or tabs would be rendered. To replace only the Edit View precisely, use the `edit.default` key instead.
To override the Document Root, use the `views.edit.root` property in your [Collection Config](../configuration/collections) or [Global Config](../configuration/globals):
```ts
import type { CollectionConfig } from 'payload'
export const MyCollection: CollectionConfig = {
slug: 'my-collection',
admin: {
components: {
views: {
edit: {
// highlight-start
root: {
Component: '/path/to/MyCustomRootComponent', // highlight-line
},
// highlight-end
},
},
},
},
}
```
### Edit View
The Edit View is where users interact with individual Collection and Global Documents. This is where they can view, edit, and save their content. the Edit View is keyed under the `default` property in the `views.edit` object.
For more information on customizing the Edit View, see the [Edit View](./edit-view) documentation.
## Document Tabs
Each Document View can be given a tab for navigation, if desired. Tabs are highly configurable, from as simple as changing the label to swapping out the entire component, they can be modified in any way.
To add or customize tabs in the Document View, use the `views.edit.[key].tab` property in your [Collection Config](../configuration/collections) or [Global Config](../configuration/globals):
```ts
import type { CollectionConfig } from 'payload'
export const MyCollection: CollectionConfig = {
slug: 'my-collection',
admin: {
components: {
views: {
edit: {
myCustomTab: {
Component: '/path/to/MyCustomTab',
path: '/my-custom-tab',
// highlight-start
tab: {
Component: '/path/to/MyCustomTabComponent'
}
// highlight-end
},
anotherCustomTab: {
Component: '/path/to/AnotherCustomView',
path: '/another-custom-view',
// highlight-start
tab: {
label: 'Another Custom View',
href: '/another-custom-view',
}
// highlight-end
},
},
},
},
},
}
```
<Banner type="warning">
**Note:**
This applies to _both_ Collections _and_ Globals.
</Banner>
The following options are available for tabs:
| Property | Description |
| ----------- | ----------------------------------------------------------------------------------------------------- |
| `label` | The label to display in the tab. |
| `href` | The URL to navigate to when the tab is clicked. This is optional and defaults to the tab's `path`. |
| `Component` | The component to render in the tab. This can be a Server or Client component. [More details](#tab-components) |
### Tab Components
If changing the label or href is not enough, you can also replace the entire tab component with your own custom component. This can be done by setting the `tab.Component` property to the path of your custom component.
Here is an example of how to scaffold a custom Document Tab:
#### Server Component
```tsx
import React from 'react'
import type { DocumentTabServerProps } from 'payload'
import { Link } from '@payloadcms/ui'
export function MyCustomTabComponent(props: DocumentTabServerProps) {
return (
<Link href="/my-custom-tab">
This is a custom Document Tab (Server)
</Link>
)
}
```
#### Client Component
```tsx
'use client'
import React from 'react'
import type { DocumentTabClientProps } from 'payload'
import { Link } from '@payloadcms/ui'
export function MyCustomTabComponent(props: DocumentTabClientProps) {
return (
<Link href="/my-custom-tab">
This is a custom Document Tab (Client)
</Link>
)
}
```

View File

@@ -1,463 +0,0 @@
---
title: Customizing the Edit View
label: Customizing the Edit View
order: 60
desc:
keywords: admin, components, custom, documentation, Content Management System, cms, headless, javascript, node, react, nextjs
---
The Edit View is where users interact with individual [Collection](../collections/overview) and [Global](../globals/overview) Documents within the [Admin Panel](../admin/overview). The Edit View contains the actual form in which submits the data to the server. This is where they can view, edit, and save their content. It contains controls for saving, publishing, and previewing the document, all of which can be customized to a high degree.
The Edit View can be swapped out in its entirety for a Custom View, or it can be injected with a number of Custom Components to add additional functionality or presentational elements without replacing the entire view.
<Banner type="warning">
**Note:**
The Edit View is one of many [Document Views](./document-views) in the Payload Admin Panel. Each Document View is responsible for a different aspect of the interacting with a single Document.
</Banner>
## Custom Edit View
To swap out the entire Edit View with a [Custom View](./custom-views), use the `views.edit.default` property in your [Collection Config](../configuration/collections) or [Global Config](../configuration/globals):
```tsx
import { buildConfig } from 'payload'
const config = buildConfig({
// ...
admin: {
components: {
views: {
edit: {
// highlight-start
default: {
Component: '/path/to/MyCustomEditViewComponent',
},
// highlight-end
}
},
},
},
})
```
Here is an example of a custom Edit View:
#### Server Component
```tsx
import React from 'react'
import type { DocumentViewServerProps } from 'payload'
export function MyCustomServerEditView(props: DocumentViewServerProps) {
return (
<div>
This is a custom Edit View (Server)
</div>
)
}
```
#### Client Component
```tsx
'use client'
import React from 'react'
import type { DocumentViewClientProps } from 'payload'
export function MyCustomClientEditView(props: DocumentViewClientProps) {
return (
<div>
This is a custom Edit View (Client)
</div>
)
}
```
_For details on how to build Custom Views, including all available props, see [Building Custom Views](./custom-views#building-custom-views)._
## Custom Components
In addition to swapping out the entire Edit View with a [Custom View](./custom-views), you can also override individual components. This allows you to customize specific parts of the Edit View without swapping out the entire view.
<Banner type="warning">
**Important:**
Collection and Globals are keyed to a different property in the `admin.components` object have slightly different options. Be sure to use the correct key for the entity you are working with.
</Banner>
#### Collections
To override Edit View components for a Collection, use the `admin.components.edit` property in your [Collection Config](../configuration/collections):
```ts
import type { CollectionConfig } from 'payload'
export const MyCollection: CollectionConfig = {
// ...
admin: {
components: {
// highlight-start
edit: {
// ...
},
// highlight-end
},
},
}
```
The following options are available:
| Path | Description |
|-----------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `SaveButton` | A button that saves the current document. [More details](#SaveButton). |
| `SaveDraftButton` | A button that saves the current document as a draft. [More details](#SaveDraftButton). |
| `PublishButton` | A button that publishes the current document. [More details](#PublishButton). |
| `PreviewButton` | A button that previews the current document. [More details](#PreviewButton). |
| `Description` | A description of the Collection. [More details](#Description). |
| `Upload` | A file upload component. [More details](#Upload). |
#### Globals
To override Edit View components for Globals, use the `admin.components.elements` property in your [Global Config](../configuration/globals):
```ts
import type { GlobalConfig } from 'payload'
export const MyGlobal: GlobalConfig = {
// ...
admin: {
components: {
// highlight-start
elements: {
// ...
},
// highlight-end
},
},
}
```
The following options are available:
| Path | Description |
|-----------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `SaveButton` | A button that saves the current document. [More details](#SaveButton). |
| `SaveDraftButton` | A button that saves the current document as a draft. [More details](#SaveDraftButton). |
| `PublishButton` | A button that publishes the current document. [More details](#PublishButton). |
| `PreviewButton` | A button that previews the current document. [More details](#PreviewButton). |
| `Description` | A description of the Global. [More details](#Description). |
### SaveButton
The `SaveButton` property allows you to render a custom Save Button in the Edit View.
To add a `SaveButton` component, use the `components.edit.SaveButton` property in your [Collection Config](../configuration/collections) or `components.elements.SaveButton` in your [Global Config](../configuration/globals):
```ts
import type { CollectionConfig } from 'payload'
export const MyCollection: CollectionConfig = {
// ...
admin: {
components: {
edit: {
// highlight-start
SaveButton: '/path/to/MySaveButton',
// highlight-end
}
},
},
}
```
Here's an example of a custom `SaveButton` component:
#### Server Component
```tsx
import React from 'react'
import { SaveButton } from '@payloadcms/ui'
import type { SaveButtonServerProps } from 'payload'
export function MySaveButton(props: SaveButtonServerProps) {
return (
<SaveButton label="Save" />
)
}
```
#### Client Component
```tsx
'use client'
import React from 'react'
import { SaveButton } from '@payloadcms/ui'
import type { SaveButtonClientProps } from 'payload'
export function MySaveButton(props: SaveButtonClientProps) {
return (
<SaveButton label="Save" />
)
}
```
### SaveDraftButton
The `SaveDraftButton` property allows you to render a custom Save Draft Button in the Edit View.
To add a `SaveDraftButton` component, use the `components.edit.SaveDraftButton` property in your [Collection Config](../configuration/collections) or `components.elements.SaveDraftButton` in your [Global Config](../configuration/globals):
```ts
import type { CollectionConfig } from 'payload'
export const MyCollection: CollectionConfig = {
// ...
admin: {
components: {
edit: {
// highlight-start
SaveDraftButton: '/path/to/MySaveDraftButton',
// highlight-end
}
},
},
}
```
Here's an example of a custom `SaveDraftButton` component:
#### Server Component
```tsx
import React from 'react'
import { SaveDraftButton } from '@payloadcms/ui'
import type { SaveDraftButtonServerProps } from 'payload'
export function MySaveDraftButton(props: SaveDraftButtonServerProps) {
return (
<SaveDraftButton />
)
}
```
#### Client Component
```tsx
'use client'
import React from 'react'
import { SaveDraftButton } from '@payloadcms/ui'
import type { SaveDraftButtonClientProps } from 'payload'
export function MySaveDraftButton(props: SaveDraftButtonClientProps) {
return (
<SaveDraftButton />
)
}
```
### PublishButton
The `PublishButton` property allows you to render a custom Publish Button in the Edit View.
To add a `PublishButton` component, use the `components.edit.PublishButton` property in your [Collection Config](../configuration/collections) or `components.elements.PublishButton` in your [Global Config](../configuration/globals):
```ts
import type { CollectionConfig } from 'payload'
export const MyCollection: CollectionConfig = {
// ...
admin: {
components: {
edit: {
// highlight-start
PublishButton: '/path/to/MyPublishButton',
// highlight-end
}
},
},
}
```
Here's an example of a custom `PublishButton` component:
#### Server Component
```tsx
import React from 'react'
import { PublishButton } from '@payloadcms/ui'
import type { PublishButtonClientProps } from 'payload'
export function MyPublishButton(props: PublishButtonServerProps) {
return (
<PublishButton label="Publish" />
)
}
```
#### Client Component
```tsx
'use client'
import React from 'react'
import { PublishButton } from '@payloadcms/ui'
import type { PublishButtonClientProps } from 'payload'
export function MyPublishButton(props: PublishButtonClientProps) {
return (
<PublishButton label="Publish" />
)
}
```
### PreviewButton
The `PreviewButton` property allows you to render a custom Preview Button in the Edit View.
To add a `PreviewButton` component, use the `components.edit.PreviewButton` property in your [Collection Config](../configuration/collections) or `components.elements.PreviewButton` in your [Global Config](../configuration/globals):
```ts
import type { CollectionConfig } from 'payload'
export const MyCollection: CollectionConfig = {
// ...
admin: {
components: {
edit: {
// highlight-start
PreviewButton: '/path/to/MyPreviewButton',
// highlight-end
}
},
},
}
```
Here's an example of a custom `PreviewButton` component:
#### Server Component
```tsx
import React from 'react'
import { PreviewButton } from '@payloadcms/ui'
import type { PreviewButtonServerProps } from 'payload'
export function MyPreviewButton(props: PreviewButtonServerProps) {
return (
<PreviewButton />
)
}
```
#### Client Component
```tsx
'use client'
import React from 'react'
import { PreviewButton } from '@payloadcms/ui'
import type { PreviewButtonClientProps } from 'payload'
export function MyPreviewButton(props: PreviewButtonClientProps) {
return (
<PreviewButton />
)
}
```
### Description
The `Description` property allows you to render a custom description of the Collection or Global in the Edit View.
To add a `Description` component, use the `components.edit.Description` property in your [Collection Config](../configuration/collections) or `components.elements.Description` in your [Global Config](../configuration/globals):
```ts
import type { CollectionConfig } from 'payload'
export const MyCollection: CollectionConfig = {
// ...
admin: {
components: {
// highlight-start
Description: '/path/to/MyDescriptionComponent',
// highlight-end
},
},
}
```
<Banner type="warning">
**Note:**
The `Description` component is shared between the Edit View and the [List View](./list-view).
</Banner>
Here's an example of a custom `Description` component:
#### Server Component
```tsx
import React from 'react'
import type { ViewDescriptionServerProps } from 'payload'
export function MyDescriptionComponent(props: ViewDescriptionServerProps) {
return (
<div>
This is a custom description component (Server)
</div>
)
}
```
#### Client Component
```tsx
'use client'
import React from 'react'
import type { ViewDescriptionClientProps } from 'payload'
export function MyDescriptionComponent(props: ViewDescriptionClientProps) {
return (
<div>
This is a custom description component (Client)
</div>
)
}
```
### Upload
The `Upload` property allows you to render a custom file upload component in the Edit View.
To add an `Upload` component, use the `components.edit.Upload` property in your [Collection Config](../configuration/collections):
```ts
import type { CollectionConfig } from 'payload'
export const MyCollection: CollectionConfig = {
// ...
admin: {
components: {
edit: {
// highlight-start
Upload: '/path/to/MyUploadComponent',
// highlight-end
}
},
},
}
```
<Banner type="warning">
**Note:**
The Upload component is only available for Collections.
</Banner>
Here's an example of a custom `Upload` component:
```tsx
import React from 'react'
export function MyUploadComponent() {
return (
<input type="file" />
)
}
```

View File

@@ -1,387 +0,0 @@
---
title: Customizing the List View
label: Customizing the List View
order: 70
desc:
keywords: admin, components, custom, documentation, Content Management System, cms, headless, javascript, node, react, nextjs
---
The List View is where users interact with a list of [Collection](../collections/overview) Documents within the [Admin Panel](../admin/overview). This is where they can view, sort, filter, and paginate their documents to find exactly what they're looking for. This is also where users can perform bulk operations on multiple documents at once, such as deleting, editing, or publishing many.
The List View can be swapped out in its entirety for a Custom View, or it can be injected with a number of Custom Components to add additional functionality or presentational elements without replacing the entire view.
<Banner type="info">
**Note:**
Only [Collections](../collections/overview) have a List View. [Globals](../globals/overview) do not have a List View as they are single documents.
</Banner>
## Custom List View
To swap out the entire List View with a [Custom View](./custom-views), use the `admin.components.views.list` property in your [Payload Config](../configuration/overview):
```tsx
import { buildConfig } from 'payload'
const config = buildConfig({
// ...
admin: {
components: {
views: {
// highlight-start
list: '/path/to/MyCustomListView',
// highlight-end
},
},
},
})
```
Here is an example of a custom List View:
#### Server Component
```tsx
import React from 'react'
import type { ListViewServerProps } from 'payload'
import { DefaultListView } from '@payloadcms/ui'
export function MyCustomServerListView(props: ListViewServerProps) {
return (
<div>
This is a custom List View (Server)
</div>
)
}
```
#### Client Component
```tsx
'use client'
import React from 'react'
import type { ListViewClientProps } from 'payload'
export function MyCustomClientListView(props: ListViewClientProps) {
return (
<div>
This is a custom List View (Client)
</div>
)
}
```
_For details on how to build Custom Views, including all available props, see [Building Custom Views](./custom-views#building-custom-views)._
## Custom Components
In addition to swapping out the entire List View with a [Custom View](./custom-views), you can also override individual components. This allows you to customize specific parts of the List View without swapping out the entire view for your own.
To override List View components for a Collection, use the `admin.components` property in your [Collection Config](../configuration/collections):
```ts
import type { CollectionConfig } from 'payload'
export const MyCollection: CollectionConfig = {
// ...
admin: {
// highlight-start
components: {
// ...
},
// highlight-end
},
}
```
The following options are available:
| Path | Description |
|-----------------------|----------------------------------------------------------------------------------------------------------------------------- |
| `beforeList` | An array of custom components to inject before the list of documents in the List View. [More details](#beforeList). |
| `beforeListTable` | An array of custom components to inject before the table of documents in the List View. [More details](#beforeListTable). |
| `afterList` | An array of custom components to inject after the list of documents in the List View. [More details](#afterList). |
| `afterListTable` | An array of custom components to inject after the table of documents in the List View. [More details](#afterListTable). |
| `Description` | A component to render a description of the Collection. [More details](#Description). |
### beforeList
The `beforeList` property allows you to inject custom components before the list of documents in the List View.
To add `beforeList` components, use the `components.beforeList` property in your [Collection Config](../configuration/collections):
```ts
import type { CollectionConfig } from 'payload'
export const MyCollection: CollectionConfig = {
// ...
admin: {
components: {
// highlight-start
beforeList: [
'/path/to/MyBeforeListComponent',
],
// highlight-end
},
},
}
```
Here's an example of a custom `beforeList` component:
#### Server Component
```tsx
import React from 'react'
import type { BeforeListServerProps } from 'payload'
export function MyBeforeListComponent(props: BeforeListServerProps) {
return (
<div>
This is a custom beforeList component (Server)
</div>
)
}
```
#### Client Component
```tsx
'use client'
import React from 'react'
import type { BeforeListClientProps } from 'payload'
export function MyBeforeListComponent(props: BeforeListClientProps) {
return (
<div>
This is a custom beforeList component (Client)
</div>
)
}
```
### beforeListTable
The `beforeListTable` property allows you to inject custom components before the table of documents in the List View.
To add `beforeListTable` components, use the `components.beforeListTable` property in your [Collection Config](../configuration/collections):
```ts
import type { CollectionConfig } from 'payload'
export const MyCollection: CollectionConfig = {
// ...
admin: {
components: {
// highlight-start
beforeListTable: [
'/path/to/MyBeforeListTableComponent',
],
// highlight-end
},
},
}
```
Here's an example of a custom `beforeListTable` component:
#### Server Component
```tsx
import React from 'react'
import type { BeforeListTableServerProps } from 'payload'
export function MyBeforeListTableComponent(props: BeforeListTableServerProps) {
return (
<div>
This is a custom beforeListTable component (Server)
</div>
)
}
```
#### Client Component
```tsx
'use client'
import React from 'react'
import type { BeforeListTableClientProps } from 'payload'
export function MyBeforeListTableComponent(props: BeforeListTableClientProps) {
return (
<div>
This is a custom beforeListTable component (Client)
</div>
)
}
```
### afterList
The `afterList` property allows you to inject custom components after the list of documents in the List View.
To add `afterList` components, use the `components.afterList` property in your [Collection Config](../configuration/collections):
```ts
import type { CollectionConfig } from 'payload'
export const MyCollection: CollectionConfig = {
// ...
admin: {
components: {
// highlight-start
afterList: [
'/path/to/MyAfterListComponent',
],
// highlight-end
},
},
}
```
Here's an example of a custom `afterList` component:
#### Server Component
```tsx
import React from 'react'
import type { AfterListServerProps } from 'payload'
export function MyAfterListComponent(props: AfterListServerProps) {
return (
<div>
This is a custom afterList component (Server)
</div>
)
}
```
#### Client Component
```tsx
'use client'
import React from 'react'
import type { AfterListClientProps } from 'payload'
export function MyAfterListComponent(props: AfterListClientProps) {
return (
<div>
This is a custom afterList component (Client)
</div>
)
}
```
### afterListTable
The `afterListTable` property allows you to inject custom components after the table of documents in the List View.
To add `afterListTable` components, use the `components.afterListTable` property in your [Collection Config](../configuration/collections):
```ts
import type { CollectionConfig } from 'payload'
export const MyCollection: CollectionConfig = {
// ...
admin: {
components: {
// highlight-start
afterListTable: [
'/path/to/MyAfterListTableComponent',
],
// highlight-end
},
},
}
```
Here's an example of a custom `afterListTable` component:
#### Server Component
```tsx
import React from 'react'
import type { AfterListTableServerProps } from 'payload'
export function MyAfterListTableComponent(props: AfterListTableServerProps) {
return (
<div>
This is a custom afterListTable component (Server)
</div>
)
}
```
#### Client Component
```tsx
'use client'
import React from 'react'
import type { AfterListTableClientProps } from 'payload'
export function MyAfterListTableComponent(props: AfterListTableClientProps) {
return (
<div>
This is a custom afterListTable component (Client)
</div>
)
}
```
### Description
The `Description` property allows you to render a custom description of the Collection in the List View.
To add a `Description` component, use the `components.Description` property in your [Collection Config](../configuration/collections):
```ts
import type { CollectionConfig } from 'payload'
export const MyCollection: CollectionConfig = {
// ...
admin: {
components: {
// highlight-start
Description: '/path/to/MyDescriptionComponent',
// highlight-end
},
},
}
```
<Banner type="warning">
**Note:**
The `Description` component is shared between the List View and the [Edit View](./edit-view).
</Banner>
Here's an example of a custom `Description` component:
#### Server Component
```tsx
import React from 'react'
import type { ViewDescriptionServerProps } from 'payload'
export function MyDescriptionComponent(props: ViewDescriptionServerProps) {
return (
<div>
This is a custom Collection description component (Server)
</div>
)
}
```
#### Client Component
```tsx
'use client'
import React from 'react'
import type { ViewDescriptionClientProps } from 'payload'
export function MyDescriptionComponent(props: ViewDescriptionClientProps) {
return (
<div>
This is a custom Collection description component (Client)
</div>
)
}
```

View File

@@ -1,491 +0,0 @@
---
title: Swap in your own React components
label: Overview
order: 10
desc: Fully customize your Admin Panel by swapping in your own React components. Add fields, remove views, update routes and change functions to sculpt your perfect Dashboard.
keywords: admin, components, custom, documentation, Content Management System, cms, headless, javascript, node, react, nextjs
---
The Payload [Admin Panel](../admin/overview) is designed to be as minimal and straightforward as possible to allow for easy customization and full control over the UI. In order for Payload to support this level of customization, Payload provides a pattern for you to supply your own React components through your [Payload Config](../configuration/overview).
All Custom Components in Payload are [React Server Components](https://react.dev/reference/rsc/server-components) by default. This enables the use of the [Local API](../local-api/overview) directly on the front-end. Custom Components are available for nearly every part of the Admin Panel for extreme granularity and control.
<Banner type="success">
**Note:**
Client Components continue to be fully supported. To use Client Components in your app, simply include the `'use client'` directive. Payload will automatically detect and remove all [non-serializable](https://react.dev/reference/rsc/use-client#serializable-types) default props before rendering your component. [More details](#client-components).
</Banner>
There are four main types of Custom Components in Payload:
- [Root Components](./root-components)
- [Collection Components](../configuration/collections#custom-components)
- [Global Components](../configuration/globals#custom-components)
- [Field Components](../fields/overview#custom-components)
To swap in your own Custom Component, first determine the scope that corresponds to what you are trying to accomplish, consult the list of available components, then [author your React component(s)](#building-custom-components) accordingly.
## Defining Custom Components
As Payload compiles the Admin Panel, it checks your config for Custom Components. When detected, Payload either replaces its own default component with yours, or if none exists by default, renders yours outright. While there are many places where Custom Components are supported in Payload, each is defined in the same way using [Component Paths](#component-paths).
To add a Custom Component, point to its file path in your Payload Config:
```ts
import { buildConfig } from 'payload'
const config = buildConfig({
// ...
admin: {
components: {
logout: {
Button: '/src/components/Logout#MyComponent' // highlight-line
}
}
},
})
```
<Banner type="success">
**Note:**
All Custom Components can be either Server Components or Client Components, depending on the presence of the `'use client'` directive at the top of the file.
</Banner>
### Component Paths
In order to ensure the Payload Config is fully Node.js compatible and as lightweight as possible, components are not directly imported into your config. Instead, they are identified by their file path for the Admin Panel to resolve on its own.
Component Paths, by default, are relative to your project's base directory. This is either your current working directory, or the directory specified in `config.admin.importMap.baseDir`.
Components using named exports are identified either by appending `#` followed by the export name, or using the `exportName` property. If the component is the default export, this can be omitted.
```ts
import { buildConfig } from 'payload'
import { fileURLToPath } from 'node:url'
import path from 'path'
const filename = fileURLToPath(import.meta.url)
const dirname = path.dirname(filename)
const config = buildConfig({
// ...
admin: {
importMap: {
baseDir: path.resolve(dirname, 'src'), // highlight-line
},
components: {
logout: {
Button: '/components/Logout#MyComponent' // highlight-line
}
}
},
})
```
In this example, we set the base directory to the `src` directory, and omit the `/src/` part of our component path string.
### Component Config
While Custom Components are usually defined as a string, you can also pass in an object with additional options:
```ts
import { buildConfig } from 'payload'
const config = buildConfig({
// ...
admin: {
components: {
logout: {
// highlight-start
Button: {
path: '/src/components/Logout',
exportName: 'MyComponent',
}
// highlight-end
}
}
},
})
```
The following options are available:
| Property | Description |
|---------------|-------------------------------------------------------------------------------------------------------------------------------|
| `clientProps` | Props to be passed to the Custom Components if it's a Client Component. [More details](#custom-props). |
| `exportName` | Instead of declaring named exports using `#` in the component path, you can also omit them from `path` and pass them in here. |
| `path` | File path to the Custom Component. Named exports can be appended to the end of the path, separated by a `#`. |
| `serverProps` | Props to be passed to the Custom Component if it's a Server Component. [More details](#custom-props). |
For details on how to build Custom Components, see [Building Custom Components](#building-custom-components).
### Import Map
In order for Payload to make use of [Component Paths](#component-paths), an "Import Map" is automatically generated at `app/(payload)/admin/importMap.js`. This file contains every Custom Component in your config, keyed to their respective paths. When Payload needs to lookup a component, it uses this file to find the correct import.
The Import Map is automatically regenerated at startup and whenever Hot Module Replacement (HMR) runs, or you can run `payload generate:importmap` to manually regenerate it.
#### Custom Imports
If needed, custom items can be appended onto the Import Map. This is mostly only relevant for plugin authors who need to add a custom import that is not referenced in a known location.
To add a custom import to the Import Map, use the `admin.dependencies` property in your [Payload Config](../configuration/overview):
```ts
import { buildConfig } from 'payload'
export default buildConfig({
// ...
admin: {
// ...
dependencies: {
myTestComponent: { // myTestComponent is the key - can be anything
path: '/components/TestComponent.js#TestComponent',
type: 'component',
clientProps: {
test: 'hello',
},
},
},
}
}
```
## Building Custom Components
All Custom Components in Payload are [React Server Components](https://react.dev/reference/rsc/server-components) by default. This enables the use of the [Local API](../local-api/overview) directly on the front-end, among other things.
### Default Props
To make building Custom Components as easy as possible, Payload automatically provides common props, such as the [`payload`](../local-api/overview) class and the [`i18n`](../configuration/i18n) object. This means that when building Custom Components within the Admin Panel, you do not have to get these yourself.
Here is an example:
```tsx
import React from 'react'
import type { Payload } from 'payload'
async function MyServerComponent({
payload // highlight-line
}: {
payload: Payload
}) {
const page = await payload.findByID({
collection: 'pages',
id: '123',
})
return (
<p>{page.title}</p>
)
}
```
Each Custom Component receives the following props by default:
| Prop | Description |
| ------------------------- | ----------------------------------------------------------------------------------------------------- |
| `payload` | The [Payload](../local-api/overview) class. |
| `i18n` | The [i18n](../configuration/i18n) object. |
<Banner type="warning">
**Reminder:**
All Custom Components also receive various other props that are specific to the component being rendered. See [Root Components](#root-components), [Collection Components](../configuration/collections#custom-components), [Global Components](../configuration/globals#custom-components), or [Field Components](../fields/overview#custom-components) for a complete list of all default props per component.
</Banner>
### Custom Props
It is also possible to pass custom props to your Custom Components. To do this, you can use either the `clientProps` or `serverProps` properties depending on whether your prop is [serializable](https://react.dev/reference/rsc/use-client#serializable-types), and whether your component is a Server or Client Component.
```ts
import { buildConfig } from 'payload'
const config = buildConfig({
// ...
admin: { // highlight-line
components: {
logout: {
Button: {
path: '/src/components/Logout#MyComponent',
clientProps: {
myCustomProp: 'Hello, World!' // highlight-line
},
}
}
}
},
})
```
Here is how your component might receive this prop:
```tsx
import React from 'react'
import { Link } from '@payloadcms/ui'
export function MyComponent({ myCustomProp }: { myCustomProp: string }) {
return (
<Link href="/admin/logout">{myCustomProp}</Link>
)
}
```
### Client Components
All Custom Components in Payload are [React Server Components](https://react.dev/reference/rsc/server-components) by default, however, it is possible to use [Client Components](https://react.dev/reference/rsc/use-client) by simply adding the `'use client'` directive at the top of your file. Payload will automatically detect and remove all [non-serializable](https://react.dev/reference/rsc/use-client#serializable-types) default props before rendering your component.
```tsx
// highlight-start
'use client'
// highlight-end
import React, { useState } from 'react'
export function MyClientComponent() {
const [count, setCount] = useState(0)
return (
<button onClick={() => setCount(count + 1)}>
Clicked {count} times
</button>
)
}
```
<Banner type="warning">
**Reminder:**
Client Components cannot be passed [non-serializable props](https://react.dev/reference/rsc/use-client#serializable-types). If you are rendering your Client Component _from within_ a Server Component, ensure that its props are serializable.
</Banner>
### Accessing the Payload Config
From any Server Component, the [Payload Config](../configuration/overview) can be accessed directly from the `payload` prop:
```tsx
import React from 'react'
export default async function MyServerComponent({
payload: {
config // highlight-line
}
}) {
return (
<Link href={config.serverURL}>
Go Home
</Link>
)
}
```
But, the Payload Config is [non-serializable](https://react.dev/reference/rsc/use-client#serializable-types) by design. It is full of custom validation functions and more. This means that the Payload Config, in its entirety, cannot be passed directly to Client Components.
For this reason, Payload creates a Client Config and passes it into the Config Provider. This is a serializable version of the Payload Config that can be accessed from any Client Component via the [`useConfig`](../admin/hooks#useconfig) hook:
```tsx
'use client'
import React from 'react'
import { useConfig } from '@payloadcms/ui'
export function MyClientComponent() {
// highlight-start
const { config: { serverURL } } = useConfig()
// highlight-end
return (
<Link href={serverURL}>
Go Home
</Link>
)
}
```
<Banner type="success">
See [Using Hooks](#using-hooks) for more details.
</Banner>
Similarly, all [Field Components](../fields/overview#custom-components) automatically receive their respective Field Config through props.
Within Server Components, this prop is named `field`:
```tsx
import React from 'react'
import type { TextFieldServerComponent } from 'payload'
export const MyClientFieldComponent: TextFieldServerComponent = ({ field: { name } }) => {
return (
<p>
{`This field's name is ${name}`}
</p>
)
}
```
Within Client Components, this prop is named `clientField` because its non-serializable props have been removed:
```tsx
'use client'
import React from 'react'
import type { TextFieldClientComponent } from 'payload'
export const MyClientFieldComponent: TextFieldClientComponent = ({ clientField: { name } }) => {
return (
<p>
{`This field's name is ${name}`}
</p>
)
}
```
### Getting the Current Language
All Custom Components can support language translations to be consistent with Payload's [I18n](../configuration/i18n). This will allow your Custom Components to display the correct language based on the user's preferences.
To do this, first add your translation resources to the [I18n Config](../configuration/i18n). Then from any Server Component, you can translate resources using the `getTranslation` function from `@payloadcms/translations`.
All Server Components automatically receive the `i18n` object as a prop by default:
```tsx
import React from 'react'
import { getTranslation } from '@payloadcms/translations'
export default async function MyServerComponent({ i18n }) {
const translatedTitle = getTranslation(myTranslation, i18n) // highlight-line
return (
<p>{translatedTitle}</p>
)
}
```
The best way to do this within a Client Component is to import the `useTranslation` hook from `@payloadcms/ui`:
```tsx
'use client'
import React from 'react'
import { useTranslation } from '@payloadcms/ui'
export function MyClientComponent() {
const { t, i18n } = useTranslation() // highlight-line
return (
<ul>
<li>{t('namespace1:key', { variable: 'value' })}</li>
<li>{t('namespace2:key', { variable: 'value' })}</li>
<li>{i18n.language}</li>
</ul>
)
}
```
<Banner type="success">
See the [Hooks](../admin/hooks) documentation for a full list of available hooks.
</Banner>
### Getting the Current Locale
All [Custom Views](./custom-views) can support multiple locales to be consistent with Payload's [Localization](../configuration/localization) feature. This can be used to scope API requests, etc.
All Server Components automatically receive the `locale` object as a prop by default:
```tsx
import React from 'react'
export default async function MyServerComponent({ payload, locale }) {
const localizedPage = await payload.findByID({
collection: 'pages',
id: '123',
locale,
})
return (
<p>{localizedPage.title}</p>
)
}
```
The best way to do this within a Client Component is to import the `useLocale` hook from `@payloadcms/ui`:
```tsx
'use client'
import React from 'react'
import { useLocale } from '@payloadcms/ui'
function Greeting() {
const locale = useLocale() // highlight-line
const trans = {
en: 'Hello',
es: 'Hola',
}
return (
<span>{trans[locale.code]}</span>
)
}
```
<Banner type="success">
See the [Hooks](../admin/hooks) documentation for a full list of available hooks.
</Banner>
### Using Hooks
To make it easier to [build your Custom Components](#building-custom-components), you can use [Payload's built-in React Hooks](../admin/hooks) in any Client Component. For example, you might want to interact with one of Payload's many React Contexts. To do this, you can use one of the many hooks available depending on your needs.
```tsx
'use client'
import React from 'react'
import { useDocumentInfo } from '@payloadcms/ui'
export function MyClientComponent() {
const { slug } = useDocumentInfo() // highlight-line
return (
<p>{`Entity slug: ${slug}`}</p>
)
}
```
<Banner type="success">
See the [Hooks](../admin/hooks) documentation for a full list of available hooks.
</Banner>
### Adding Styles
Payload has a robust [CSS Library](../admin/customizing-css) that you can use to style your Custom Components to match to Payload's built-in styling. This will ensure that your Custom Components integrate well into the existing design system. This will make it so they automatically adapt to any theme changes that might occur.
To apply custom styles, simply import your own `.css` or `.scss` file into your Custom Component:
```tsx
import './index.scss'
export function MyComponent() {
return (
<div className="my-component">
My Custom Component
</div>
)
}
```
Then to colorize your Custom Component's background, for example, you can use the following CSS:
```scss
.my-component {
background-color: var(--theme-elevation-500);
}
```
Payload also exports its [SCSS](https://sass-lang.com) library for reuse which includes mixins, etc. To use this, simply import it as follows into your `.scss` file:
```scss
@import '~@payloadcms/ui/scss';
.my-component {
@include mid-break {
background-color: var(--theme-elevation-900);
}
}
```
<Banner type="success">
**Note:**
You can also drill into Payload's own component styles, or easily apply global, app-wide CSS. More on that [here](../admin/customizing-css).
</Banner>

View File

@@ -1,485 +0,0 @@
---
title: Root Components
label: Root Components
order: 20
desc:
keywords: admin, components, custom, documentation, Content Management System, cms, headless, javascript, node, react, nextjs
---
Root Components are those that affect the [Admin Panel](../admin/overview) at a high-level, such as the logo or the main nav. You can swap out these components with your own [Custom Components](./overview) to create a completely custom look and feel.
When combined with [Custom CSS](../admin/customizing-css), you can create a truly unique experience for your users, such as white-labeling the Admin Panel to match your brand.
To override Root Components, use the `admin.components` property at the root of your [Payload Config](../configuration/overview):
```ts
import { buildConfig } from 'payload'
export default buildConfig({
// ...
admin: {
// highlight-start
components: {
// ...
},
// highlight-end
},
})
```
## Config Options
The following options are available:
| Path | Description |
|-----------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `actions` | An array of Custom Components to be rendered _within_ the header of the Admin Panel, providing additional interactivity and functionality. [More details](#actions). |
| `afterDashboard` | An array of Custom Components to inject into the built-in Dashboard, _after_ the default dashboard contents. [More details](#afterdashboard). |
| `afterLogin` | An array of Custom Components to inject into the built-in Login, _after_ the default login form. [More details](#afterlogin). |
| `afterNavLinks` | An array of Custom Components to inject into the built-in Nav, _after_ the links. [More details](#afternavlinks). |
| `beforeDashboard` | An array of Custom Components to inject into the built-in Dashboard, _before_ the default dashboard contents. [More details](#beforedashboard). |
| `beforeLogin` | An array of Custom Components to inject into the built-in Login, _before_ the default login form. [More details](#beforelogin). |
| `beforeNavLinks` | An array of Custom Components to inject into the built-in Nav, _before_ the links themselves. [More details](#beforenavlinks). |
| `graphics.Icon` | The simplified logo used in contexts like the the `Nav` component. [More details](#graphicsicon). |
| `graphics.Logo` | The full logo used in contexts like the `Login` view. [More details](#graphicslogo). |
| `header` | An array of Custom Components to be injected above the Payload header. [More details](#header). |
| `logout.Button` | The button displayed in the sidebar that logs the user out. [More details](#logoutbutton). |
| `Nav` | Contains the sidebar / mobile menu in its entirety. [More details](#nav). |
| `providers` | Custom [React Context](https://react.dev/learn/scaling-up-with-reducer-and-context) providers that will wrap the entire Admin Panel. [More details](./custom-providers). |
| `views` | Override or create new views within the Admin Panel. [More details](./custom-views). |
_For details on how to build Custom Components, see [Building Custom Components](./overview#building-custom-components)._
<Banner type="success">
**Note:**
You can also use set [Collection Components](../configuration/collections#custom-components) and [Global Components](../configuration/globals#custom-components) in their respective configs.
</Banner>
## Components
### actions
Actions are rendered within the header of the Admin Panel. Actions are typically used to display buttons that add additional interactivity and functionality, although they can be anything you'd like.
To add an action, use the `actions` property in your `admin.components` config:
```ts
import { buildConfig } from 'payload'
export default buildConfig({
// ...
admin: {
// highlight-start
components: {
actions: [
'/path/to/your/component',
],
},
// highlight-end
},
})
```
Here is an example of a simple Action component:
```tsx
export default function MyCustomAction() {
return (
<button onClick={() => alert('Hello, world!')}>
This is a custom action component
</button>
)
}
```
<Banner type="success">
**Note:**
You can also use add Actions to the [Edit View](./edit-view) and [List View](./list-view) in their respective configs.
</Banner>
### beforeDashboard
The `beforeDashboard` property allows you to inject Custom Components into the built-in Dashboard, before the default dashboard contents.
To add `beforeDashboard` components, use the `admin.components.beforeDashboard` property in your Payload Config:
```ts
import { buildConfig } from 'payload'
export default buildConfig({
// ...
admin: {
// highlight-start
components: {
beforeDashboard: [
'/path/to/your/component',
],
},
// highlight-end
},
})
```
Here is an example of a simple `beforeDashboard` component:
```tsx
export default function MyBeforeDashboardComponent() {
return (
<div>
This is a custom component injected before the Dashboard.
</div>
)
}
```
### afterDashboard
Similar to `beforeDashboard`, the `afterDashboard` property allows you to inject Custom Components into the built-in Dashboard, _after_ the default dashboard contents.
To add `afterDashboard` components, use the `admin.components.afterDashboard` property in your Payload Config:
```ts
import { buildConfig } from 'payload'
export default buildConfig({
// ...
admin: {
// highlight-start
components: {
afterDashboard: [
'/path/to/your/component',
],
},
// highlight-end
},
})
```
Here is an example of a simple `afterDashboard` component:
```tsx
export default function MyAfterDashboardComponent() {
return (
<div>
This is a custom component injected after the Dashboard.
</div>
)
}
```
### beforeLogin
The `beforeLogin` property allows you to inject Custom Components into the built-in Login view, _before_ the default login form.
To add `beforeLogin` components, use the `admin.components.beforeLogin` property in your Payload Config:
```ts
import { buildConfig } from 'payload'
export default buildConfig({
// ...
admin: {
// highlight-start
components: {
beforeLogin: [
'/path/to/your/component',
],
},
// highlight-end
},
})
```
Here is an example of a simple `beforeLogin` component:
```tsx
export default function MyBeforeLoginComponent() {
return (
<div>
This is a custom component injected before the Login form.
</div>
)
}
```
### afterLogin
Similar to `beforeLogin`, the `afterLogin` property allows you to inject Custom Components into the built-in Login view, _after_ the default login form.
To add `afterLogin` components, use the `admin.components.afterLogin` property in your Payload Config:
```ts
import { buildConfig } from 'payload'
export default buildConfig({
// ...
admin: {
// highlight-start
components: {
afterLogin: [
'/path/to/your/component',
],
},
// highlight-end
},
})
```
Here is an example of a simple `afterLogin` component:
```tsx
export default function MyAfterLoginComponent() {
return (
<div>
This is a custom component injected after the Login form.
</div>
)
}
```
### beforeNavLinks
The `beforeNavLinks` property allows you to inject Custom Components into the built-in [Nav Component](#nav), _before_ the nav links themselves.
To add `beforeNavLinks` components, use the `admin.components.beforeNavLinks` property in your Payload Config:
```ts
import { buildConfig } from 'payload'
export default buildConfig({
// ...
admin: {
// highlight-start
components: {
beforeNavLinks: [
'/path/to/your/component',
],
},
// highlight-end
},
})
```
Here is an example of a simple `beforeNavLinks` component:
```tsx
export default function MyBeforeNavLinksComponent() {
return (
<div>
This is a custom component injected before the Nav links.
</div>
)
}
```
### afterNavLinks
Similar to `beforeNavLinks`, the `afterNavLinks` property allows you to inject Custom Components into the built-in Nav, _after_ the nav links.
To add `afterNavLinks` components, use the `admin.components.afterNavLinks` property in your Payload Config:
```ts
import { buildConfig } from 'payload'
export default buildConfig({
// ...
admin: {
// highlight-start
components: {
afterNavLinks: [
'/path/to/your/component',
],
},
// highlight-end
},
})
```
Here is an example of a simple `afterNavLinks` component:
```tsx
export default function MyAfterNavLinksComponent() {
return (
<p>This is a custom component injected after the Nav links.</p>
)
}
```
### Nav
The `Nav` property contains the sidebar / mobile menu in its entirety. Use this property to completely replace the built-in Nav with your own custom navigation.
To add a custom nav, use the `admin.components.Nav` property in your Payload Config:
```ts
import { buildConfig } from 'payload'
export default buildConfig({
// ...
admin: {
// highlight-start
components: {
Nav: '/path/to/your/component',
},
// highlight-end
},
})
```
Here is an example of a simple `Nav` component:
```tsx
import { Link } from '@payloadcms/ui'
export default function MyCustomNav() {
return (
<nav>
<ul>
<li>
<Link href="/dashboard">
Dashboard
</Link>
</li>
</ul>
</nav>
)
}
```
### graphics.Icon
The `Icon` property is the simplified logo used in contexts like the `Nav` component. This is typically a small, square icon that represents your brand.
To add a custom icon, use the `admin.components.graphics.Icon` property in your Payload Config:
```ts
import { buildConfig } from 'payload'
export default buildConfig({
// ...
admin: {
// highlight-start
components: {
graphics: {
Icon: '/path/to/your/component',
},
},
// highlight-end
},
})
```
Here is an example of a simple `Icon` component:
```tsx
export default function MyCustomIcon() {
return (
<img src="/path/to/your/icon.png" alt="My Custom Icon" />
)
}
```
### graphics.Logo
The `Logo` property is the full logo used in contexts like the `Login` view. This is typically a larger, more detailed representation of your brand.
To add a custom logo, use the `admin.components.graphic.Logo` property in your Payload Config:
```ts
import { buildConfig } from 'payload'
export default buildConfig({
// ...
admin: {
// highlight-start
components: {
graphics: {
Logo: '/path/to/your/component',
},
},
// highlight-end
},
})
```
Here is an example of a simple `Logo` component:
```tsx
export default function MyCustomLogo() {
return (
<img src="/path/to/your/logo.png" alt="My Custom Logo" />
)
}
```
### Header
The `Header` property allows you to inject Custom Components above the Payload header.
Examples of a custom header components might include an announcements banner, a notifications bar, or anything else you'd like to display at the top of the Admin Panel in a prominent location.
To add `Header` components, use the `admin.components.header` property in your Payload Config:
```ts
import { buildConfig } from 'payload'
export default buildConfig({
// ...
admin: {
// highlight-start
components: {
Header: [
'/path/to/your/component'
],
},
// highlight-end
},
})
```
Here is an example of a simple `Header` component:
```tsx
export default function MyCustomHeader() {
return (
<header>
<h1>My Custom Header</h1>
</header>
)
}
```
### logout.Button
The `logout.Button` property is the button displayed in the sidebar that should log the user out when clicked.
To add a custom logout button, use the `admin.components.logout.Button` property in your Payload Config:
```ts
import { buildConfig } from 'payload'
export default buildConfig({
// ...
admin: {
// highlight-start
components: {
logout: {
Button: '/path/to/your/component',
}
},
// highlight-end
},
})
```
Here is an example of a simple `logout.Button` component:
```tsx
export default function MyCustomLogoutButton() {
return (
<button onClick={() => alert('Logging out!')}>
Log Out
</button>
)
}
```

View File

@@ -274,5 +274,5 @@ export default buildConfig({
Passing your migrations as shown above will tell Payload, in production only, to execute any migrations that need to be run prior to completing the initialization of Payload. This is ideal for long-running services where Payload will only be initialized at startup.
<Banner type="warning">
**Warning:** if Payload is instructed to run migrations in production, this may slow down serverless cold starts on platforms such as Vercel. Generally, this option should only be used for long-running servers / containers.
Warning - if Payload is instructed to run migrations in production, this may slow down serverless cold starts on platforms such as Vercel. Generally, this option should only be used for long-running servers / containers.
</Banner>

View File

@@ -52,7 +52,7 @@ export default buildConfig({
<Banner type="info">
**Note:**
If you're using `vercelPostgresAdapter` your `process.env.POSTGRES_URL` or `pool.connectionString` points to a local database (e.g hostname has `localhost` or `127.0.0.1`) we use the `pg` module for pooling instead of `@vercel/postgres`. This is because `@vercel/postgres` doesn't work with local databases, if you want to disable that behavior, you can pass `forceUseVercelPostgres: true` to the adapter's args and follow [Vercel guide](https://vercel.com/docs/storage/vercel-postgres/local-development#option-2:-local-postgres-instance-with-docker) for a Docker Neon DB setup.
If you're using `vercelPostgresAdapter` your `process.env.POSTGRES_URL` or `pool.connectionString` points to a local database (e.g hostname has `localhost` or `127.0.0.1`) we use the `pg` module for pooling instead of `@vercel/postgres`. This is because `@vercel/postgres` doesn't work with local databases, if you want to disable that behavior, you can pass `forceUseVercelPostgres: true` to adapter's 'args and follow [Vercel guide](https://vercel.com/docs/storage/vercel-postgres/local-development#option-2:-local-postgres-instance-with-docker) for a Docker Neon DB setup.
</Banner>
## Options

View File

@@ -79,12 +79,12 @@ export const MyArrayField: Field = {
}
```
The Array Field inherits all of the default options from the base [Field Admin Config](./overview#admin-options), plus the following additional options:
The Array Field inherits all of the default options from the base [Field Admin Config](../admin/fields#admin-options), plus the following additional options:
| Option | Description |
| ------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------- |
| **`initCollapsed`** | Set the initial collapsed state |
| **`components.RowLabel`** | React component to be rendered as the label on the array row. [Example](#row-label) |
| **`components.RowLabel`** | React component to be rendered as the label on the array row. [Example](#example-of-a-custom-rowlabel-component) |
| **`isSortable`** | Disable order sorting by setting this value to `false` |
## Example
@@ -125,99 +125,18 @@ export const ExampleCollection: CollectionConfig = {
type: 'text',
},
],
admin: {
components: {
RowLabel: '/path/to/ArrayRowLabel#ArrayRowLabel',
},
},
},
],
}
```
## Custom Components
### Example of a custom RowLabel component
### Field
#### Server Component
```tsx
import type React from 'react'
import { ArrayField } from '@payloadcms/ui'
import type { ArrayFieldServerComponent } from 'payload'
export const CustomArrayFieldServer: ArrayFieldServerComponent = ({
clientField,
path,
schemaPath,
permissions
}) => {
return (
<ArrayField
field={clientField}
path={path}
schemaPath={schemaPath}
permissions={permissions}
/>
)
}
```
#### Client Component
```tsx
'use client'
import React from 'react'
import { ArrayField } from '@payloadcms/ui'
import type { ArrayFieldClientComponent } from 'payload'
export const CustomArrayFieldClient: ArrayFieldClientComponent = (props) => {
return <ArrayField {...props} />
}
```
### Label
#### Server Component
```tsx
import React from 'react'
import { FieldLabel } from '@payloadcms/ui'
import type { ArrayFieldLabelServerComponent } from 'payload'
export const CustomArrayFieldLabelServer: ArrayFieldLabelServerComponent = ({
clientField,
path,
}) => {
return (
<FieldLabel
label={clientField?.label || clientField?.name}
path={path}
required={clientField?.required}
/>
)
}
```
#### Client Component
```tsx
'use client'
import type { ArrayFieldLabelClientComponent } from 'payload'
import { FieldLabel } from '@payloadcms/ui'
import React from 'react'
export const CustomArrayFieldLabelClient: ArrayFieldLabelClientComponent = ({
field,
path
}) => {
return (
<FieldLabel
label={field?.label || field?.name}
path={path}
required={field?.required}
/>
)
}
```
### Row Label
```tsx
'use client'

View File

@@ -6,7 +6,7 @@ desc: The Blocks Field is a great layout build and can be used to construct any
keywords: blocks, fields, config, configuration, documentation, Content Management System, cms, headless, javascript, node, react, nextjs
---
The Blocks Field is **incredibly powerful**, storing an array of objects based on the fields that you define, where each item in the array is a "block" with its own unique schema.
The Blocks Field is **incredibly powerful** storing an array of objects based on the fields that your define, where each item in the array is a "block" with its own unique schema.
Blocks are a great way to create a flexible content model that can be used to build a wide variety of content types, including:
@@ -64,7 +64,7 @@ _* An asterisk denotes that a property is required._
## Admin Options
To customize the appearance and behavior of the Blocks Field in the [Admin Panel](../admin/overview), you can use the `admin` option:
The customize the appearance and behavior of the Blocks Field in the [Admin Panel](../admin/overview), you can use the `admin` option:
```ts
import type { Field } from 'payload'
@@ -77,7 +77,7 @@ export const MyBlocksField: Field = {
}
```
The Blocks Field inherits all of the default options from the base [Field Admin Config](./overview#admin-options), plus the following additional options:
The Blocks Field inherits all of the default options from the base [Field Admin Config](../admin/fields#admin-options), plus the following additional options:
| Option | Description |
| ------------------- | ---------------------------------- |
@@ -209,156 +209,6 @@ export const ExampleCollection: CollectionConfig = {
}
```
## Custom Components
### Field
#### Server Component
```tsx
import type React from 'react'
import { BlocksField } from '@payloadcms/ui'
import type { BlocksFieldServerComponent } from 'payload'
export const CustomBlocksFieldServer: BlocksFieldServerComponent = ({
clientField,
path,
schemaPath,
permissions
}) => {
return (
<BlocksField field={clientField}
path={path}
schemaPath={schemaPath}
permissions={permissions}
/>
)
}
```
#### Client Component
```tsx
'use client'
import React from 'react'
import { BlocksField } from '@payloadcms/ui'
import type { BlocksFieldClientComponent } from 'payload'
export const CustomBlocksFieldClient: BlocksFieldClientComponent = (props) => {
return <BlocksField {...props} />
}
```
### Label
#### Server Component
```tsx
import React from 'react'
import { FieldLabel } from '@payloadcms/ui'
import type { BlocksFieldLabelServerComponent } from 'payload'
export const CustomBlocksFieldLabelServer: BlocksFieldLabelServerComponent = ({
clientField,
path,
}) => {
return (
<FieldLabel
label={clientField?.label || clientField?.name}
path={path}
required={clientField?.required}
/>
)
}
```
#### Client Component
```tsx
'use client'
import React from 'react'
import { FieldLabel } from '@payloadcms/ui'
import type { BlocksFieldLabelClientComponent } from 'payload'
export const CustomBlocksFieldLabelClient: BlocksFieldLabelClientComponent = ({
label,
path,
required,
}) => {
return (
<FieldLabel
label={field?.label || field?.name}
path={path}
required={field?.required}
/>
)
}
```
## Block References
If you have multiple blocks used in multiple places, your Payload Config can grow in size, potentially sending more data to the client and requiring more processing on the server. However, you can optimize performance by defining each block **once** in your Payload Config and then referencing its slug wherever it's used instead of passing the entire block config.
To do this, define the block in the `blocks` array of the Payload Config. Then, in the Blocks Field, pass the block slug to the `blockReferences` array - leaving the `blocks` array empty for compatibility reasons.
```ts
import { buildConfig } from 'payload'
import { lexicalEditor, BlocksFeature } from '@payloadcms/richtext-lexical'
// Payload Config
const config = buildConfig({
// Define the block once
blocks: [
{
slug: 'TextBlock',
fields: [
{
name: 'text',
type: 'text',
},
],
},
],
collections: [
{
slug: 'collection1',
fields: [
{
name: 'content',
type: 'blocks',
// Reference the block by slug
blockReferences: ['TextBlock'],
blocks: [], // Required to be empty, for compatibility reasons
},
],
},
{
slug: 'collection2',
fields: [
{
name: 'editor',
type: 'richText',
editor: lexicalEditor({
BlocksFeature({
// Same reference can be reused anywhere, even in the lexical editor, without incurred performance hit
blocks: ['TextBlock'],
})
})
},
],
},
],
})
```
<Banner type="warning">
**Reminder:**
Blocks referenced in the `blockReferences` array are treated as isolated from the collection / global config. This has the following implications:
1. The block config cannot be modified or extended in the collection config. It will be identical everywhere it's referenced.
2. Access control for blocks referenced in the `blockReferences` are run only once - data from the collection will not be available in the block's access control.
</Banner>
## TypeScript
As you build your own Block configs, you might want to store them in separate files but retain typing accordingly. To do so, you can import and use Payload's `Block` type:

View File

@@ -41,7 +41,7 @@ export const MyCheckboxField: Field = {
| **`defaultValue`** | Provide data to be used for this field's default value, will default to false if field is also `required`. [More](/docs/fields/overview#default-values) |
| **`localized`** | Enable localization for this field. Requires [localization to be enabled](/docs/configuration/localization) in the Base config. |
| **`required`** | Require this field to have a value. |
| **`admin`** | Admin-specific configuration. [More details](./overview#admin-options). |
| **`admin`** | Admin-specific configuration. [More details](../admin/fields#admin-options). |
| **`custom`** | Extension point for adding custom data (e.g. for plugins) |
| **`typescriptSchema`** | Override field type generation with providing a JSON schema |
| **`virtual`** | Provide `true` to disable field in the database. See [Virtual Fields](https://payloadcms.com/blog/learn-how-virtual-fields-can-help-solve-common-cms-challenges) |
@@ -67,90 +67,3 @@ export const ExampleCollection: CollectionConfig = {
],
}
```
## Custom Components
### Field
#### Server Component
```tsx
import type React from 'react'
import { CheckboxField } from '@payloadcms/ui'
import type { CheckboxFieldServerComponent } from 'payload'
export const CustomCheckboxFieldServer: CheckboxFieldServerComponent = ({
clientField,
path,
schemaPath,
permissions,
}) => {
return (
<CheckboxField
field={clientField}
path={path}
schemaPath={schemaPath}
permissions={permissions}
/>
)
}
```
#### Client Component
```tsx
'use client'
import React from 'react'
import { CheckboxField } from '@payloadcms/ui'
import type { CheckboxFieldClientComponent } from 'payload'
export const CustomCheckboxFieldClient: CheckboxFieldClientComponent = (props) => {
return <CheckboxField {...props} />
}
```
### Label
#### Server Component
```tsx
import React from 'react'
import { FieldLabel } from '@payloadcms/ui'
import type { CheckboxFieldLabelServerComponent } from 'payload'
export const CustomCheckboxFieldLabelServer: CheckboxFieldLabelServerComponent = ({
clientField,
path,
}) => {
return (
<FieldLabel
label={clientField?.label || clientField?.name}
path={path}
required={clientField?.required}
/>
)
}
```
#### Client Component
```tsx
'use client'
import React from 'react'
import { FieldLabel } from '@payloadcms/ui'
import type { CheckboxFieldLabelClientComponent } from 'payload'
export const CustomCheckboxFieldLabelClient: CheckboxFieldLabelClientComponent = ({
label,
path,
required,
}) => {
return (
<FieldLabel
label={field?.label || field?.name}
path={path}
required={field?.required}
/>
)
}
```

View File

@@ -54,7 +54,7 @@ _* An asterisk denotes that a property is required._
## Admin Options
To customize the appearance and behavior of the Code Field in the [Admin Panel](../admin/overview), you can use the `admin` option:
The customize the appearance and behavior of the Code Field in the [Admin Panel](../admin/overview), you can use the `admin` option:
```ts
import type { Field } from 'payload'
@@ -67,7 +67,7 @@ export const MyCodeField: Field = {
}
```
The Code Field inherits all of the default options from the base [Field Admin Config](./overview#admin-options), plus the following additional options:
The Code Field inherits all of the default options from the base [Field Admin Config](../admin/fields#admin-options), plus the following additional options:
| Option | Description |
| ------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
@@ -95,85 +95,3 @@ export const ExampleCollection: CollectionConfig = {
],
}
```
## Custom Components
### Field
#### Server Component
```tsx
import type React from 'react'
import { CodeField } from '@payloadcms/ui'
import type { CodeFieldServerComponent } from 'payload'
export const CustomCodeFieldServer: CodeFieldServerComponent = ({
clientField,
path,
schemaPath,
permissions,
}) => {
return (
<CodeField field={clientField} path={path} schemaPath={schemaPath} permissions={permissions} />
)
}
```
#### Client Component
```tsx
'use client'
import React from 'react'
import { CodeField } from '@payloadcms/ui'
import type { CodeFieldClientComponent } from 'payload'
export const CustomCodeFieldClient: CodeFieldClientComponent = (props) => {
return <CodeField {...props} />
}
```
### Label
#### Server Component
```tsx
import React from 'react'
import { FieldLabel } from '@payloadcms/ui'
import type { CodeFieldLabelServerComponent } from 'payload'
export const CustomCodeFieldLabelServer: CodeFieldLabelServerComponent = ({
clientField,
path,
}) => {
return (
<FieldLabel
label={clientField?.label || clientField?.name}
path={path}
required={clientField?.required}
/>
)
}
```
#### Client Component
```tsx
'use client'
import React from 'react'
import { FieldLabel } from '@payloadcms/ui'
import type { CodeFieldLabelClientComponent } from 'payload'
export const CustomCodeFieldLabelClient: CodeFieldLabelClientComponent = ({
field,
path,
}) => {
return (
<FieldLabel
label={field?.label || field?.name}
path={path}
required={field?.required}
/>
)
}
```

View File

@@ -44,7 +44,7 @@ _* An asterisk denotes that a property is required._
## Admin Options
To customize the appearance and behavior of the Collapsible Field in the [Admin Panel](../admin/overview), you can use the `admin` option:
The customize the appearance and behavior of the Collapsible Field in the [Admin Panel](../admin/overview), you can use the `admin` option:
```ts
import type { Field } from 'payload'
@@ -57,7 +57,7 @@ export const MyCollapsibleField: Field = {
}
```
The Collapsible Field inherits all of the default options from the base [Field Admin Config](./overview#admin-options), plus the following additional options:
The Collapsible Field inherits all of the default options from the base [Field Admin Config](../admin/fields#admin-options), plus the following additional options:
| Option | Description |
| ------------------- | ------------------------------- |

View File

@@ -43,7 +43,6 @@ export const MyDateField: Field = {
| **`required`** | Require this field to have a value. |
| **`admin`** | Admin-specific configuration. [More details](#admin-options). |
| **`custom`** | Extension point for adding custom data (e.g. for plugins) |
| **`timezone`** * | Set to `true` to enable timezone selection on this field. [More details](#timezones). |
| **`typescriptSchema`** | Override field type generation with providing a JSON schema |
| **`virtual`** | Provide `true` to disable field in the database. See [Virtual Fields](https://payloadcms.com/blog/learn-how-virtual-fields-can-help-solve-common-cms-challenges) |
@@ -51,7 +50,7 @@ _* An asterisk denotes that a property is required._
## Admin Options
To customize the appearance and behavior of the Date Field in the [Admin Panel](../admin/overview), you can use the `admin` option:
The customize the appearance and behavior of the Date Field in the [Admin Panel](../admin/overview), you can use the `admin` option:
```ts
import type { Field } from 'payload'
@@ -64,7 +63,7 @@ export const MyDateField: Field = {
}
```
The Date Field inherits all of the default options from the base [Field Admin Config](./overview#admin-options), plus the following additional options:
The Date Field inherits all of the default options from the base [Field Admin Config](../admin/fields#admin-options), plus the following additional options:
| Property | Description |
| ------------------------------ | -------------------------------------------------------------------------------------------------------------------------------------- |
@@ -136,112 +135,3 @@ export const ExampleCollection: CollectionConfig = {
],
}
```
## Custom Components
### Field
#### Server Component
```tsx
import type React from 'react'
import { DateTimeField } from '@payloadcms/ui'
import type { DateFieldServerComponent } from 'payload'
export const CustomDateFieldServer: DateFieldServerComponent = ({
clientField,
path,
schemaPath,
permissions,
}) => {
return (
<DateTimeField
field={clientField}
path={path}
schemaPath={schemaPath}
permissions={permissions}
/>
)
}
```
#### Client Component
```tsx
'use client'
import React from 'react'
import { DateTimeField } from '@payloadcms/ui'
import type { DateFieldClientComponent } from 'payload'
export const CustomDateFieldClient: DateFieldClientComponent = (props) => {
return <DateTimeField {...props} />
}
```
### Label
#### Server Component
```tsx
import React from 'react'
import { FieldLabel } from '@payloadcms/ui'
import type { DateFieldLabelServerComponent } from 'payload'
export const CustomDateFieldLabelServer: DateFieldLabelServerComponent = ({
clientField,
path,
}) => {
return (
<FieldLabel
label={clientField?.label || clientField?.name}
path={path}
required={clientField?.required}
/>
)
}
```
#### Client Component
```tsx
'use client'
import React from 'react'
import { FieldLabel } from '@payloadcms/ui'
import type { DateFieldLabelClientComponent } from 'payload'
export const CustomDateFieldLabelClient: DateFieldLabelClientComponent = ({
field,
path,
}) => {
return (
<FieldLabel
label={field?.label || field?.name}
path={path}
required={field?.required}
/>
)
}
```
## Timezones
To enable timezone selection on a Date field, set the `timezone` property to `true`:
```ts
{
name: 'date',
type: 'date',
timezone: true,
}
```
This will add a dropdown to the date picker that allows users to select a timezone. The selected timezone will be saved in the database along with the date in a new column named `date_tz`.
You can customise the available list of timezones in the [global admin config](../admin/overview#timezones).
<Banner type="info">
**Good to know:**
The date itself will be stored in UTC so it's up to you to handle the conversion to the user's timezone when displaying the date in your frontend.
Dates without a specific time are normalised to 12:00 in the selected timezone.
</Banner>

View File

@@ -51,7 +51,7 @@ _* An asterisk denotes that a property is required._
## Admin Options
To customize the appearance and behavior of the Email Field in the [Admin Panel](../admin/overview), you can use the `admin` option:
The customize the appearance and behavior of the Email Field in the [Admin Panel](../admin/overview), you can use the `admin` option:
```ts
import type { Field } from 'payload'
@@ -64,7 +64,7 @@ export const MyEmailField: Field = {
}
```
The Email Field inherits all of the default options from the base [Field Admin Config](./overview#admin-options), plus the following additional options:
The Email Field inherits all of the default options from the base [Field Admin Config](../admin/fields#admin-options), plus the following additional options:
| Property | Description |
| ------------------------------ | -------------------------------------------------------------------------------------------------------------------------------------- |
@@ -90,83 +90,3 @@ export const ExampleCollection: CollectionConfig = {
],
}
```
## Custom Components
### Field
#### Server Component
```tsx
import type React from 'react'
import { EmailField } from '@payloadcms/ui'
import type { EmailFieldServerComponent } from 'payload'
export const CustomEmailFieldServer: EmailFieldServerComponent = ({
clientField,
path,
schemaPath,
permissions,
}) => {
return (
<EmailField field={clientField} path={path} schemaPath={schemaPath} permissions={permissions} />
)
}
```
#### Client Component
```tsx
'use client'
import React from 'react'
import { EmailField } from '@payloadcms/ui'
import type { EmailFieldClientComponent } from 'payload'
export const CustomEmailFieldClient: EmailFieldClientComponent = (props) => {
return <EmailField {...props} />
}
```
### Label
#### Server Component
```tsx
import React from 'react'
import { FieldLabel } from '@payloadcms/ui'
import type { EmailFieldLabelServerComponent } from 'payload'
export const CustomEmailFieldLabelServer: EmailFieldLabelServerComponent = ({
clientField,
path,
}) => {
return (
<FieldLabel
label={clientField?.label || clientField?.name}
path={path}
required={clientField?.required}
/>
)
}
```
#### Client Component
```tsx
'use client'
import React from 'react'
import { FieldLabel } from '@payloadcms/ui'
import type { EmailFieldLabelClientComponent } from 'payload'
export const CustomEmailFieldLabelClient: EmailFieldLabelClientComponent = ({
field,
path,
}) => {
return (
<FieldLabel
label={field?.label || field?.name}
path={path}
required={field?.required}
/>
)}
```

View File

@@ -55,7 +55,7 @@ _* An asterisk denotes that a property is required._
## Admin Options
To customize the appearance and behavior of the Group Field in the [Admin Panel](../admin/overview), you can use the `admin` option:
The customize the appearance and behavior of the Group Field in the [Admin Panel](../admin/overview), you can use the `admin` option:
```ts
import type { Field } from 'payload'
@@ -68,7 +68,7 @@ export const MyGroupField: Field = {
}
```
The Group Field inherits all of the default options from the base [Field Admin Config](./overview#admin-options), plus the following additional options:
The Group Field inherits all of the default options from the base [Field Admin Config](../admin/fields#admin-options), plus the following additional options:
| Option | Description |
| ------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |

View File

@@ -121,22 +121,22 @@ powerful Admin UI.
## Config Options
| Option | Description |
| ---------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **`name`** * | To be used as the property name when retrieved from the database. [More](./overview#field-names) |
| **`collection`** * | The `slug`s having the relationship field or an array of collection slugs. |
| **`on`** * | The name of the relationship or upload field that relates to the collection document. Use dot notation for nested paths, like 'myGroup.relationName'. If `collection` is an array, this field must exist for all specified collections |
| **`where`** | A `Where` query to hide related documents from appearing. Will be merged with any `where` specified in the request. |
| **`maxDepth`** | Default is 1, Sets a maximum population depth for this field, regardless of the remaining depth when this field is reached. [Max Depth](../queries/depth#max-depth). |
| **`label`** | Text used as a field label in the Admin Panel or an object with keys for each language. |
| **`hooks`** | Provide Field Hooks to control logic for this field. [More details](../hooks/fields). |
| **`access`** | Provide Field Access Control to denote what users can see and do with this field's data. [More details](../access-control/fields). |
| **`defaultLimit`** | The number of documents to return. Set to 0 to return all related documents. |
| **`defaultSort`** | The field name used to specify the order the joined documents are returned. |
| **`admin`** | Admin-specific configuration. [More details](#admin-config-options). |
| **`custom`** | Extension point for adding custom data (e.g. for plugins). |
| **`typescriptSchema`** | Override field type generation with providing a JSON schema. |
| **`graphQL`** | Custom graphQL configuration for the field. [More details](/docs/graphql/overview#field-complexity) |
| Option | Description |
|------------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| **`name`** * | To be used as the property name when retrieved from the database. [More](/docs/fields/overview#field-names) |
| **`collection`** * | The `slug`s having the relationship field. |
| **`on`** * | The name of the relationship or upload field that relates to the collection document. Use dot notation for nested paths, like 'myGroup.relationName'. |
| **`where`** | A `Where` query to hide related documents from appearing. Will be merged with any `where` specified in the request. |
| **`maxDepth`** | Default is 1, Sets a maximum population depth for this field, regardless of the remaining depth when this field is reached. [Max Depth](/docs/getting-started/concepts#field-level-max-depth). |
| **`label`** | Text used as a field label in the Admin Panel or an object with keys for each language. |
| **`hooks`** | Provide Field Hooks to control logic for this field. [More details](../hooks/fields). |
| **`access`** | Provide Field Access Control to denote what users can see and do with this field's data. [More details](../access-control/fields). |
| **`defaultLimit`** | The number of documents to return. Set to 0 to return all related documents. |
| **`defaultSort`** | The field name used to specify the order the joined documents are returned. |
| **`admin`** | Admin-specific configuration. [More details](#admin-config-options). |
| **`custom`** | Extension point for adding custom data (e.g. for plugins). |
| **`typescriptSchema`** | Override field type generation with providing a JSON schema. |
| **`graphQL`** | Custom graphQL configuration for the field. [More details](/docs/graphql/overview#field-complexity) |
_* An asterisk denotes that a property is required._
@@ -149,7 +149,7 @@ You can control the user experience of the join field using the `admin` config p
|------------------------|---------------------------------------------------------------------------------------------------------------------------|
| **`defaultColumns`** | Array of field names that correspond to which columns to show in the relationship table. Default is the collection config. |
| **`allowCreate`** | Set to `false` to remove the controls for making new related documents from this field. |
| **`components.Label`** | Override the default Label of the Field Component. [More details](./overview#label) |
| **`components.Label`** | Override the default Label of the Field Component. [More details](../admin/fields#label) |
## Join Field Data
@@ -177,35 +177,6 @@ object with:
}
```
## Join Field Data (polymorphic)
When a document is returned that for a polymorphic Join field (with `collection` as an array) is populated with related documents. The structure returned is an
object with:
- `docs` an array of `relationTo` - the collection slug of the document and `value` - the document itself or the ID if the depth is reached
- `hasNextPage` a boolean indicating if there are additional documents
```json
{
"id": "66e3431a3f23e684075aae9c",
"relatedPosts": {
"docs": [
{
"relationTo": "posts",
"value": {
"id": "66e3431a3f23e684075aaeb9",
// other fields...
"category": "66e3431a3f23e684075aae9c"
}
}
// { ... }
],
"hasNextPage": false
}
// other fields...
}
```
## Query Options
The Join Field supports custom queries to filter, sort, and limit the related documents that will be returned. In
@@ -227,8 +198,7 @@ These can be applied to the local API, GraphQL, and REST API.
By adding `joins` to the local API you can customize the request for each join field by the `name` of the field.
```js
const result = await payload.find({
collection: 'categories',
const result = await db.findOne('categories', {
where: {
title: {
equals: 'My Category'
@@ -248,25 +218,6 @@ const result = await payload.find({
})
```
<Banner type="warning">
Currently, `Where` query support on joined documents for join fields with an array of `collection` is limited and not supported for fields inside arrays and blocks.
</Banner>
<Banner type="warning">
Currently, querying by the Join Field itself is not supported, meaning:
```ts
payload.find({
collection: 'categories',
where: {
'relatedPosts.title': { // relatedPosts is a join field
equals: "post"
}
}
})
```
does not work yet.
</Banner>
### Rest API
The rest API supports the same query options as the local API. You can use the `joins` query parameter to customize the

View File

@@ -53,7 +53,7 @@ _* An asterisk denotes that a property is required._
## Admin Options
To customize the appearance and behavior of the JSON Field in the [Admin Panel](../admin/overview), you can use the `admin` option:
The customize the appearance and behavior of the JSON Field in the [Admin Panel](../admin/overview), you can use the `admin` option:
```ts
import type { Field } from 'payload'
@@ -66,7 +66,7 @@ export const MyJSONField: Field = {
}
```
The JSON Field inherits all of the default options from the base [Field Admin Config](./overview#admin-options), plus the following additional options:
The JSON Field inherits all of the default options from the base [Field Admin Config](../admin/fields#admin-options), plus the following additional options:
| Option | Description |
| ------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------- |
@@ -154,89 +154,3 @@ export const ExampleCollection: CollectionConfig = {
// {"foo": "bar"} or {"foo": "foobar"} - ok
// Attempting to create {"foo": "not-bar"} will throw an error
```
## Custom Components
### Field
#### Server Component
```tsx
import type React from 'react'
import { JSONField } from '@payloadcms/ui'
import type { JSONFieldServerComponent } from 'payload'
export const CustomJSONFieldServer: JSONFieldServerComponent = ({
clientField,
path,
schemaPath,
permissions,
}) => {
return (
<JSONField
field={clientField}
path={path}
schemaPath={schemaPath}
permissions={permissions}
/>
)
}
```
#### Client Component
```tsx
'use client'
import React from 'react'
import { JSONField } from '@payloadcms/ui'
import type { JSONFieldClientComponent } from 'payload'
export const CustomJSONFieldClient: JSONFieldClientComponent = (props) => {
return <JSONField {...props} />
}
```
### Label
#### Server Component
```tsx
import React from 'react'
import { FieldLabel } from '@payloadcms/ui'
import type { JSONFieldLabelServerComponent } from 'payload'
export const CustomJSONFieldLabelServer: JSONFieldLabelServerComponent = ({
clientField,
path,
}) => {
return (
<FieldLabel
label={clientField?.label || clientField?.name}
path={path}
required={clientField?.required}
/>
)
}
```
#### Client Component
```tsx
'use client'
import React from 'react'
import { FieldLabel } from '@payloadcms/ui'
import type { JSONFieldLabelClientComponent } from 'payload'
export const CustomJSONFieldLabelClient: JSONFieldLabelClientComponent = ({
field,
path,
}) => {
return (
<FieldLabel
label={field?.label || field?.name}
path={path}
required={field?.required}
/>
)
}
```

View File

@@ -56,7 +56,7 @@ _* An asterisk denotes that a property is required._
## Admin Options
To customize the appearance and behavior of the Number Field in the [Admin Panel](../admin/overview), you can use the `admin` option:
The customize the appearance and behavior of the Number Field in the [Admin Panel](../admin/overview), you can use the `admin` option:
```ts
import type { Field } from 'payload'
@@ -69,7 +69,7 @@ export const MyNumberField: Field = {
}
```
The Number Field inherits all of the default options from the base [Field Admin Config](./overview#admin-options), plus the following additional options:
The Number Field inherits all of the default options from the base [Field Admin Config](../admin/fields#admin-options), plus the following additional options:
| Property | Description |
| ------------------------------ | -------------------------------------------------------------------------------------------------------------------------------------- |
@@ -98,89 +98,3 @@ export const ExampleCollection: CollectionConfig = {
],
}
```
## Custom Components
### Field
#### Server Component
```tsx
import type React from 'react'
import { NumberField } from '@payloadcms/ui'
import type { NumberFieldServerComponent } from 'payload'
export const CustomNumberFieldServer: NumberFieldServerComponent = ({
clientField,
path,
schemaPath,
permissions,
}) => {
return (
<NumberField
field={clientField}
path={path}
schemaPath={schemaPath}
permissions={permissions}
/>
)
}
```
#### Client Component
```tsx
'use client'
import React from 'react'
import { NumberField } from '@payloadcms/ui'
import type { NumberFieldClientComponent } from 'payload'
export const CustomNumberFieldClient: NumberFieldClientComponent = (props) => {
return <NumberField {...props} />
}
```
### Label
#### Server Component
```tsx
import React from 'react'
import { FieldLabel } from '@payloadcms/ui'
import type { NumberFieldLabelServerComponent } from 'payload'
export const CustomNumberFieldLabelServer: NumberFieldLabelServerComponent = ({
clientField,
path,
}) => {
return (
<FieldLabel
label={clientField?.label || clientField?.name}
path={path}
required={clientField?.required}
/>
)
}
```
#### Client Component
```tsx
'use client'
import React from 'react'
import { FieldLabel } from '@payloadcms/ui'
import type { NumberFieldLabelClientComponent } from 'payload'
export const CustomNumberFieldLabelClient: NumberFieldLabelClientComponent = ({
field,
path,
}) => {
return (
<FieldLabel
label={field?.label || field?.name}
path={path}
required={field?.required}
/>
)
}
```

View File

@@ -1,16 +1,14 @@
---
description: Fields are the building blocks of Payload, find out how to add or remove a field, change field type, add hooks, define Access Control and Validation.
keywords: overview, fields, config, configuration, documentation, Content Management System, cms, headless, javascript, node, react, nextjs
title: Fields Overview
label: Overview
order: 10
title: Fields Overview
desc: Fields are the building blocks of Payload, find out how to add or remove a field, change field type, add hooks, define Access Control and Validation.
keywords: overview, fields, config, configuration, documentation, Content Management System, cms, headless, javascript, node, react, nextjs
---
Fields are the building blocks of Payload. They define the schema of the Documents that will be stored in the [Database](../database/overview), as well as automatically generate the corresponding UI within the [Admin Panel](../admin/overview).
There are many [Field Types](#field-types) to choose from, ranging anywhere from simple text strings to nested arrays and blocks. Most fields save data to the database, while others are strictly presentational. Fields can have [Custom Validations](#validation), [Conditional Logic](./overview#conditional-logic), [Access Control](#field-level-access-control), [Hooks](#field-level-hooks), and so much more.
Fields can be endlessly customized in their appearance and behavior without affecting their underlying data structure. Fields are designed to withstand heavy modification or even complete replacement through the use of [Custom Field Components](#custom-components).
There are many [Field Types](#field-types) to choose from, ranging anywhere from simple text strings to nested arrays and blocks. Most fields save data to the database, while others are strictly presentational. Fields can have [Custom Validations](#validation), [Conditional Logic](../admin/fields#conditional-logic), [Access Control](#field-level-access-control), [Hooks](#field-level-hooks), and so much more.
To configure fields, use the `fields` property in your [Collection](../configuration/collections) or [Global](../configuration/globals) config:
@@ -25,6 +23,10 @@ export const Page: CollectionConfig = {
}
```
<Banner type="success">
You can fully customize the appearance and behavior of all fields within the Admin Panel. [More details](../admin/fields).
</Banner>
## Field Types
Payload provides a wide variety of built-in Field Types, each with its own unique properties and behaviors that determine which values it can accept, how it is presented in the API, and how it will be rendered in the [Admin Panel](../admin/overview).
@@ -48,16 +50,16 @@ export const Page: CollectionConfig = {
```
<Banner type="warning">
**Reminder:** Each field is an object with at least the `type` property. This matches the field to its corresponding Field Type. [More details](#field-options).
**Reminder:**
Each field is an object with at least the `type` property. This matches the field to its corresponding Field Type. [More details](#field-options).
</Banner>
There are three main categories of fields in Payload:
There are two main categories of fields in Payload:
- [Data Fields](#data-fields)
- [Presentational Fields](#presentational-fields)
- [Virtual Fields](#virtual-fields)
To begin writing fields, first determine which [Field Type](#field-types) best supports your application. Then author your field accordingly using the [Field Options](#field-options) for your chosen field type.
To begin writing fields, first determine which [Field Type](#field-types) best supports your application. Then to author your field accordingly using the [Field Options](#field-options) for your chosen field type.
### Data Fields
@@ -90,21 +92,15 @@ Presentational Fields do not store data in the database. Instead, they are used
Here are the available Presentational Fields:
- [Collapsible](../fields/collapsible) - nests fields within a collapsible component
- [Row](../fields/row) - aligns fields horizontally
- [Tabs (Unnamed)](../fields/tabs) - nests fields within a tabbed layout
- [UI](../fields/ui) - blank field for custom UI components
- [Collapsible](/docs/fields/collapsible) - nests fields within a collapsible component
- [Join](/docs/fields/join) - achieves two-way data binding between fields
- [Row](/docs/fields/row) - aligns fields horizontally
- [Tabs (Unnamed)](/docs/fields/tabs) - nests fields within a tabbed layout
- [UI](/docs/fields/ui) - blank field for custom UI components
### Virtual Fields
Virtual fields are used to display data that is not stored in the database. They are useful for displaying computed values that populate within the APi response through hooks, etc.
Here are the available Virtual Fields:
- [Join](../fields/join) - achieves two-way data binding between fields
<Banner type="success">
**Tip:** Don't see a built-in field type that you need? Build it! Using a combination of [Field Validations](#validation) and [Custom Components](../custom-components/overview), you can override the entirety of how a component functions within the [Admin Panel](../admin/overview) to effectively create your own field type.
<Banner type="warning">
**Tip:**
Don't see a Field Type that fits your needs? You can build your own using a [Custom Field Component](../admin/fields#field).
</Banner>
## Field Options
@@ -145,10 +141,10 @@ Payload reserves various field names for internal use. Using reserved field name
The following field names are forbidden and cannot be used:
- `__v`
- `salt`
- `hash`
- `file`
- `__v`
- `salt`
- `hash`
- `file`
### Field-level Hooks
@@ -239,7 +235,8 @@ export const myField: Field = {
```
<Banner type="success">
**Tip:** You can use async `defaultValue` functions to fill fields with data from API requests or Local API using `req.payload`.
**Tip:**
You can use async `defaultValue` functions to fill fields with data from API requests or Local API using `req.payload`.
</Banner>
### Validation
@@ -262,10 +259,10 @@ Custom validation functions should return either `true` or a `string` representi
The following arguments are provided to the `validate` function:
| Argument | Description |
| --- | --- |
| `value` | The value of the field being validated. |
| `ctx` | An object with additional data and context. [More details](#validation-context) |
| Argument | Description |
| -------- | --------------------------------------------------------------------------------------------- |
| `value` | The value of the field being validated. |
| `ctx` | An object with additional data and context. [More details](#validation-context) |
#### Validation Context
@@ -286,14 +283,13 @@ export const MyField: Field = {
The following additional properties are provided in the `ctx` object:
| Property | Description |
| --- | --- |
| `data` | An object containing the full collection or global document currently being edited. |
| `siblingData` | An object containing document data that is scoped to only fields within the same parent of this field. |
| `operation` | Will be `create` or `update` depending on the UI action or API call. |
| `id` | The `id` of the current document being edited. `id` is `undefined` during the `create` operation. |
| `req` | The current HTTP request object. Contains `payload`, `user`, etc. |
| `event` | Either `onChange` or `submit` depending on the current action. Used as a performance opt-in. [More details](#async-field-validations). |
| Property | Description |
| ------------- | ------------------------------------------------------------------------------------------------------------------------ |
| `data` | An object containing the full collection or global document currently being edited. |
| `siblingData` | An object containing document data that is scoped to only fields within the same parent of this field. |
| `operation` | Will be `create` or `update` depending on the UI action or API call. |
| `id` | The `id` of the current document being edited. `id` is `undefined` during the `create` operation. |
| `req` | The current HTTP request object. Contains `payload`, `user`, etc. |
#### Reusing Default Field Validations
@@ -314,37 +310,10 @@ const field: Field = {
}
```
Here is a list of all default field validation functions:
```ts
import {
array,
blocks,
checkbox,
code,
date,
email,
group,
json,
number,
point,
radio,
relationship,
richText,
select,
tabs,
text,
textarea,
upload,
} from 'payload/shared'
```
#### Async Field Validations
Custom validation functions can also be asynchronous depending on your needs. This makes it possible to make requests to external services or perform other miscellaneous asynchronous logic.
When writing async validation functions, it is important to consider the performance implications. Validations are executed on every change to the field, so they should be as lightweight as possible. If you need to perform expensive validations, such as querying the database, consider using the `event` property in the `ctx` object to only run the validation on form submission.
To write asynchronous validation functions, use the `async` keyword to define your function:
```ts
@@ -357,18 +326,10 @@ export const Orders: CollectionConfig = {
name: 'customerNumber',
type: 'text',
// highlight-start
validate: async (val, { event }) => {
if (event === 'onChange') {
return true
}
// only perform expensive validation when the form is submitted
validate: async (val, { operation }) => {
if (operation !== 'create') return true
const response = await fetch(`https://your-api.com/customers/${val}`)
if (response.ok) {
return true
}
if (response.ok) return true
return 'The customer number provided does not match any customers within our records.'
},
// highlight-end
@@ -377,6 +338,24 @@ export const Orders: CollectionConfig = {
}
```
### Admin Options
In addition to each field's base configuration, you can use the `admin` key to specify traits and properties for fields that will only effect how they are _rendered_ within the [Admin Panel](../admin/overview), such as their appearance or behavior.
```ts
import type { Field } from 'payload'
export const MyField: Field = {
type: 'text',
name: 'myField',
admin: { // highlight-line
// ...
}
}
```
For full details on Admin Options, see the [Field Admin Options](../admin/fields) documentation.
## Custom ID Fields
All [Collections](../configuration/collections) automatically generate their own ID field. If needed, you can override this behavior by providing an explicit ID field to your config. This field should either be required or have a hook to generate the ID dynamically.
@@ -399,539 +378,12 @@ export const MyCollection: CollectionConfig = {
```
<Banner type="warning">
**Reminder:** The Custom ID Fields can only be of type [`Number`](./number) or [`Text`](./text). Custom ID fields with type `text` must not contain `/` or `.` characters.
**Reminder:**
The Custom ID Fields can only be of type [`Number`](./number) or [`Text`](./text).
Custom ID fields with type `text` must not contain `/` or `.` characters.
</Banner>
## Admin Options
You can customize the appearance and behavior of fields within the [Admin Panel](../admin/overview) through the `admin` property of any Field Config:
```ts
import type { CollectionConfig } from 'payload'
export const CollectionConfig: CollectionConfig = {
// ...
fields: [
// ...
{
name: 'myField',
type: 'text',
admin: { // highlight-line
// ...
},
}
]
}
```
The following options are available:
| Option | Description |
| --- | --- |
| **`condition`** | Programmatically show / hide fields based on other fields. [More details](#conditional-logic). |
| **`components`** | All Field Components can be swapped out for [Custom Components](../custom-components/overview) that you define. |
| **`description`** | Helper text to display alongside the field to provide more information for the editor. [More details](#description). |
| **`position`** | Specify if the field should be rendered in the sidebar by defining `position: 'sidebar'`. |
| **`width`** | Restrict the width of a field. You can pass any string-based value here, be it pixels, percentages, etc. This property is especially useful when fields are nested within a `Row` type where they can be organized horizontally. |
| **`style`** | [CSS Properties](https://developer.mozilla.org/en-US/docs/Web/CSS) to inject into the root element of the field. |
| **`className`** | Attach a [CSS class attribute](https://developer.mozilla.org/en-US/docs/Web/CSS/Class_selectors) to the root DOM element of a field. |
| **`readOnly`** | Setting a field to `readOnly` has no effect on the API whatsoever but disables the admin component's editability to prevent editors from modifying the field's value. |
| **`disabled`** | If a field is `disabled`, it is completely omitted from the [Admin Panel](../admin/overview) entirely. |
| **`disableBulkEdit`** | Set `disableBulkEdit` to `true` to prevent fields from appearing in the select options when making edits for multiple documents. Defaults to `true` for UI fields. |
| **`disableListColumn`** | Set `disableListColumn` to `true` to prevent fields from appearing in the list view column selector. |
| **`disableListFilter`** | Set `disableListFilter` to `true` to prevent fields from appearing in the list view filter options. |
| **`hidden`** | Will transform the field into a `hidden` input type. Its value will still submit with requests in the Admin Panel, but the field itself will not be visible to editors. |
### Field Descriptions
Field Descriptions are used to provide additional information to the editor about a field, such as special instructions. Their placement varies from field to field, but typically are displayed with subtle style differences beneath the field inputs.
A description can be configured in three ways:
- As a string.
- As a function which returns a string. [More details](#description-functions).
- As a React component. [More details](#description).
To add a Custom Description to a field, use the `admin.description` property in your Field Config:
```ts
import type { CollectionConfig } from 'payload'
export const MyCollectionConfig: CollectionConfig = {
// ...
fields: [
// ...
{
name: 'myField',
type: 'text',
admin: {
description: 'Hello, world!' // highlight-line
},
},
]
}
```
<Banner type="warning">
**Reminder:** To replace the Field Description with a [Custom Component](../custom-components/overview), use the `admin.components.Description` property. [More details](#description).
</Banner>
#### Description Functions
Custom Descriptions can also be defined as a function. Description Functions are executed on the server and can be used to format simple descriptions based on the user's current [Locale](../configuration/localization).
To add a Description Function to a field, set the `admin.description` property to a *function* in your Field Config:
```ts
import type { CollectionConfig } from 'payload'
export const MyCollectionConfig: CollectionConfig = {
// ...
fields: [
// ...
{
name: 'myField',
type: 'text',
admin: {
description: ({ t }) => `${t('Hello, world!')}` // highlight-line
},
},
]
}
```
All Description Functions receive the following arguments:
| Argument | Description |
| --- | --- |
| **`t`** | The `t` function used to internationalize the Admin Panel. [More details](../configuration/i18n) |
<Banner type="info">
**Note:** If you need to subscribe to live updates within your form, use a Description Component instead. [More details](#description).
</Banner>
### Conditional Logic
You can show and hide fields based on what other fields are doing by utilizing conditional logic on a field by field basis. The `condition` property on a field's admin config accepts a function which takes three arguments:
- `data` - the entire document's data that is currently being edited
- `siblingData` - only the fields that are direct siblings to the field with the condition
- `{ user }` - the final argument is an object containing the currently authenticated user
The `condition` function should return a boolean that will control if the field should be displayed or not.
**Example:**
```ts
{
fields: [
{
name: 'enableGreeting',
type: 'checkbox',
defaultValue: false,
},
{
name: 'greeting',
type: 'text',
admin: {
// highlight-start
condition: (data, siblingData, { user }) => {
if (data.enableGreeting) {
return true
} else {
return false
}
},
// highlight-end
},
},
]
}
```
### Custom Components
Within the [Admin Panel](../admin/overview), fields are represented in three distinct places:
- [Field](#field) - The actual form field rendered in the Edit View.
- [Cell](#cell) - The table cell component rendered in the List View.
- [Filter](#filter) - The filter component rendered in the List View.
- [Diff](#diff) - The Diff component rendered in the Version Diff View
To swap in Field Components with your own, use the `admin.components` property in your Field Config:
```ts
import type { CollectionConfig } from 'payload'
export const CollectionConfig: CollectionConfig = {
// ...
fields: [
// ...
{
// ...
admin: {
components: { // highlight-line
// ...
},
},
}
]
}
```
The following options are available:
| Component | Description |
| --- | --- |
| **`Field`** | The form field rendered of the Edit View. [More details](#field). |
| **`Cell`** | The table cell rendered of the List View. [More details](#cell). |
| **`Filter`** | The filter component rendered in the List View. [More details](#filter). |
| **`Label`** | Override the default Label of the Field Component. [More details](#label). |
| **`Error`** | Override the default Error of the Field Component. [More details](#error). |
| **`Diff`** | Override the default Diff component rendered in the Version Diff View. [More details](#diff). |
| **`Description`** | Override the default Description of the Field Component. [More details](#description). |
| **`beforeInput`** | An array of elements that will be added before the input of the Field Component. [More details](#afterinput-and-beforeinput). |
| **`afterInput`** | An array of elements that will be added after the input of the Field Component. [More details](#afterinput-and-beforeinput). |
#### Field
The Field Component is the actual form field rendered in the Edit View. This is the input that user's will interact with when editing a document.
To swap in your own Field Component, use the `admin.components.Field` property in your Field Config:
```ts
import type { CollectionConfig } from 'payload'
export const CollectionConfig: CollectionConfig = {
// ...
fields: [
// ...
{
// ...
admin: {
components: {
Field: '/path/to/MyFieldComponent', // highlight-line
},
},
}
]
}
```
*For details on how to build Custom Components, see [Building Custom Components](../custom-components/overview#building-custom-components).*
<Banner type="warning">
Instead of replacing the entire Field Component, you can alternately replace or slot-in only specific parts by using the [`Label`](#label), [`Error`](#error), [`beforeInput`](#afterinput-and-beforinput), and [`afterInput`](#afterinput-and-beforinput) properties.
</Banner>
##### Default Props
All Field Components receive the following props by default:
| Property | Description |
| --- | --- |
| **`docPreferences`** | An object that contains the [Preferences](../admin/preferences) for the document. |
| **`field`** | In Client Components, this is the sanitized Client Field Config. In Server Components, this is the original Field Config. Server Components will also receive the sanitized field config through the`clientField` prop (see below). |
| **`locale`** | The locale of the field. [More details](../configuration/localization). |
| **`readOnly`** | A boolean value that represents if the field is read-only or not. |
| **`user`** | The currently authenticated user. [More details](../authentication/overview). |
| **`validate`** | A function that can be used to validate the field. |
| **`path`** | A string representing the direct, dynamic path to the field at runtime, i.e. `myGroup.myArray.0.myField`. |
| **`schemaPath`** | A string representing the direct, static path to the Field Config, i.e. `posts.myGroup.myArray.myField`. |
| **`indexPath`** | A hyphen-notated string representing the path to the field *within the nearest named ancestor field*, i.e. `0-0` |
In addition to the above props, all Server Components will also receive the following props:
| Property | Description |
| --- | --- |
| **`clientField`** | The serializable Client Field Config. |
| **`field`** | The Field Config. |
| **`data`** | The current document being edited. |
| **`i18n`** | The [i18n](../configuration/i18n) object. |
| **`payload`** | The [Payload](../local-api/overview) class. |
| **`permissions`** | The field permissions based on the currently authenticated user. |
| **`siblingData`** | The data of the field's siblings. |
| **`user`** | The currently authenticated user. [More details](../authentication/overview). |
| **`value`** | The value of the field at render-time. |
##### Sending and receiving values from the form
When swapping out the `Field` component, you are responsible for sending and receiving the field's `value` from the form itself.
To do so, import the [`useField`](../admin/hooks#usefield) hook from `@payloadcms/ui` and use it to manage the field's value:
```tsx
'use client'
import { useField } from '@payloadcms/ui'
export const CustomTextField: React.FC = () => {
const { value, setValue } = useField() // highlight-line
return (
<input
onChange={(e) => setValue(e.target.value)}
value={value}
/>
)
}
```
<Banner type="success">
For a complete list of all available React hooks, see the [Payload React Hooks](../admin/hooks) documentation. For additional help, see [Building Custom Components](../custom-components/overview#building-custom-components).
</Banner>
##### TypeScript#field-component-types
When building Custom Field Components, you can import the client field props to ensure type safety in your component. There is an explicit type for the Field Component, one for every Field Type and server/client environment. The convention is to prepend the field type onto the target type, i.e. `TextFieldClientComponent`:
```tsx
import type {
TextFieldClientComponent,
TextFieldServerComponent,
TextFieldClientProps,
TextFieldServerProps,
// ...and so on for each Field Type
} from 'payload'
```
See each individual Field Type for exact type imports.
#### Cell
The Cell Component is rendered in the table of the List View. It represents the value of the field when displayed in a table cell.
To swap in your own Cell Component, use the `admin.components.Cell` property in your Field Config:
```ts
import type { Field } from 'payload'
export const myField: Field = {
name: 'myField',
type: 'text',
admin: {
components: {
Cell: '/path/to/MyCustomCellComponent', // highlight-line
},
},
}
```
All Cell Components receive the same [Default Field Component Props](#field), plus the following:
| Property | Description |
| --- | --- |
| **`link`** | A boolean representing whether this cell should be wrapped in a link. |
| **`onClick`** | A function that is called when the cell is clicked. |
For details on how to build Custom Components themselves, see [Building Custom Components](../custom-components/overview#building-custom-components).
#### Filter
The Filter Component is the actual input element rendered within the "Filter By" dropdown of the List View used to represent this field when building filters.
To swap in your own Filter Component, use the `admin.components.Filter` property in your Field Config:
```ts
import type { Field } from 'payload'
export const myField: Field = {
name: 'myField',
type: 'text',
admin: {
components: {
Filter: '/path/to/MyCustomFilterComponent', // highlight-line
},
},
}
```
All Custom Filter Components receive the same [Default Field Component Props](#field).
For details on how to build Custom Components themselves, see [Building Custom Components](../custom-components/overview#building-custom-components).
#### Label
The Label Component is rendered anywhere a field needs to be represented by a label. This is typically used in the Edit View, but can also be used in the List View and elsewhere.
To swap in your own Label Component, use the `admin.components.Label` property in your Field Config:
```ts
import type { Field } from 'payload'
export const myField: Field = {
name: 'myField',
type: 'text',
admin: {
components: {
Label: '/path/to/MyCustomLabelComponent', // highlight-line
},
},
}
```
All Custom Label Components receive the same [Default Field Component Props](#field).
For details on how to build Custom Components themselves, see [Building Custom Components](../custom-components/overview#building-custom-components).
##### TypeScript#label-component-types
When building Custom Label Components, you can import the component types to ensure type safety in your component. There is an explicit type for the Label Component, one for every Field Type and server/client environment. The convention is to append `LabelServerComponent` or `LabelClientComponent` to the type of field, i.e. `TextFieldLabelClientComponent`.
```tsx
import type {
TextFieldLabelServerComponent,
TextFieldLabelClientComponent,
// ...and so on for each Field Type
} from 'payload'
```
#### Description
Alternatively to the [Description Property](#field-descriptions), you can also use a [Custom Component](../custom-components/overview) as the Field Description. This can be useful when you need to provide more complex feedback to the user, such as rendering dynamic field values or other interactive elements.
To add a Description Component to a field, use the `admin.components.Description` property in your Field Config:
```ts
import type { CollectionConfig } from 'payload'
export const MyCollectionConfig: CollectionConfig = {
// ...
fields: [
// ...
{
name: 'myField',
type: 'text',
admin: {
components: {
Description: '/path/to/MyCustomDescriptionComponent', // highlight-line
}
}
}
]
}
```
All Custom Description Components receive the same [Default Field Component Props](#field).
For details on how to build a Custom Components themselves, see [Building Custom Components](../custom-components/overview#building-custom-components).
##### TypeScript#description-component-types
When building Custom Description Components, you can import the component props to ensure type safety in your component. There is an explicit type for the Description Component, one for every Field Type and server/client environment. The convention is to append `DescriptionServerComponent` or `DescriptionClientComponent` to the type of field, i.e. `TextFieldDescriptionClientComponent`.
```tsx
import type {
TextFieldDescriptionServerComponent,
TextFieldDescriptionClientComponent,
// And so on for each Field Type
} from 'payload'
```
#### Error
The Error Component is rendered when a field fails validation. It is typically displayed beneath the field input in a visually-compelling style.
To swap in your own Error Component, use the `admin.components.Error` property in your Field Config:
```ts
import type { Field } from 'payload'
export const myField: Field = {
name: 'myField',
type: 'text',
admin: {
components: {
Error: '/path/to/MyCustomErrorComponent', // highlight-line
},
},
}
```
All Error Components receive the [Default Field Component Props](#field).
For details on how to build Custom Components themselves, see [Building Custom Components](../custom-components/overview#building-custom-components).
##### TypeScript#error-component-types
When building Custom Error Components, you can import the component types to ensure type safety in your component. There is an explicit type for the Error Component, one for every Field Type and server/client environment. The convention is to append `ErrorServerComponent` or `ErrorClientComponent` to the type of field, i.e. `TextFieldErrorClientComponent`.
```tsx
import type {
TextFieldErrorServerComponent,
TextFieldErrorClientComponent,
// And so on for each Field Type
} from 'payload'
```
#### Diff
The Diff Component is rendered in the Version Diff view. It will only be visible in entities with versioning enabled,
To swap in your own Diff Component, use the `admin.components.Diff` property in your Field Config:
```ts
import type { Field } from 'payload'
export const myField: Field = {
name: 'myField',
type: 'text',
admin: {
components: {
Diff: '/path/to/MyCustomDiffComponent', // highlight-line
},
},
}
```
All Error Components receive the [Default Field Component Props](#field).
For details on how to build Custom Components themselves, see [Building Custom Components](../custom-components/overview#building-custom-components).
##### TypeScript#diff-component-types
When building Custom Diff Components, you can import the component types to ensure type safety in your component. There is an explicit type for the Diff Component, one for every Field Type and server/client environment. The convention is to append `DiffServerComponent` or `DiffClientComponent` to the type of field, i.e. `TextFieldDiffClientComponent`.
```tsx
import type {
TextFieldDiffServerComponent,
TextFieldDiffClientComponent,
// And so on for each Field Type
} from 'payload'
```
#### afterInput and beforeInput
With these properties you can add multiple components *before* and *after* the input element, as their name suggests. This is useful when you need to render additional elements alongside the field without replacing the entire field component.
To add components before and after the input element, use the `admin.components.beforeInput` and `admin.components.afterInput` properties in your Field Config:
```ts
import type { CollectionConfig } from 'payload'
export const MyCollectionConfig: CollectionConfig = {
// ...
fields: [
// ...
{
name: 'myField',
type: 'text',
admin: {
components: {
// highlight-start
beforeInput: ['/path/to/MyCustomComponent'],
afterInput: ['/path/to/MyOtherCustomComponent'],
// highlight-end
}
}
}
]
}
```
All `afterInput` and `beforeInput` Components receive the same [Default Field Component Props](#field).
For details on how to build Custom Components, see [Building Custom Components](../custom-components/overview#building-custom-components).
## TypeScript
You can import the Payload `Field` type as well as other common types from the `payload` package. [More details](../typescript/overview).

View File

@@ -6,7 +6,7 @@ desc: The Point field type stores coordinates in the database. Learn how to use
keywords: point, geolocation, geospatial, geojson, 2dsphere, config, configuration, documentation, Content Management System, cms, headless, javascript, node, react, nextjs
---
The Point Field saves a pair of coordinates in the database and assigns an index for location related queries. The data structure in the database matches the GeoJSON structure to represent point. The Payload API simplifies the object data to only the [longitude, latitude] location.
The Point Field saves a pair of coordinates in the database and assigns an index for location related queries. The data structure in the database matches the GeoJSON structure to represent point. The Payload APIs simplifies the object data to only the [longitude, latitude] location.
<LightDarkImage
srcLight="https://payloadcms.com/images/docs/fields/point.png"
@@ -47,7 +47,7 @@ export const MyPointField: Field = {
| **`defaultValue`** | Provide data to be used for this field's default value. [More](/docs/fields/overview#default-values) |
| **`localized`** | Enable localization for this field. Requires [localization to be enabled](/docs/configuration/localization) in the Base config. |
| **`required`** | Require this field to have a value. |
| **`admin`** | Admin-specific configuration. [More details](./overview#admin-options). |
| **`admin`** | Admin-specific configuration. [More details](../admin/fields#admin-options). |
| **`custom`** | Extension point for adding custom data (e.g. for plugins) |
| **`typescriptSchema`** | Override field type generation with providing a JSON schema |
| **`virtual`** | Provide `true` to disable field in the database. See [Virtual Fields](https://payloadcms.com/blog/learn-how-virtual-fields-can-help-solve-common-cms-challenges) |
@@ -129,84 +129,3 @@ payload.find({
},
})
```
## Custom Components
### Field
#### Server Component
```tsx
import type React from 'react'
import { PointField } from '@payloadcms/ui'
import type { PointFieldServerComponent } from 'payload'
export const CustomPointFieldServer: PointFieldServerComponent = ({
clientField,
path,
schemaPath,
permissions,
}) => {
return (
<PointField field={clientField} path={path} schemaPath={schemaPath} permissions={permissions} />
)
}
```
#### Client Component
```tsx
'use client'
import React from 'react'
import { PointField } from '@payloadcms/ui'
import type { PointFieldClientComponent } from 'payload'
export const CustomPointFieldClient: PointFieldClientComponent = (props) => {
return <PointField {...props} />
}
```
### Label
#### Server Component
```tsx
import React from 'react'
import { FieldLabel } from '@payloadcms/ui'
import type { PointFieldLabelServerComponent } from 'payload'
export const CustomPointFieldLabelServer: PointFieldLabelServerComponent = ({
clientField,
path,
}) => {
return (
<FieldLabel
label={clientField?.label || clientField?.name}
path={path}
required={clientField?.required}
/>
)
}
```
#### Client Component
```tsx
'use client'
import React from 'react'
import { FieldLabel } from '@payloadcms/ui'
import type { PointFieldLabelClientComponent } from 'payload'
export const CustomPointFieldLabelClient: PointFieldLabelClientComponent = ({
field,
path,
}) => {
return (
<FieldLabel
label={field?.label || field?.name}
path={path}
required={field?.required}
/>
)
}
```

View File

@@ -50,7 +50,6 @@ export const MyRadioField: Field = {
| **`admin`** | Admin-specific configuration. [More details](#admin-options). |
| **`custom`** | Extension point for adding custom data (e.g. for plugins) |
| **`enumName`** | Custom enum name for this field when using SQL Database Adapter ([Postgres](/docs/database/postgres)). Auto-generated from name if not defined. |
| **`interfaceName`** | Create a top level, reusable [Typescript interface](/docs/typescript/generating-types#custom-field-interfaces) & [GraphQL type](/docs/graphql/graphql-schema#custom-field-schemas). |
| **`typescriptSchema`** | Override field type generation with providing a JSON schema |
| **`virtual`** | Provide `true` to disable field in the database. See [Virtual Fields](https://payloadcms.com/blog/learn-how-virtual-fields-can-help-solve-common-cms-challenges) |
@@ -67,7 +66,7 @@ _* An asterisk denotes that a property is required._
## Admin Options
To customize the appearance and behavior of the Radio Field in the [Admin Panel](../admin/overview), you can use the `admin` option:
The customize the appearance and behavior of the Radio Field in the [Admin Panel](../admin/overview), you can use the `admin` option:
```ts
import type { Field } from 'payload'
@@ -80,7 +79,7 @@ export const MyRadioField: Field = {
}
```
The Radio Field inherits all of the default options from the base [Field Admin Config](./overview#admin-options), plus the following additional options:
The Radio Field inherits all of the default options from the base [Field Admin Config](../admin/fields#admin-options), plus the following additional options:
| Property | Description |
| ------------------------------ | -------------------------------------------------------------------------------------------------------------------------------------- |
@@ -118,90 +117,3 @@ export const ExampleCollection: CollectionConfig = {
],
}
```
## Custom Components
### Field
#### Server Component
```tsx
import type React from 'react'
import { RadioGroupField } from '@payloadcms/ui'
import type { RadioFieldServerComponent } from 'payload'
export const CustomRadioFieldServer: RadioFieldServerComponent = ({
clientField,
path,
schemaPath,
permissions,
}) => {
return (
<RadioGroupField
field={clientField}
path={path}
schemaPath={schemaPath}
permissions={permissions}
/>
)
}
```
#### Client Component
```tsx
'use client'
import React from 'react'
import { RadioGroupField } from '@payloadcms/ui'
import type { RadioFieldClientComponent } from 'payload'
export const CustomRadioFieldClient: RadioFieldClientComponent = (props) => {
return <RadioGroupField {...props} />
}
```
### Label
#### Server Component
```tsx
import React from 'react'
import { FieldLabel } from '@payloadcms/ui'
import type { RadioFieldLabelServerComponent } from 'payload'
export const CustomRadioFieldLabelServer: RadioFieldLabelServerComponent = ({
clientField,
path,
required,
}) => {
return (
<FieldLabel
label={clientField?.label || clientField?.name}
path={path}
required={clientField?.required}
/>
)
}
```
#### Client Component
```tsx
'use client'
import React from 'react'
import { FieldLabel } from '@payloadcms/ui'
import type { RadioFieldLabelClientComponent } from 'payload'
export const CustomRadioFieldLabelClient: RadioFieldLabelClientComponent = ({
field,
path,
}) => {
return (
<FieldLabel
label={field?.label || field?.name}
path={path}
required={field?.required}
/>
)
}
```

View File

@@ -6,7 +6,7 @@ desc: The Relationship field provides the ability to relate documents together.
keywords: relationship, fields, config, configuration, documentation, Content Management System, cms, headless, javascript, node, react, nextjs
---
The Relationship Field is one of the most powerful fields Payload features. It provides the ability to easily relate documents together.
The Relationship Field is one of the most powerful fields Payload features. It provides for the ability to easily relate documents together.
<LightDarkImage
srcLight="https://payloadcms.com/images/docs/fields/relationship.png"
@@ -71,7 +71,8 @@ _* An asterisk denotes that a property is required._
</Banner>
## Admin Options
To the appearance and behavior of the Relationship Field in the [Admin Panel](../admin/overview), you can use the `admin` option:
The customize the appearance and behavior of the Relationship Field in the [Admin Panel](../admin/overview), you can use the `admin` option:
```ts
import type { Field } from 'payload'
@@ -84,7 +85,7 @@ export const MyRelationshipField: Field = {
}
```
The Relationship Field inherits all of the default options from the base [Field Admin Config](./overview#admin-options), plus the following additional options:
The Relationship Field inherits all of the default options from the base [Field Admin Config](../admin/fields#admin-options), plus the following additional options:
| Property | Description |
| ------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------- |
@@ -135,19 +136,21 @@ Note: If `sortOptions` is not defined, the default sorting behavior of the Relat
## Filtering relationship options
Options can be dynamically limited by supplying a [query constraint](/docs/queries/overview), which will be used both for validating input and filtering available relationships in the UI.
Options can be dynamically limited by supplying a [query constraint](/docs/queries/overview), which will be used both
for validating input and filtering available relationships in the UI.
The `filterOptions` property can either be a `Where` query, or a function returning `true` to not filter, `false` to prevent all, or a `Where` query. When using a function, it will be called with an argument object with the following properties:
The `filterOptions` property can either be a `Where` query, or a function returning `true` to not filter, `false` to
prevent all, or a `Where` query. When using a function, it will be
called with an argument object with the following properties:
| Property | Description |
| ------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `blockData` | The data of the nearest parent block. Will be `undefined` if the field is not within a block or when called on a `Filter` component within the list view. |
| `data` | An object containing the full collection or global document currently being edited. Will be an empty object when called on a `Filter` component within the list view. |
| `id` | The `id` of the current document being edited. Will be `undefined` during the `create` operation or when called on a `Filter` component within the list view. |
| `relationTo` | The collection `slug` to filter against, limited to this field's `relationTo` property. |
| `req` | The Payload Request, which contains references to `payload`, `user`, `locale`, and more. |
| `siblingData` | An object containing document data that is scoped to only fields within the same parent of this field. Will be an emprt object when called on a `Filter` component within the list view. |
| `user` | An object containing the currently authenticated user. |
| Property | Description |
| ------------- | ----------------------------------------------------------------------------------------------------- |
| `relationTo` | The collection `slug` to filter against, limited to this field's `relationTo` property |
| `data` | An object containing the full collection or global document currently being edited |
| `siblingData` | An object containing document data that is scoped to only fields within the same parent of this field |
| `id` | The `id` of the current document being edited. `id` is `undefined` during the `create` operation |
| `user` | An object containing the currently authenticated user |
| `req` | The Payload Request, which contains references to `payload`, `user`, `locale`, and more. |
## Example
@@ -293,7 +296,7 @@ The `hasMany` tells Payload that there may be more than one collection saved to
}
```
To save to the `hasMany` relationship field we need to send an array of IDs:
To save the to `hasMany` relationship field we need to send an array of IDs:
```json
{
@@ -370,89 +373,3 @@ Since we are referencing multiple collections, the field you are querying on may
You **cannot** query on a field within a polymorphic relationship as you would with a
non-polymorphic relationship.
</Banner>
## Custom Components
### Field
#### Server Component
```tsx
import type React from 'react'
import { RelationshipField } from '@payloadcms/ui'
import type { RelationshipFieldServerComponent } from 'payload'
export const CustomRelationshipFieldServer: RelationshipFieldServerComponent = ({
clientField,
path,
schemaPath,
permissions,
}) => {
return (
<RelationshipField
field={clientField}
path={path}
schemaPath={schemaPath}
permissions={permissions}
/>
)
}
```
#### Client Component
```tsx
'use client'
import React from 'react'
import { RelationshipField } from '@payloadcms/ui'
import type { RelationshipFieldClientComponent } from 'payload'
export const CustomRelationshipFieldClient: RelationshipFieldClientComponent = (props) => {
return <RelationshipField {...props} />
}
```
### Label
#### Server Component
```tsx
import React from 'react'
import { FieldLabel } from '@payloadcms/ui'
import type { RelationshipFieldLabelServerComponent } from 'payload'
export const CustomRelationshipFieldLabelServer: RelationshipFieldLabelServerComponent = (
clientField,
path
) => {
return (
<FieldLabel
label={clientField?.label || clientField?.name}
path={path}
required={clientField?.required}
/>
)
}
```
#### Client Component
```tsx
'use client'
import React from 'react'
import { FieldLabel } from '@payloadcms/ui'
import type { RelationshipFieldLabelClientComponent } from 'payload'
export const CustomRelationshipFieldLabelClient: RelationshipFieldLabelClientComponent = ({
field,
path,
}) => {
return (
<FieldLabel
label={field?.label || field?.name}
path={path}
required={field?.required}
/>
)
}
```

View File

@@ -18,14 +18,14 @@ Instead, you can invest your time and effort into learning the underlying open-s
| Option | Description |
| --- | --- |
| **`name`** * | To be used as the property name when stored and retrieved from the database. [More](./overview#field-names) |
| **`name`** * | To be used as the property name when stored and retrieved from the database. [More](../fields/overview#field-names) |
| **`label`** | Text used as a field label in the Admin Panel or an object with keys for each language. |
| **`validate`** | Provide a custom validation function that will be executed on both the Admin Panel and the backend. [More](./overview#validation) |
| **`validate`** | Provide a custom validation function that will be executed on both the Admin Panel and the backend. [More](../fields/overview#validation) |
| **`saveToJWT`** | If this field is top-level and nested in a config supporting [Authentication](../authentication/overview), include its data in the user JWT. |
| **`hooks`** | Provide Field Hooks to control logic for this field. [More details](../hooks/fields). |
| **`access`** | Provide Field Access Control to denote what users can see and do with this field's data. [More details](../access-control/fields). |
| **`hidden`** | Restrict this field's visibility from all APIs entirely. Will still be saved to the database, but will not appear in any API or the Admin Panel. |
| **`defaultValue`** | Provide data to be used for this field's default value. [More](./overview#default-values) |
| **`defaultValue`** | Provide data to be used for this field's default value. [More](../fields/overview#default-values) |
| **`localized`** | Enable localization for this field. Requires [localization to be enabled](../configuration/localization) in the Base config. |
| **`required`** | Require this field to have a value. |
| **`admin`** | Admin-specific configuration. [More details](#admin-options). |
@@ -38,7 +38,7 @@ Instead, you can invest your time and effort into learning the underlying open-s
## Admin Options
To customize the appearance and behavior of the Rich Text Field in the [Admin Panel](../admin/overview), you can use the `admin` option. The Rich Text Field inherits all the default options from the base [Field Admin Config](./overview#admin-options).
To customize the appearance and behavior of the Rich Text Field in the [Admin Panel](../admin/overview), you can use the `admin` option. The Rich Text Field inherits all the default options from the base [Field Admin Config](../admin/fields#admin-options).
```ts
import type { Field } from 'payload'
@@ -56,4 +56,4 @@ Further customization can be done with editor-specific options.
## Editor-specific Options
For a ton more editor-specific options, including how to build custom rich text elements directly into your editor,
take a look at the [rich text editor documentation](../rich-text/overview).
take a look at the [rich text editor documentation](../rich-text/overview).

View File

@@ -36,7 +36,7 @@ export const MyRowField: Field = {
| Option | Description |
| --------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **`fields`** * | Array of field types to nest within this Row. |
| **`admin`** | Admin-specific configuration excluding `description`, `readOnly`, and `hidden`. [More details](./overview#admin-options). |
| **`admin`** | Admin-specific configuration excluding `description`, `readOnly`, and `hidden`. [More details](../admin/fields#admin-options). |
| **`custom`** | Extension point for adding custom data (e.g. for plugins) |
_* An asterisk denotes that a property is required._

View File

@@ -53,7 +53,6 @@ export const MySelectField: Field = {
| **`custom`** | Extension point for adding custom data (e.g. for plugins) |
| **`enumName`** | Custom enum name for this field when using SQL Database Adapter ([Postgres](/docs/database/postgres)). Auto-generated from name if not defined. |
| **`dbName`** | Custom table name (if `hasMany` set to `true`) for this field when using SQL Database Adapter ([Postgres](/docs/database/postgres)). Auto-generated from name if not defined. |
| **`interfaceName`** | Create a top level, reusable [Typescript interface](/docs/typescript/generating-types#custom-field-interfaces) & [GraphQL type](/docs/graphql/graphql-schema#custom-field-schemas). |
| **`typescriptSchema`** | Override field type generation with providing a JSON schema |
| **`virtual`** | Provide `true` to disable field in the database. See [Virtual Fields](https://payloadcms.com/blog/learn-how-virtual-fields-can-help-solve-common-cms-challenges) |
@@ -69,7 +68,7 @@ _* An asterisk denotes that a property is required._
## Admin Options
To customize the appearance and behavior of the Select Field in the [Admin Panel](../admin/overview), you can use the `admin` option:
The customize the appearance and behavior of the Select Field in the [Admin Panel](../admin/overview), you can use the `admin` option:
```ts
import type { Field } from 'payload'
@@ -82,7 +81,7 @@ export const MySelectField: Field = {
}
```
The Select Field inherits all of the default options from the base [Field Admin Config](./overview#admin-options), plus the following additional options:
The Select Field inherits all of the default options from the base [Field Admin Config](../admin/fields#admin-options), plus the following additional options:
| Property | Description |
| ------------------------------ | ---------------------------------------------------------------------------------------------------------------------------------------- |
@@ -126,90 +125,83 @@ export const ExampleCollection: CollectionConfig = {
}
```
## Custom Components
## Customization
### Field
The Select field UI component can be customized by providing a custom React component to the `components` object in the Base config.
#### Server Component
```ts
export const CustomSelectField: Field = {
name: 'customSelectField',
type: 'select', // or 'text' if you have dynamic options
admin: {
components: {
Field: CustomSelectComponent({
options: [
{
label: 'Option 1',
value: '1',
},
{
label: 'Option 2',
value: '2',
},
],
}),
},
},
}
```
```tsx
import type { SelectFieldServerComponent } from 'payload'
import type React from 'react'
You can import the existing Select component directly from Payload, then extend and customize it as needed.
import { SelectField } from '@payloadcms/ui'
```ts
import * as React from 'react';
import { SelectInput, useAuth, useField } from '@payloadcms/ui';
type CustomSelectProps = {
path: string;
options: {
label: string;
value: string;
}[];
}
export const CustomSelectComponent: React.FC<CustomSelectProps> = ({ path, options }) => {
const { value, setValue } = useField<string>({ path })
const { user } = useAuth()
const adjustedOptions = options.filter((option) => {
/*
A common use case for a custom select
is to show different options based on
the current user's role.
*/
return option;
});
export const CustomSelectFieldServer: SelectFieldServerComponent = ({
clientField,
path,
schemaPath,
permissions,
}) => {
return (
<SelectField
field={clientField}
path={path}
schemaPath={schemaPath}
permissions={permissions}
/>
<div>
<label className="field-label">
Custom Select
</label>
<SelectInput
path={path}
name={path}
options={adjustedOptions}
value={value}
onChange={(e) => setValue(e.value)}
/>
</div>
)
}
```
#### Client Component
If you are looking to create a dynamic select field, the following tutorial will walk you through the process of creating a custom select field that fetches its options from an external API.
```tsx
'use client'
import type { SelectFieldClientComponent } from 'payload'
<VideoDrawer
id="Efn9OxSjA6Y"
label="How to Create a Custom Select Field"
drawerTitle="How to Create a Custom Select Field: A Step-by-Step Guide"
/>
import { SelectField } from '@payloadcms/ui'
import React from 'react'
export const CustomSelectFieldClient: SelectFieldClientComponent = (props) => {
return <SelectField {...props} />
}
```
### Label
#### Server Component
```tsx
import React from 'react'
import { FieldLabel } from '@payloadcms/ui'
import type { SelectFieldLabelServerComponent } from 'payload'
export const CustomSelectFieldLabelServer: SelectFieldLabelServerComponent = ({
clientField,
path,
}) => {
return (
<FieldLabel
label={clientField?.label || clientField?.name}
path={path}
required={clientField?.required}
/>
)
}
```
#### Client Component
```tsx
'use client'
import React from 'react'
import { FieldLabel } from '@payloadcms/ui'
import type { SelectFieldLabelClientComponent } from 'payload'
export const CustomSelectFieldLabelClient: SelectFieldLabelClientComponent = ({
field,
path,
}) => {
return (
<FieldLabel
label={field?.label || field?.name}
path={path}
required={field?.required}
/>
)
}
```
If you want to learn more about custom components check out the [Admin > Custom Component](/docs/admin/fields) docs.

View File

@@ -36,7 +36,7 @@ export const MyTabsField: Field = {
| Option | Description |
| ------------- | ------------------------------------------------------------------------------------------------------------------------ |
| **`tabs`** * | Array of tabs to render within this Tabs field. |
| **`admin`** | Admin-specific configuration. [More details](./overview#admin-options). |
| **`admin`** | Admin-specific configuration. [More details](../admin/fields#admin-options). |
| **`custom`** | Extension point for adding custom data (e.g. for plugins) |
### Tab-specific Config

View File

@@ -56,7 +56,7 @@ _* An asterisk denotes that a property is required._
## Admin Options
To customize the appearance and behavior of the Text Field in the [Admin Panel](../admin/overview), you can use the `admin` option:
The customize the appearance and behavior of the Text Field in the [Admin Panel](../admin/overview), you can use the `admin` option:
```ts
import type { Field } from 'payload'
@@ -69,7 +69,7 @@ export const MyTextField: Field = {
}
```
The Text Field inherits all of the default options from the base [Field Admin Config](./overview#admin-options), plus the following additional options:
The Text Field inherits all of the default options from the base [Field Admin Config](../admin/fields#admin-options), plus the following additional options:
| Option | Description |
| -------------- | ---------------------------------------------------------------------------------------------------------------- |
@@ -95,85 +95,3 @@ export const ExampleCollection: CollectionConfig = {
],
}
```
## Custom Components
### Field
#### Server Component
```tsx
import type React from 'react'
import { TextField } from '@payloadcms/ui'
import type { TextFieldServerComponent } from 'payload'
export const CustomTextFieldServer: TextFieldServerComponent = ({
clientField,
path,
schemaPath,
permissions,
}) => {
return (
<TextField field={clientField} path={path} schemaPath={schemaPath} permissions={permissions} />
)
}
```
#### Client Component
```tsx
'use client'
import React from 'react'
import { TextField } from '@payloadcms/ui'
import type { TextFieldClientComponent } from 'payload'
export const CustomTextFieldClient: TextFieldClientComponent = (props) => {
return <TextField {...props} />
}
```
### Label
#### Server Component
```tsx
import React from 'react'
import { FieldLabel } from '@payloadcms/ui'
import type { TextFieldLabelServerComponent } from 'payload'
export const CustomTextFieldLabelServer: TextFieldLabelServerComponent = ({
clientField,
path,
required,
}) => {
return (
<FieldLabel
label={clientField?.label || clientField?.name}
path={path}
required={clientField?.required}
/>
)
}
```
#### Client Component
```tsx
'use client'
import React from 'react'
import { FieldLabel } from '@payloadcms/ui'
import type { TextFieldLabelClientComponent } from 'payload'
export const CustomTextFieldLabelClient: TextFieldLabelClientComponent = ({
field,
path,
}) => {
return (
<FieldLabel
label={field?.label || field?.name}
path={path}
required={field?.required}
/>
)
}
```

View File

@@ -53,7 +53,7 @@ _* An asterisk denotes that a property is required._
## Admin Options
To customize the appearance and behavior of the Textarea Field in the [Admin Panel](../admin/overview), you can use the `admin` option:
The customize the appearance and behavior of the Textarea Field in the [Admin Panel](../admin/overview), you can use the `admin` option:
```ts
import type { Field } from 'payload'
@@ -66,7 +66,7 @@ export const MyTextareaField: Field = {
}
```
The Textarea Field inherits all of the default options from the base [Field Admin Config](./overview#admin-options), plus the following additional options:
The Textarea Field inherits all of the default options from the base [Field Admin Config](../admin/fields#admin-options), plus the following additional options:
| Option | Description |
| ------------------ | --------------------------------------------------------------------------------------------------------------------------- |
@@ -93,89 +93,3 @@ export const ExampleCollection: CollectionConfig = {
],
}
```
## Custom Components
### Field
#### Server Component
```tsx
import type React from 'react'
import { TextareaField } from '@payloadcms/ui'
import type { TextareaFieldServerComponent } from 'payload'
export const CustomTextareaFieldServer: TextareaFieldServerComponent = ({
clientField,
path,
schemaPath,
permissions,
}) => {
return (
<TextareaField
field={clientField}
path={path}
schemaPath={schemaPath}
permissions={permissions}
/>
)
}
```
#### Client Component
```tsx
'use client'
import React from 'react'
import { TextareaField } from '@payloadcms/ui'
import type { TextareaFieldClientComponent } from 'payload'
export const CustomTextareaFieldClient: TextareaFieldClientComponent = (props) => {
return <TextareaField {...props} />
}
```
### Label
#### Server Component
```tsx
import React from 'react'
import { FieldLabel } from '@payloadcms/ui'
import type { TextareaFieldLabelServerComponent } from 'payload'
export const CustomTextareaFieldLabelServer: TextareaFieldLabelServerComponent = ({
clientField,
path,
}) => {
return (
<FieldLabel
label={clientField?.label || clientField?.name}
path={path}
required={clientField?.required}
/>
)
}
```
#### Client Component
```tsx
'use client'
import React from 'react'
import { FieldLabel } from '@payloadcms/ui'
import type { TextareaFieldLabelClientComponent } from 'payload'
export const CustomTextareaFieldLabelClient: TextareaFieldLabelClientComponent = ({
field,
path,
}) => {
return (
<FieldLabel
label={field?.label || field?.name}
path={path}
required={field?.required}
/>
)
}
```

View File

@@ -32,8 +32,8 @@ export const MyUIField: Field = {
| ------------------------------- | ------------------------------------------------------------------------------------------------------------------- |
| **`name`** * | A unique identifier for this field. |
| **`label`** | Human-readable label for this UI field. |
| **`admin.components.Field`** * | React component to be rendered for this field within the Edit View. [More](./overview#field) |
| **`admin.components.Cell`** | React component to be rendered as a Cell within collection List views. [More](./overview#cell) |
| **`admin.components.Field`** * | React component to be rendered for this field within the Edit View. [More](../admin/fields#field) |
| **`admin.components.Cell`** | React component to be rendered as a Cell within collection List views. [More](../admin/fields#cell) |
| **`admin.disableListColumn`** | Set `disableListColumn` to `true` to prevent the UI field from appearing in the list view column selector. |
| **`custom`** | Extension point for adding custom data (e.g. for plugins) |

View File

@@ -64,7 +64,7 @@ export const MyUploadField: Field = {
| **`displayPreview`** | Enable displaying preview of the uploaded file. Overrides related Collection's `displayPreview` option. [More](/docs/upload/overview#collection-upload-options). |
| **`localized`** | Enable localization for this field. Requires [localization to be enabled](/docs/configuration/localization) in the Base config. |
| **`required`** | Require this field to have a value. |
| **`admin`** | Admin-specific configuration. [Admin Options](./overview#admin-options). |
| **`admin`** | Admin-specific configuration. [Admin Options](../admin/fields#admin-options). |
| **`custom`** | Extension point for adding custom data (e.g. for plugins) |
| **`typescriptSchema`** | Override field type generation with providing a JSON schema |
| **`virtual`** | Provide `true` to disable field in the database. See [Virtual Fields](https://payloadcms.com/blog/learn-how-virtual-fields-can-help-solve-common-cms-challenges) |

View File

@@ -50,7 +50,7 @@ Everything Payload does (create, read, update, delete, login, logout, etc.) is e
- [Local API](#local-api) - Extremely fast, direct-to-database access
- [REST API](#rest-api) - Standard HTTP endpoints for querying and mutating data
- [GraphQL](#graphql-api) - A full GraphQL API with a GraphQL Playground
- [GraphQL](#graphql) - A full GraphQL API with a GraphQL Playground
<Banner type="success">
**Note:**
@@ -157,7 +157,7 @@ All of Payload's GraphQL functionality is abstracted into a separate package. Pa
This is the UI library that Payload's Admin Panel uses. All components are exported from this package and can be re-used as you build extensions to the Payload admin UI, or want to use Payload components in your own React apps. Some exports are server components and some are client components.
`@payloadcms/db-postgres`, `@payloadcms/db-vercel-postgres`, `@payloadcms/db-mongodb`, `@payloadcms/db-sqlite`
`@payloadcms/db-postgres`, `@payloadcms/db-vercel-postgres`, `@payloadcms/db-mongodb`
You can choose which Database Adapter you'd like to use for your project, and no matter which you choose, the entire data layer for Payload is contained within these packages. You can only use one at a time for any given project.

View File

@@ -94,7 +94,7 @@ const Header: GlobalConfig = {
## Preferences
User [preferences](../admin/preferences) for the [Admin Panel](../admin/overview) are also available to GraphQL the same way as other collection schemas are generated. To query preferences you must supply an authorization token in the header and only the preferences of that user will be accessible.
User [preferences](/docs/admin/overview#preferences) for the [Admin Panel](../admin/overview) are also available to GraphQL the same way as other collection schemas are generated. To query preferences you must supply an authorization token in the header and only the preferences of that user will be accessible.
**Payload will open the following query:**

View File

@@ -6,7 +6,7 @@ desc: Context allows you to pass in extra data that can be shared between hooks
keywords: hooks, context, payload context, payloadcontext, data, extra data, shared data, shared, extra
---
The `context` object is used to share data across different Hooks. This persists throughout the entire lifecycle of a request and is available within every Hook. By setting properties to `req.context`, you can effectively share logic across multiple Hooks.
The `context` object is used to share data across different Hooks. This persists throughout the entire lifecycle of a request and is available within every Hook. By setting properties to `req.context`, you can effectively logic across multiple Hooks.
## When To Use Context

View File

@@ -27,7 +27,7 @@ All Field Hooks accept an array of synchronous or asynchronous functions. These
<Banner type="warning">
**Important:**
Due to GraphQL's typed nature, changing the type of data that you return from a field will produce errors in the [GraphQL API](../graphql/overview). If you need to change the shape or type of data, consider [Collection Hooks](./collections) or [Global Hooks](./globals) instead.
Due to GraphQL's typed nature, changing the type of data that you return from a field will produce errors in the [GraphQL API](../graphql/overview). If you need to change the shape or type of data, consider [Collection Hooks](./collections) or [Global Hooks](./hooks) instead.
</Banner>
To add hooks to a Field, use the `hooks` property in your [Field Config](../fields/overview):
@@ -71,7 +71,6 @@ The following arguments are provided to all Field Hooks:
| **`schemaPath`** | The path of the [Field](../fields/overview) in the schema. |
| **`siblingData`** | The data of sibling fields adjacent to the field that the Hook is running against. |
| **`siblingDocWithLocales`** | The sibling data of the Document with all [Locales](../configuration/localization). |
| **`siblingFields`** | The sibling fields of the field which the hook is running against. |
| **`value`** | The value of the [Field](../fields/overview). |
<Banner type="success">

View File

@@ -29,7 +29,7 @@ As mentioned above, you can queue jobs, but the jobs won't run unless a worker p
#### Cron jobs
You can use the `jobs.autoRun` property to configure cron jobs:
You can use the jobs.autoRun property to configure cron jobs:
```ts
export default buildConfig({
@@ -47,12 +47,6 @@ export default buildConfig({
},
// add as many cron jobs as you want
],
shouldAutoRun: async (payload) => {
// Tell Payload if it should run jobs or not.
// This function will be invoked each time Payload goes to pick up and run jobs.
// If this function ever returns false, the cron schedule will be stopped.
return true
}
},
})
```

View File

@@ -20,7 +20,7 @@ The most important aspect of a Workflow is the `handler`, where you can declare
However, importantly, tasks that have successfully been completed will simply re-return the cached and saved output without running again. The Workflow will pick back up where it failed and only task from the failure point onward will be re-executed.
To define a JS-based workflow, simply add a workflow to the `jobs.workflows` array in your Payload config. A workflow consists of the following fields:
To define a JS-based workflow, simply add a workflow to the `jobs.wokflows` array in your Payload config. A workflow consists of the following fields:
| Option | Description |
| --------------------------- | -------------------------------------------------------------------------------- |

View File

@@ -256,14 +256,18 @@ If you are using relationships or uploads in your front-end application, and you
// ...
// If your site is running on a different domain than your Payload server,
// This will allows requests to be made between the two domains
cors: [
'http://localhost:3001' // Your front-end application
],
cors: {
[
'http://localhost:3001' // Your front-end application
],
},
// If you are protecting resources behind user authentication,
// This will allow cookies to be sent between the two domains
csrf: [
'http://localhost:3001' // Your front-end application
],
csrf: {
[
'http://localhost:3001' // Your front-end application
],
},
}
```

View File

@@ -28,15 +28,16 @@ const config = buildConfig({
}
})
```
<Banner type="warning">
**Reminder:**
Alternatively, you can define the `admin.livePreview` property on individual [Collection Admin Configs](../configuration/collections#admin-options) and [Global Admin Configs](../configuration/globals#admin-options). Settings defined here will be merged into the top-level as overrides.
Alternatively, you can define the `admin.livePreview` property on individual [Collection Admin Configs](../admin/collections) and [Global Admin Configs](../admin/globals). Settings defined here will be merged into the top-level as overrides.
</Banner>
{/* IMAGE OF LIVE PREVIEW HERE */}
## Options
Setting up Live Preview is easy. This can be done either globally through the [Root Admin Config](../admin/overview), or on individual [Collection Admin Configs](../configuration/collections#admin-options) and [Global Admin Configs](../configuration/globals#admin-options). Once configured, a new "Live Preview" tab will appear at the top of enabled Documents. Navigating to this tab opens the preview window and loads your front-end application.
Setting up Live Preview is easy. This can be done either globally through the [Root Admin Config](../admin/overview), or on individual [Collection Admin Configs](../admin/collections) and [Global Admin Configs](../admin/globals). Once configured, a new "Live Preview" tab will appear at the top of enabled Documents. Navigating to this tab opens the preview window and loads your front-end application.
The following options are available:
@@ -105,16 +106,14 @@ The following arguments are provided to the `url` function:
| ------------------ | ----------------------------------------------------------------------------------------------------------------- |
| **`data`** | The data of the Document being edited. This includes changes that have not yet been saved. |
| **`locale`** | The locale currently being edited (if applicable). [More details](../configuration/localization). |
| **`collectionConfig`** | The Collection Admin Config of the Document being edited. [More details](../configuration/collections#admin-options). |
| **`globalConfig`** | The Global Admin Config of the Document being edited. [More details](../configuration/globals#admin-options). |
| **`collectionConfig`** | The Collection Admin Config of the Document being edited. [More details](../admin/collections). |
| **`globalConfig`** | The Global Admin Config of the Document being edited. [More details](../admin/globals). |
| **`req`** | The Payload Request object. |
You can return either an absolute URL or relative URL from this function. If you don't know the URL of your frontend at build-time, you can return a relative URL, and in that case, Payload will automatically construct an absolute URL by injecting the protocol, domain, and port from your browser window. Returning a relative URL is helpful for platforms like Vercel where you may have preview deployment URLs that are unknown at build time.
If your application requires a fully qualified URL, or you are attempting to preview with a frontend on a different domain, you can use the `req` property to build this URL:
If your application requires a fully qualified URL, such as within deploying to Vercel Preview Deployments, you can use the `req` property to build this URL:
```ts
url: ({ data, req }) => `${req.protocol}//${req.host}/${data.slug}` // highlight-line
url: (doc, { req }) => `${req.protocol}//${req.host}/${doc.slug}` // highlight-line
```
### Breakpoints

View File

@@ -19,7 +19,7 @@ Here are some common examples of how you can use the Local API:
- Fetching Payload data within React Server Components
- Seeding data via Node seed scripts that you write and maintain
- Opening custom Next.js route handlers which feature additional functionality but still rely on Payload
- Within [Access Control](../access-control/overview) and [Hooks](../hooks/overview)
- Within [Access Control](../access-control) and [Hooks](../hooks/overview)
## Accessing Payload
@@ -345,7 +345,8 @@ const result = await payload.login({
email: 'dev@payloadcms.com',
password: 'rip',
},
req: req, // optional, pass a Request object to be provided to all hooks
req: req, // pass a Request object to be provided to all hooks
res: res, // used to automatically set an HTTP-only auth cookie
depth: 2,
locale: 'en',
fallbackLocale: false,
@@ -383,7 +384,8 @@ const result = await payload.resetPassword({
password: req.body.password, // the new password to set
token: 'afh3o2jf2p3f...', // the token generated from the forgotPassword operation
},
req: req, // optional, pass a Request object to be provided to all hooks
req: req, // pass a Request object to be provided to all hooks
res: res, // used to automatically set an HTTP-only auth cookie
})
```
@@ -397,7 +399,7 @@ const result = await payload.unlock({
// required
email: 'dev@payloadcms.com',
},
req: req, // optional, pass a Request object to be provided to all hooks
req: req, // pass a Request object to be provided to all hooks
overrideAccess: true,
})
```

View File

@@ -443,7 +443,7 @@ For more details, see the [Documentation](https://payloadcms.com/docs/getting-st
})
```
For more details, see the [Documentation](https://payloadcms.com/docs/custom-components/overview#component-paths).
For more details, see the [Documentation](https://payloadcms.com/docs/admin/components#component-paths).
1. All Custom Components are now server-rendered by default, and therefore, cannot use state or hooks directly. If youre using Custom Components in your app that requires state or hooks, add the `'use client'` directive at the top of the file.
@@ -463,7 +463,7 @@ For more details, see the [Documentation](https://payloadcms.com/docs/getting-st
}
```
For more details, see the [Documentation](https://payloadcms.com/docs/custom-components/overview#client-components).
For more details, see the [Documentation](https://payloadcms.com/docs/admin/components#client-components).
1. The `admin.description` property within Collection, Globals, and Fields no longer accepts a React Component. Instead, you must define it as a Custom Component.
@@ -854,7 +854,7 @@ For more details, see the [Documentation](https://payloadcms.com/docs/getting-st
}
```
For more details, see the [Documentation](https://payloadcms.com/docs/admin/custom-components/overview#accessing-the-payload-config).
For more details, see the [Documentation](https://payloadcms.com/docs/admin/components#accessing-the-payload-config).
1. The `useCollapsible` hook has had slight changes to its property names. `collapsed` is now `isCollapsed` and `withinCollapsible` is now `isWithinCollapsible`.
@@ -1102,7 +1102,7 @@ plugins: [
## `@payloadcms/richtext-lexical`
If you have custom features for `@payloadcms/richtext-lexical` you will need to migrate your code to the new API. Read more about the new API in the [documentation](https://payloadcms.com/docs/rich-text/building-custom-features).
If you have custom features for `@payloadcms/richtext-lexical` you will need to migrate your code to the new API. Read more about the new API in the [documentation](https://payloadcms.com/docs/lexical/building-custom-features).
## Upgrade from previous beta

View File

@@ -6,7 +6,7 @@ desc: Easily build and manage forms from the Admin Panel. Send dynamic, personal
keywords: plugins, plugin, form, forms, form builder
---
![https://www.npmjs.com/package/@payloadcms/plugin-form-builder](https://img.shields.io/npm/v/@payloadcms/plugin-form-builder)
[![npm](https://img.shields.io/npm/v/@payloadcms/plugin-form-builder)](https://www.npmjs.com/package/@payloadcms/plugin-form-builder)
This plugin allows you to build and manage custom forms directly within the [Admin Panel](../admin/overview). Instead of hard-coding a new form into your website or application every time you need one, admins can simply define the schema for each form they need on-the-fly, and your front-end can map over this schema, render its own UI components, and match your brand's design system.

View File

@@ -6,7 +6,7 @@ desc: Scaffolds multi-tenancy for your Payload application
keywords: plugins, multi-tenant, multi-tenancy, plugin, payload, cms, seo, indexing, search, search engine
---
![https://www.npmjs.com/package/@payloadcms/plugin-multi-tenant](https://img.shields.io/npm/v/@payloadcms/plugin-multi-tenant)
[![npm](https://img.shields.io/npm/v/@payloadcms/plugin-multi-tenants)](https://www.npmjs.com/package/@payloadcms/plugin-multi-tenants)
This plugin sets up multi-tenancy for your application from within your [Admin Panel](../admin/overview). It does so by adding a `tenant` field to all specified collections. Your front-end application can then query data by tenant. You must add the Tenants collection so you control what fields are available for each tenant.
@@ -25,25 +25,13 @@ This plugin sets up multi-tenancy for your application from within your [Admin P
- Adds a `tenant` field to each specified collection
- Adds a tenant selector to the admin panel, allowing you to switch between tenants
- Filters list view results by selected tenant
- Filters relationship fields by selected tenant
- Ability to create "global" like collections, 1 doc per tenant
- Automatically assign a tenant to new documents
<Banner type="error">
**Warning**
By default this plugin cleans up documents when a tenant is deleted. You should ensure you have
strong access control on your tenants collection to prevent deletions by unauthorized users.
You can disabled this behavior by setting `cleanupAfterTenantDelete` to `false` in the plugin options.
</Banner>
## Installation
Install the plugin using any JavaScript package manager like [pnpm](https://pnpm.io), [npm](https://npmjs.com), or [Yarn](https://yarnpkg.com):
```bash
pnpm add @payloadcms/plugin-multi-tenant
pnpm add @payloadcms/plugin-multi-tenant@beta
```
### Options
@@ -52,7 +40,7 @@ The plugin accepts an object with the following properties:
```ts
type MultiTenantPluginConfig<ConfigTypes = unknown> = {
/**
/**
* After a tenant is deleted, the plugin will attempt to clean up related documents
* - removing documents with the tenant ID
* - removing the tenant from users
@@ -122,18 +110,6 @@ type MultiTenantPluginConfig<ConfigTypes = unknown> = {
* Access configuration for the array field
*/
arrayFieldAccess?: ArrayField['access']
/**
* Name of the array field
*
* @default 'tenants'
*/
arrayFieldName?: string
/**
* Name of the tenant field
*
* @default 'tenant'
*/
arrayTenantFieldName?: string
/**
* When `includeDefaultField` is `true`, the field will be added to the users collection automatically
*/
@@ -149,8 +125,6 @@ type MultiTenantPluginConfig<ConfigTypes = unknown> = {
}
| {
arrayFieldAccess?: never
arrayFieldName?: string
arrayTenantFieldName?: string
/**
* When `includeDefaultField` is `false`, you must include the field on your users collection manually
*/
@@ -170,12 +144,8 @@ type MultiTenantPluginConfig<ConfigTypes = unknown> = {
* Useful for super-admin type users
*/
userHasAccessToAllTenants?: (
user: ConfigTypes extends { user: unknown } ? ConfigTypes['user'] : User,
user: ConfigTypes extends { user } ? ConfigTypes['user'] : User,
) => boolean
/**
* Opt out of adding access constraints to the tenants collection
*/
useTenantsCollectionAccess?: boolean
}
```

View File

@@ -6,7 +6,7 @@ desc: Nested documents in a parent, child, and sibling relationship.
keywords: plugins, nested, documents, parent, child, sibling, relationship
---
![https://www.npmjs.com/package/@payloadcms/plugin-nested-docs](https://img.shields.io/npm/v/@payloadcms/plugin-nested-docs)
[![npm](https://img.shields.io/npm/v/@payloadcms/plugin-nested-docs)](https://www.npmjs.com/package/@payloadcms/plugin-nested-docs)
This plugin allows you to easily nest the documents of your application inside of one another. It does so by adding a
new `parent` field onto each of your documents that, when selected, attaches itself to the parent's tree. When you edit

View File

@@ -6,7 +6,7 @@ desc: Plugins provide a great way to modularize Payload functionalities into eas
keywords: plugins, config, configuration, extensions, custom, documentation, Content Management System, cms, headless, javascript, node, react, nextjs
---
Payload Plugins take full advantage of the modularity of the [Payload Config](../configuration/overview), allowing developers to easily inject custom—sometimes complex—functionality into Payload apps from a very small touch-point. This is especially useful for sharing your work across multiple projects or with the greater Payload community.
Payload Plugins take full advantage of the modularity of the [Payload Config](../configuration/overview), allowing developers developers to easily inject custom—sometimes complex—functionality into Payload apps from a very small touch-point. This is especially useful is sharing your work across multiple projects or with the greater Payload community.
There are many [Official Plugins](#official-plugins) available that solve for some of the most common uses cases, such as the [Form Builder Plugin](./form-builder) or [SEO Plugin](./seo). There are also [Community Plugins](#community-plugins) available, maintained entirely by contributing members. To extend Payload's functionality in some other way, you can easily [build your own plugin](./build-your-own).

View File

@@ -6,7 +6,7 @@ desc: Automatically create redirects for your Payload application
keywords: plugins, redirects, redirect, plugin, payload, cms, seo, indexing, search, search engine
---
![https://www.npmjs.com/package/@payloadcms/plugin-redirects](https://img.shields.io/npm/v/@payloadcms/plugin-redirects)
[![npm](https://img.shields.io/npm/v/@payloadcms/plugin-redirects)](https://www.npmjs.com/package/@payloadcms/plugin-redirects)
This plugin allows you to easily manage redirects for your application from within your [Admin Panel](../admin/overview). It does so by adding a `redirects` collection to your config that allows you specify a redirect from one URL to another. Your front-end application can use this data to automatically redirect users to the correct page using proper HTTP status codes. This is useful for SEO, indexing, and search engine ranking when re-platforming or when changing your URL structure.

View File

@@ -6,7 +6,7 @@ desc: Generates records of your documents that are extremely fast to search on.
keywords: plugins, search, search plugin, search engine, search index, search results, search bar, search box, search field, search form, search input
---
![https://www.npmjs.com/package/@payloadcms/plugin-search](https://img.shields.io/npm/v/@payloadcms/plugin-search)
[![npm](https://img.shields.io/npm/v/@payloadcms/plugin-search)](https://www.npmjs.com/package/@payloadcms/plugin-search)
This plugin generates records of your documents that are extremely fast to search on. It does so by creating a new `search` collection that is indexed in the database then saving a static copy of each of your documents using only search-critical data. Search records are automatically created, synced, and deleted behind-the-scenes as you manage your application's documents.

View File

@@ -6,7 +6,7 @@ desc: Integrate Sentry error tracking into your Payload application
keywords: plugins, sentry, error, tracking, monitoring, logging, bug, reporting, performance
---
![https://www.npmjs.com/package/@payloadcms/plugin-sentry](https://img.shields.io/npm/v/@payloadcms/plugin-sentry)
[![npm](https://img.shields.io/npm/v/@payloadcms/plugin-sentry)](https://www.npmjs.com/package/@payloadcms/plugin-sentry)
This plugin allows you to integrate [Sentry](https://sentry.io/) seamlessly with your [Payload](https://github.com/payloadcms/payload) application.

View File

@@ -6,7 +6,7 @@ desc: Easily accept payments with Stripe
keywords: plugins, stripe, payments, ecommerce
---
![https://www.npmjs.com/package/@payloadcms/plugin-stripe](https://img.shields.io/npm/v/@payloadcms/plugin-stripe)
[![npm](https://img.shields.io/npm/v/@payloadcms/plugin-stripe)](https://www.npmjs.com/package/@payloadcms/plugin-stripe)
With this plugin you can easily integrate [Stripe](https://stripe.com) into Payload. Simply provide your Stripe credentials and this plugin will open up a two-way communication channel between the two platforms. This enables you to easily sync data back and forth, as well as proxy the Stripe REST API through Payload's [Access Control](../access-control/overview). Use this plugin to completely offload billing to Stripe and retain full control over your application's data.

View File

@@ -101,7 +101,8 @@ unsupported `$facet` aggregation.
### CosmosDB
When using Azure Cosmos DB, an index is needed for any field you may want to sort on. To add the sort index for all
fields that may be sorted in the admin UI use the [indexSortableFields](/docs/configuration/overview) option.
fields that may be sorted in the admin UI use the <a href="/docs/configuration/overview">indexSortableFields</a>
configuration option.
## File storage

View File

@@ -28,7 +28,7 @@ To securely allow headless operation you will need to configure the allowed orig
## Limiting GraphQL Complexity
Because GraphQL gives the power of query writing outside a server's control, someone with bad intentions might write a maliciously complex query and bog down your server. To prevent resource-intensive GraphQL requests, Payload provides a way to specify complexity limits. These limits are based on a complexity score calculated for each request.
Because GraphQL gives the power of query writing outside a server's control, someone with bad intentions might write a maliciously complex query and bog down your server. To prevent resource-intensive GraphQL requests, Payload provides a way specify complexity limits which are based on a complexity score that is calculated for each request.
Any GraphQL request that is calculated to be too expensive is rejected. On the Payload Config, in `graphQL` you can set the `maxComplexity` value as an integer. For reference, the default complexity value for each added field is 1, and all `relationship` and `upload` fields are assigned a value of 10.

View File

@@ -39,23 +39,23 @@ _The exact query syntax will depend on the API you are using, but the concepts a
The following operators are available for use in queries:
| Operator | Description |
| -------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `equals` | The value must be exactly equal. |
| `not_equals` | The query will return all documents where the value is not equal. |
| `greater_than` | For numeric or date-based fields. |
| `greater_than_equal` | For numeric or date-based fields. |
| `less_than` | For numeric or date-based fields. |
| `less_than_equal` | For numeric or date-based fields. |
| `like` | Case-insensitive string must be present. If string of words, all words must be present, in any order. |
| `contains` | Must contain the value entered, case-insensitive. |
| `in` | The value must be found within the provided comma-delimited list of values. |
| `not_in` | The value must NOT be within the provided comma-delimited list of values. |
| `all` | The value must contain all values provided in the comma-delimited list. Note: currently this operator is supported only with the MongoDB adapter. |
| `exists` | Only return documents where the value either exists (`true`) or does not exist (`false`). |
| `near` | For distance related to a [Point Field](../fields/point) comma separated as `<longitude>, <latitude>, <maxDistance in meters (nullable)>, <minDistance in meters (nullable)>`. |
| `within` | For [Point Fields](../fields/point) to filter documents based on whether points are inside of the given area defined in GeoJSON. [Example](../fields/point#querying-within) |
| `intersects` | For [Point Fields](../fields/point) to filter documents based on whether points intersect with the given area defined in GeoJSON. [Example](../fields/point#querying-intersects) |
| Operator | Description |
| -------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `equals` | The value must be exactly equal. |
| `not_equals` | The query will return all documents where the value is not equal. |
| `greater_than` | For numeric or date-based fields. |
| `greater_than_equal` | For numeric or date-based fields. |
| `less_than` | For numeric or date-based fields. |
| `less_than_equal` | For numeric or date-based fields. |
| `like` | Case-insensitive string must be present. If string of words, all words must be present, in any order. |
| `contains` | Must contain the value entered, case-insensitive. |
| `in` | The value must be found within the provided comma-delimited list of values. |
| `not_in` | The value must NOT be within the provided comma-delimited list of values. |
| `all` | The value must contain all values provided in the comma-delimited list. |
| `exists` | Only return documents where the value either exists (`true`) or does not exist (`false`). |
| `near` | For distance related to a [Point Field](../fields/point) comma separated as `<longitude>, <latitude>, <maxDistance in meters (nullable)>, <minDistance in meters (nullable)>`. |
| `within` | For [Point Fields](../fields/point) to filter documents based on whether points are inside of the given area defined in GeoJSON. [Example](../fields/point#querying-within) |
| `intersects` | For [Point Fields](../fields/point) to filter documents based on whether points intersect with the given area defined in GeoJSON. [Example](../fields/point#querying-intersects) |
<Banner type="success">
**Tip:**

View File

@@ -138,7 +138,7 @@ export const Pages: CollectionConfig<'pages'> = {
```
<Banner type="warning">
**Important:**
<strong>Important:</strong>
When using `defaultPopulate` on a collection with [Uploads](/docs/fields/upload) enabled and you want to select the `url` field, it is important to specify `filename: true` as well, otherwise Payload will not be able to construct the correct file URL, instead returning `url: null`.
</Banner>

View File

@@ -20,11 +20,6 @@ All Payload API routes are mounted and prefixed to your config's `routes.api` UR
- [fallback-locale](/docs/configuration/localization#retrieving-localized-docs) - specifies a fallback locale if no locale value exists
- [select](../queries/select) - specifies which fields to include to the result
- [populate](../queries/select#populate) - specifies which fields to include to the result from populated documents
- [limit](../queries/pagination#pagination-controls) - limits the number of documents returned
- [page](../queries/pagination#pagination-controls) - specifies which page to get documents from when used with a limit
- [sort](../queries/sort#rest-api) - specifies the field(s) to use to sort the returned documents by
- [where](../queries/overview) - specifies advanced filters to use to query documents
- [joins](/docs/fields/join#rest-api) - specifies the custom request for each join field by name of the field
## Collections
@@ -578,7 +573,7 @@ Each endpoint object needs to have:
| ------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **`path`** | A string for the endpoint route after the collection or globals slug |
| **`method`** | The lowercase HTTP verb to use: 'get', 'head', 'post', 'put', 'delete', 'connect' or 'options' |
| **`handler`** | A function that accepts **req** - `PayloadRequest` object which contains [Web Request](https://developer.mozilla.org/en-US/docs/Web/API/Request) properties, currently authenticated `user` and the Local API instance `payload`. |
| **`handler`** | A function or array of functions to be called with **req**, **res** and **next** arguments. [Next.js](https://nextjs.org/docs/app/building-your-application/routing/route-handlers) |
| **`root`** | When `true`, defines the endpoint on the root Next.js app, bypassing Payload handlers and the `routes.api` subpath. Note: this only applies to top-level endpoints of your Payload Config, endpoints defined on `collections` or `globals` cannot be root. |
| **`custom`** | Extension point for adding custom data (e.g. for plugins) |
@@ -663,7 +658,7 @@ Data is not automatically appended to the request. You can read the body data by
Or you could use our helper function that mutates the request and appends data and file if found.
```ts
import { addDataAndFileToRequest } from 'payload'
import { addDataAndFileToRequest } from '@payloadcms/next/utilities'
// custom endpoint example
{
@@ -689,7 +684,7 @@ import { addDataAndFileToRequest } from 'payload'
The locale and the fallback locale are not automatically appended to custom endpoint requests. If you would like to add them you can use this helper function.
```ts
import { addLocalesToRequestFromData } from 'payload'
import { addLocalesToRequestFromData } from '@payloadcms/next/utilities'
// custom endpoint example
{

View File

@@ -1,8 +1,8 @@
---
title: Custom Features
title: Lexical Building Custom Features
label: Custom Features
order: 40
desc: Building custom features
desc: Building custom lexical features
keywords: lexical, rich text, editor, headless cms, feature, features
---
@@ -409,7 +409,7 @@ Explore the APIs available through ClientFeature to add the specific functionali
### Adding a client feature to the server feature
Inside of your server feature, you can provide an [import path](/docs/admin/custom-components/overview#component-paths) to the client feature like this:
Inside of your server feature, you can provide an [import path](/docs/admin/components#component-paths) to the client feature like this:
```ts
import { createServerFeature } from '@payloadcms/richtext-lexical';
@@ -614,7 +614,7 @@ import {
COMMAND_PRIORITY_EDITOR
} from '@payloadcms/richtext-lexical/lexical'
import { useLexicalComposerContext } from '@payloadcms/richtext-lexical/lexical/react/LexicalComposerContext'
import { useLexicalComposerContext } from '@payloadcms/richtext-lexical/lexical/react/LexicalComposerContext.js'
import { $insertNodeToNearestRoot } from '@payloadcms/richtext-lexical/lexical/utils'
import { useEffect } from 'react'

View File

@@ -51,10 +51,6 @@ const jsxConverters: JSXConvertersFunction = ({ defaultConverters }) => ({
// myTextBlock is the slug of the block
myTextBlock: ({ node }) => <div style={{ backgroundColor: 'red' }}>{node.fields.text}</div>,
},
inlineBlocks: {
// myInlineBlock is the slug of the block
myInlineBlock: ({ node }) => <span>{node.fields.text}</span>,
},
})
export const MyComponent = ({ lexicalData }) => {

View File

@@ -16,7 +16,7 @@ Just import the `migrateSlateToLexical` function we provide, pass it the `payloa
IMPORTANT: This will overwrite all slate data. We recommend doing the following first:
1. Take a backup of your entire database. If anything goes wrong and you do not have a backup, you are on your own and will not receive any support.
2. Make every richText field a lexical editor. This script will only convert lexical richText fields with old Slate data.
2. Make every richText field a lexical editor. This script will only convert lexical richText fields with old Slate data
3. Add the SlateToLexicalFeature (as seen below) first, and test it out by loading up the Admin Panel, to see if the migrator works as expected. You might have to build some custom converters for some fields first in order to convert custom Slate nodes. The SlateToLexicalFeature is where the converters are stored. Only fields with this feature added will be migrated.
4. If this works as expected, add the `disableHooks: true` prop everywhere you're initializing `SlateToLexicalFeature`. Example: `SlateToLexicalFeature({ disableHooks: true })`. Once you did that, you're ready to run the migration script.
@@ -67,7 +67,7 @@ If you have custom Slate nodes, create a custom converter for them. Here's the U
```ts
import type { SerializedUploadNode } from '../uploadNode'
import type { SlateNodeConverter } from '@payloadcms/richtext-lexical'
import type { SlateNodeConverter } from '@payloadcms/richtext-lexical/migrate'
export const SlateUploadConverter: SlateNodeConverter = {
converter({ slateNode }) {
@@ -90,7 +90,7 @@ export const SlateUploadConverter: SlateNodeConverter = {
It's pretty simple: You get a Slate node as input, and you return the lexical node. The `nodeTypes` array is used to determine which Slate nodes this converter can handle.
When using a migration script, you can add your custom converters to the `converters` property of the `convertSlateToLexical` props, as seen in the example above.
When using a migration script, you can add your custom converters to the `converters` property of the `convertSlateToLexical` props, as seen in the example above
When using the `SlateToLexicalFeature`, you can add your custom converters to the `converters` property of the `SlateToLexicalFeature` props:

View File

@@ -7,21 +7,21 @@ title: Rich Text Editor
---
<Banner type="success">
This documentation is about our new editor, based on Lexical (Meta's rich text editor). The previous default
editor was based on Slate and is still supported. You can read [its documentation](/docs/rich-text/slate),
or the optional [migration guide](/docs/rich-text/migration) to migrate from Slate to Lexical (recommended).
The Payload editor is based on Lexical, Meta's rich text editor. The previous default editor was based on Slate and is still supported. You can read [its documentation](../rich-text/slate), or the optional [migration guide](../rich-text/migration) to migrate from Slate to Lexical (recommended).
</Banner>
The editor is the most important property of the [rich text field](/docs/fields/rich-text).
One of Payload's goals is to build the best rich text editor experience that we possibly can. We want to combine the beauty and polish of the Medium editing experience with the strength and features of the Notion editor - all in one place.
As a key part of Payload, we are proud to offer you the best editing experience you can imagine. With healthy
defaults out of the box, but also with the flexibility to customize every detail: from the “/” menu
and toolbars (whether inline or fixed) to inserting any component or subfield you can imagine.
Classically, we've used SlateJS to work toward this goal, but building custom elements into Slate has proven to be more difficult than we'd like, and we've been keeping our options open.
Lexical is extremely impressive and trivializes a lot of the hard parts of building new elements into a rich text editor. It has a few distinct advantages over Slate, including the following:
To use the rich text editor, first you need to install it:
1. A "/" menu, which allows editors to easily add new elements while never leaving their keyboard
2. A "hover" toolbar that pops up if you select text
3. It supports Payload blocks natively, directly within your rich text editor
4. Custom elements, called "features", are much easier to build in Lexical vs. Slate
To use the Lexical editor, first you need to install it:
```bash
pnpm install @payloadcms/richtext-lexical
@@ -161,7 +161,7 @@ Here's an overview of all the included features:
| **`CheckListFeature`** | Yes | Adds checklists |
| **`LinkFeature`** | Yes | Allows you to create internal and external links |
| **`RelationshipFeature`** | Yes | Allows you to create block-level (not inline) relationships to other documents |
| **`BlockquoteFeature`** | Yes | Allows you to create block-level quotes |
| **`BlockQuoteFeature`** | Yes | Allows you to create block-level quotes |
| **`UploadFeature`** | Yes | Allows you to create block-level upload nodes - this supports all kinds of uploads, not just images |
| **`HorizontalRuleFeature`** | Yes | Horizontal rules / separators. Basically displays an `<hr>` element |
| **`InlineToolbarFeature`** | Yes | The inline toolbar is the floating toolbar which appears when you select text. This toolbar only contains actions relevant for selected text |
@@ -174,7 +174,7 @@ Notice how even the toolbars are features? That's how extensible our lexical edi
## Creating your own, custom Feature
You can find more information about creating your own feature in our [building custom feature docs](../rich-text/custom-features).
You can find more information about creating your own feature in our [building custom feature docs](../rich-text/building-custom-features).
## TypeScript

View File

@@ -6,13 +6,9 @@ desc: The Slate editor has been supported by Payload since beta. It's very power
keywords: slatejs, slate, rich text, editor, headless cms
---
<Banner type="warning">
The Slate editor has been supported by Payload since we released our initial beta. It's battle-tested and will continue to be supported into the future.
The [default Payload editor](/docs/rich-text/overview) is currently based on Lexical. This documentation
is about our old Slate-based editor. You can continue using it because it is still supported, or you can
see the optional [migration guide](/docs/rich-text/migration) to migrate from Slate to Lexical (recommended).
</Banner>
If you are migrating a Payload project from 1.x or earlier, you can continue to use the Slate editor as long as you'd like.
To use the Slate editor, first you need to install it:

View File

@@ -6,7 +6,7 @@ desc: Generate your own TypeScript interfaces based on your collections and glob
keywords: headless cms, typescript, documentation, Content Management System, cms, headless, javascript, node, react, nextjs
---
While building your own custom functionality into Payload, like [Plugins](../plugins/overview), [Hooks](../hooks/overview), [Access Control](../access-control/overview) functions, [Custom Views](../custom-components/custom-views), [GraphQL queries / mutations](../graphql/overview), or anything else, you may benefit from generating your own TypeScript types dynamically from your Payload Config itself.
While building your own custom functionality into Payload, like [Plugins](../plugins/overview), [Hooks](../hooks/overview), [Access Control](../access-control/overview) functions, [Custom Views](../admin/views), [GraphQL queries / mutations](../graphql/overview), or anything else, you may benefit from generating your own TypeScript types dynamically from your Payload Config itself.
## Types generation script

View File

@@ -20,7 +20,7 @@ It's also possible to set up a TypeScript project from scratch. We plan to write
## Using Payload's Exported Types
Payload exports a number of types that you may find useful while writing your own custom functionality like [Plugins](../plugins/overview), [Hooks](../hooks/overview), [Access Control](../access-control/overview) functions, [Custom Views](../custom-components/custom-views), [GraphQL queries / mutations](../graphql/overview) or anything else.
Payload exports a number of types that you may find useful while writing your own custom functionality like [Plugins](../plugins/overview), [Hooks](../hooks/overview), [Access Control](../access-control/overview) functions, [Custom Views](../admin/views), [GraphQL queries / mutations](../graphql/overview) or anything else.
## Config Types

View File

@@ -88,51 +88,31 @@ export const Media: CollectionConfig = {
_An asterisk denotes that an option is required._
| Option | Description |
|--------------------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| **`adminThumbnail`** | Set the way that the [Admin Panel](../admin/overview) will display thumbnails for this Collection. [More](#admin-thumbnails) |
| **`bulkUpload`** | Allow users to upload in bulk from the list view, default is true |
| **`cacheTags`** | Set to `false` to disable the cache tag set in the UI for the admin thumbnail component. Useful for when CDNs don't allow certain cache queries. |
| **`crop`** | Set to `false` to disable the cropping tool in the [Admin Panel](../admin/overview). Crop is enabled by default. [More](#crop-and-focal-point-selector) |
| **`disableLocalStorage`** | Completely disable uploading files to disk locally. [More](#disabling-local-upload-storage) |
| **`displayPreview`** | Enable displaying preview of the uploaded file in Upload fields related to this Collection. Can be locally overridden by `displayPreview` option in Upload field. [More](/docs/fields/upload#config-options). |
| **`externalFileHeaderFilter`** | Accepts existing headers and returns the headers after filtering or modifying. |
| **`filesRequiredOnCreate`** | Mandate file data on creation, default is true. |
| **`filenameCompoundIndex`** | Field slugs to use for a compound index instead of the default filename index. |
| **`focalPoint`** | Set to `false` to disable the focal point selection tool in the [Admin Panel](../admin/overview). The focal point selector is only available when `imageSizes` or `resizeOptions` are defined. [More](#crop-and-focal-point-selector) |
| **`formatOptions`** | An object with `format` and `options` that are used with the Sharp image library to format the upload file. [More](https://sharp.pixelplumbing.com/api-output#toformat) |
| **`handlers`** | Array of Request handlers to execute when fetching a file, if a handler returns a Response it will be sent to the client. Otherwise Payload will retrieve and send back the file. |
| **`imageSizes`** | If specified, image uploads will be automatically resized in accordance to these image sizes. [More](#image-sizes) |
| **`mimeTypes`** | Restrict mimeTypes in the file picker. Array of valid mimetypes or mimetype wildcards [More](#mimetypes) |
| **`pasteURL`** | Controls whether files can be uploaded from remote URLs by pasting them into the Upload field. **Enabled by default.** Accepts `false` to disable or an object with an `allowList` of valid remote URLs. [More](#uploading-files-from-remote-urls) |
| **`resizeOptions`** | An object passed to the the Sharp image library to resize the uploaded file. [More](https://sharp.pixelplumbing.com/api-resize) |
| **`staticDir`** | The folder directory to use to store media in. Can be either an absolute path or relative to the directory that contains your config. Defaults to your collection slug |
| **`trimOptions`** | An object passed to the the Sharp image library to trim the uploaded file. [More](https://sharp.pixelplumbing.com/api-resize#trim) |
| **`withMetadata`** | If specified, appends metadata to the output image file. Accepts a boolean or a function that receives `metadata` and `req`, returning a boolean. |
| **`hideFileInputOnCreate`** | Set to `true` to prevent the admin UI from showing file inputs during document creation, useful for programmatic file generation. |
| **`hideRemoveFile`** | Set to `true` to prevent the admin UI having a way to remove an existing file while editing. |
| Option | Description |
| ------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **`adminThumbnail`** | Set the way that the [Admin Panel](../admin/overview) will display thumbnails for this Collection. [More](#admin-thumbnails) |
| **`bulkUpload`** | Allow users to upload in bulk from the list view, default is true |
| **`cacheTags`** | Set to `false` to disable the cache tag set in the UI for the admin thumbnail component. Useful for when CDNs don't allow certain cache queries. |
| **`crop`** | Set to `false` to disable the cropping tool in the [Admin Panel](../admin/overview). Crop is enabled by default. [More](#crop-and-focal-point-selector) |
| **`disableLocalStorage`** | Completely disable uploading files to disk locally. [More](#disabling-local-upload-storage) |
| **`displayPreview`** | Enable displaying preview of the uploaded file in Upload fields related to this Collection. Can be locally overridden by `displayPreview` option in Upload field. [More](/docs/fields/upload#config-options). |
| **`externalFileHeaderFilter`** | Accepts existing headers and returns the headers after filtering or modifying. |
| **`filesRequiredOnCreate`** | Mandate file data on creation, default is true. |
| **`filenameCompoundIndex`** | Field slugs to use for a compound index instead of the default filename index. |
| **`focalPoint`** | Set to `false` to disable the focal point selection tool in the [Admin Panel](../admin/overview). The focal point selector is only available when `imageSizes` or `resizeOptions` are defined. [More](#crop-and-focal-point-selector) |
| **`formatOptions`** | An object with `format` and `options` that are used with the Sharp image library to format the upload file. [More](https://sharp.pixelplumbing.com/api-output#toformat) |
| **`handlers`** | Array of Request handlers to execute when fetching a file, if a handler returns a Response it will be sent to the client. Otherwise Payload will retrieve and send back the file. |
| **`imageSizes`** | If specified, image uploads will be automatically resized in accordance to these image sizes. [More](#image-sizes) |
| **`mimeTypes`** | Restrict mimeTypes in the file picker. Array of valid mimetypes or mimetype wildcards [More](#mimetypes) |
| **`resizeOptions`** | An object passed to the the Sharp image library to resize the uploaded file. [More](https://sharp.pixelplumbing.com/api-resize) |
| **`staticDir`** | The folder directory to use to store media in. Can be either an absolute path or relative to the directory that contains your config. Defaults to your collection slug |
| **`trimOptions`** | An object passed to the the Sharp image library to trim the uploaded file. [More](https://sharp.pixelplumbing.com/api-resize#trim) |
| **`withMetadata`** | If specified, appends metadata to the output image file. Accepts a boolean or a function that receives `metadata` and `req`, returning a boolean. |
### Payload-wide Upload Options
Upload options are specifiable on a Collection by Collection basis, you can also control app wide options by passing your base Payload Config an `upload` property containing an object supportive of all `Busboy` configuration options.
| Option | Description |
| ------------------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **`abortOnLimit`** | A boolean that, if `true`, returns HTTP 413 if a file exceeds the file size limit. If `false`, the file is truncated. Defaults to `false`. |
| **`createParentPath`** | Set to `true` to automatically create a directory path when moving files from a temporary directory or buffer. Defaults to `false`. |
| **`debug`** | A boolean that turns upload process logging on if `true`, or off if `false`. Useful for troubleshooting. Defaults to `false`. |
| **`limitHandler`** | A function which is invoked if the file is greater than configured limits. |
| **`parseNested`** | Set to `true` to turn `req.body` and `req.files` into nested structures. By default `req.body` and `req.files` are flat objects. Defaults to `false`. |
| **`preserveExtension`** | Preserves file extensions with the `safeFileNames` option. Limits file names to 3 characters if `true` or a custom length if a `number`, trimming from the start of the extension. |
| **`responseOnLimit`** | A `string` that is sent in the Response to a client if the file size limit is exceeded when used with `abortOnLimit`. |
| **`safeFileNames`** | Set to `true` to strip non-alphanumeric characters except dashes and underscores. Can also be set to a regex to determine what to strip. Defaults to `false`. |
| **`tempFileDir`** | A `string` path to store temporary files used when the `useTempFiles` option is set to `true`. Defaults to `'./tmp'`. |
| **`uploadTimeout`** | A `number` that defines how long to wait for data before aborting, specified in milliseconds. Set to `0` to disable timeout checks. Defaults to `60000`. |
| **`uriDecodeFileNames`** | Set to `true` to apply uri decoding to file names. Defaults to `false`. |
| **`useTempFiles`** | Set to `true` to store files to a temporary directory instead of in RAM, reducing memory usage for large files or many files. |
[Click here](https://github.com/mscdex/busboy#api) for more documentation about what you can control with `Busboy`.
Upload options are specifiable on a Collection by Collection basis, you can also control app wide options by passing your base Payload Config an `upload` property containing an object supportive of all `Busboy` configuration options. [Click here](https://github.com/mscdex/busboy#api) for more documentation about what you can control.
A common example of what you might want to customize within Payload-wide Upload options would be to increase the allowed `fileSize` of uploads sent to Payload:
@@ -347,64 +327,6 @@ fetch('api/:upload-slug', {
})
```
## Uploading Files from Remote URLs
The `pasteURL` option allows users to fetch files from remote URLs by pasting them into an Upload field. This option is **enabled by default** and can be configured to either **allow unrestricted client-side fetching** or **restrict server-side fetching** to specific trusted domains.
By default, Payload uses **client-side fetching**, where the browser downloads the file directly from the provided URL. However, **client-side fetching will fail if the URLs server has CORS restrictions**, making it suitable only for internal URLs or public URLs without CORS blocks.
To fetch files from **restricted URLs** that would otherwise be blocked by CORS, use **server-side fetching** by configuring the `pasteURL` option with an `allowList` of trusted domains. This method ensures that Payload downloads the file on the server and streams it to the browser. However, for security reasons, only URLs that match the specified `allowList` will be allowed.
#### Configuration Example
Heres how to configure the pasteURL option to control remote URL fetching:
```
import type { CollectionConfig } from 'payload'
export const Media: CollectionConfig = {
slug: 'media',
upload: {
pasteURL: {
allowList: [
{
hostname: 'payloadcms.com', // required
pathname: '',
port: '',
protocol: 'https',
search: ''
},
{
hostname: 'example.com',
pathname: '/images/*',
},
],
},
},
}
```
##### Accepted Values for `pasteURL`
| Option | Description |
| --------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **`undefined`** | Default behavior. Enables client-side fetching for internal or public URLs. |
| **`false`** | Disables the ability to paste URLs into Upload fields. |
| **`allowList`** | Enables server-side fetching for specific trusted URLs. Requires an array of objects defining trusted domains. See the table below for details on `AllowItem`. |
##### `AllowItem` Properties
_An asterisk denotes that an option is required._
| Option | Description | Example |
| ---------------- | ---------------------------------------------------------------------------------------------------- | ------------- |
| **`hostname`** * | The hostname of the allowed URL. This is required to ensure the URL is coming from a trusted source. | `example.com` |
| **`pathname`** | The path portion of the URL. Supports wildcards to match multiple paths. | `/images/*` |
| **`port`** | The port number of the URL. If not specified, the default port for the protocol will be used. | `3000` |
| **`protocol`** | The protocol to match. Must be either `http` or `https`. Defaults to `https`. | `https` |
| **`search`** | The query string of the URL. If specified, the URL must match this exact query string. | `?version=1` |
## Access Control
All files that are uploaded to each Collection automatically support the `read` [Access Control](/docs/access-control/overview) function from the Collection itself. You can use this to control who should be allowed to see your uploads, and who should not.

View File

@@ -19,11 +19,8 @@ export const defaultESLintIgnores = [
'**/build/',
'**/node_modules/',
'**/temp/',
'packages/**/*.spec.ts',
'**/*.spec.ts',
'next-env.d.ts',
'**/app',
'src/**/*.spec.ts',
'**/jest.setup.js',
]
/** @typedef {import('eslint').Linter.Config} Config */
@@ -31,7 +28,10 @@ export const defaultESLintIgnores = [
export const rootParserOptions = {
sourceType: 'module',
ecmaVersion: 'latest',
projectService: true,
projectService: {
maximumDefaultProjectFileMatchCount_THIS_WILL_SLOW_DOWN_LINTING: 40,
allowDefaultProject: ['scripts/*.ts', '*.js', '*.mjs', '*.d.ts'],
},
}
/** @type {Config[]} */
@@ -68,14 +68,6 @@ export const rootEslintConfig = [
'perfectionist/sort-objects': 'off',
},
},
{
files: ['tools/**/*.ts'],
rules: {
'no-console': 'off',
'perfectionist/sort-object-types': 'off',
'perfectionist/sort-objects': 'off',
},
},
]
export default [

Some files were not shown because too many files have changed in this diff Show More