feat: conditional blocks (#13801)
This PR introduces support for conditionally setting allowable block types via a new `field.filterOptions` property on the blocks field. Closes the following feature requests: https://github.com/payloadcms/payload/discussions/5348, https://github.com/payloadcms/payload/discussions/4668 (partly) ## Example ```ts fields: [ { name: 'enabledBlocks', type: 'text', admin: { description: "Change the value of this field to change the enabled blocks of the blocksWithDynamicFilterOptions field. If it's empty, all blocks are enabled.", }, }, { name: 'blocksWithFilterOptions', type: 'blocks', filterOptions: ['block1', 'block2'], blocks: [ { slug: 'block1', fields: [ { type: 'text', name: 'block1Text', }, ], }, { slug: 'block2', fields: [ { type: 'text', name: 'block2Text', }, ], }, { slug: 'block3', fields: [ { type: 'text', name: 'block3Text', }, ], }, ], }, { name: 'blocksWithDynamicFilterOptions', type: 'blocks', filterOptions: ({ siblingData: _siblingData, data }) => { const siblingData = _siblingData as { enabledBlocks: string } if (siblingData?.enabledBlocks !== data?.enabledBlocks) { // Just an extra assurance that the field is working as intended throw new Error('enabledBlocks and siblingData.enabledBlocks must be identical') } return siblingData?.enabledBlocks?.length ? [siblingData.enabledBlocks] : true }, blocks: [ { slug: 'block1', fields: [ { type: 'text', name: 'block1Text', }, ], }, { slug: 'block2', fields: [ { type: 'text', name: 'block2Text', }, ], }, { slug: 'block3', fields: [ { type: 'text', name: 'block3Text', }, ], }, ], }, ] ``` https://github.com/user-attachments/assets/e38a804f-22fa-4fd2-a6af-ba9b0a5a04d2 # Rationale ## Why not `block.condition`? - Individual blocks are often reused in multiple contexts, where the logic for when they should be available may differ. It’s more appropriate for the blocks field (typically tied to a single collection) to determine availability. - Hiding existing blocks when they no longer satisfy a condition would cause issues - for example, reordering blocks would break or cause block data to disappear. Instead, this implementation ensures consistency by throwing a validation error if a block is no longer allowed. This aligns with the behavior of `filterOptions` in relationship fields, rather than `condition`. ## Why not call it `blocksFilterOptions`? Although the type differs from relationship fields, this property is named `filterOptions` (and not `blocksFilterOptions`) for consistency across field types. For example, the Select field also uses `filterOptions` despite its type being unique. --- - To see the specific tasks where the Asana app for GitHub is being used, see below: - https://app.asana.com/0/0/1211334752795631
This commit is contained in:
@@ -389,3 +389,34 @@ As you build your own Block configs, you might want to store them in separate fi
|
||||
```ts
|
||||
import type { Block } from 'payload'
|
||||
```
|
||||
|
||||
## Conditional Blocks
|
||||
|
||||
Blocks can be conditionally enabled using the `filterOptions` property on the blocks field. It allows you to provide a function that returns which block slugs should be available based on the given context.
|
||||
|
||||
### Behavior
|
||||
|
||||
- `filterOptions` is re-evaluated as part of the form state request, whenever the document data changes.
|
||||
- If a block is present in the field but no longer allowed by `filterOptions`, a validation error will occur when saving.
|
||||
|
||||
### Example
|
||||
|
||||
```ts
|
||||
{
|
||||
name: 'blocksWithDynamicFilterOptions',
|
||||
type: 'blocks',
|
||||
filterOptions: ({ siblingData }) => {
|
||||
return siblingData?.enabledBlocks?.length
|
||||
? [siblingData.enabledBlocks] // allow only the matching block
|
||||
: true // allow all blocks if no value is set
|
||||
},
|
||||
blocks: [
|
||||
{ slug: 'block1', fields: [{ type: 'text', name: 'block1Text' }] },
|
||||
{ slug: 'block2', fields: [{ type: 'text', name: 'block2Text' }] },
|
||||
{ slug: 'block3', fields: [{ type: 'text', name: 'block3Text' }] },
|
||||
// ...
|
||||
],
|
||||
}
|
||||
```
|
||||
|
||||
In this example, the list of available blocks is determined by the enabledBlocks sibling field. If no value is set, all blocks remain available.
|
||||
|
||||
Reference in New Issue
Block a user