Skip to content

Regression: conditional fields in Lexical blocks don't maintain state #14359

@immotus

Description

@immotus

Describe the Bug

Here's a simple configuration, where the presence of an upload field depends on a certain condition, i.e. select option:

const getFields = (): Field[] => [
  {
    type: "select",
    name: "style",
    options: [
      { label: "Style A - no image", value: "style-no-image" },
      { label: "Style B - with image", value: "style-with-image" },
    ],
    defaultValue: "style-no-image",
    required: true,
  },
  {
    type: "upload",
    name: "image",
    relationTo: "media",
    required: true,
    filterOptions: {
      mimeType: { contains: "image" },
    },
    admin: {
      condition: (_data: any, siblingData: any) => siblingData?.["style"] === "style-with-image",
    }
  },
];

The code above is straightforward and works as expected in a CollectionConfig, i.e. it displays the required upload field only when the "Style B - with image" option is selected.

For example, these fields are embedded in a group:

{
  type: "group",
  name: "in-a-group",
  fields: getFields(),
},

However, if the same is done as part of a Block embedded in a Lexical editor, something weird happens when you open the file selection drawer for the Upload field. My preliminary digging shows that Lexical appears to lose the state of the block, including both the select field and the upload field. It is probably just the select field that loses its state, and as a result, the admin.condition on the upload field becomes unsatisfied, and Payload just kills off the field altogether. Further, as a result of that, the selection drawer disappears, leaving the invisible overlay, which blocks the rest of the UI. See the attached video clip.

For example:

export const TestBlock: Block = {
  slug: "test-block",
  fields: getFields(),
};

as part of:

{
  name: "content",
  type: "richText",
  editor: lexicalEditor({
    features: ({ defaultFeatures }) => [
      ...defaultFeatures,
      BlocksFeature({
        blocks: [
          TestBlock,
        ],
      })
    ],
  }),
},
Video_2025-10-26_231914.mp4

Link to the code that reproduces this issue

https://github.com/immotus/bug-lexical-block-state

Reproduction Steps

  1. Clone the repo
  2. pnpm dev
  3. Go to localhost:3000
  4. Seed the test database
  5. Go to the "Test" collection and create a new document
  6. "In A Group" section, choose "Style B - with image", then in the appeared Upload field choose an image — should work just fine.
  7. Then, in the Lexical editor below, type /Test Block to insert the Test Block of the same structure.
  8. Choose "Style B - with image", then in the appeared Upload field choose an image — the selection drawer will appear.
  9. Now, do anything in the drawer, e.g., go to another page if you have enough uploads, change the list of displayed columns, or change the "Per Page" value — IT WILL KILL THE DRAWER AND leave the UI in an unusable/unclickable state. Yes, it is also quite inconsistent, so fiddle with basic drawer functionality, and at some point, it will snap.

Which area(s) are affected? (Select all that apply)

area: ui

Environment Info

Binaries:
  Node: 24.8.0
  npm: N/A
  Yarn: N/A
  pnpm: 10.17.0
Relevant Packages:
  payload: 3.61.1
  next: 15.4.4
  @payloadcms/db-mongodb: 3.61.1
  @payloadcms/email-nodemailer: 3.61.1
  @payloadcms/graphql: 3.61.1
  @payloadcms/live-preview: 3.61.1
  @payloadcms/live-preview-react: 3.61.1
  @payloadcms/next/utilities: 3.61.1
  @payloadcms/payload-cloud: 3.61.1
  @payloadcms/plugin-form-builder: 3.61.1
  @payloadcms/plugin-nested-docs: 3.61.1
  @payloadcms/plugin-redirects: 3.61.1
  @payloadcms/plugin-search: 3.61.1
  @payloadcms/plugin-seo: 3.61.1
  @payloadcms/richtext-lexical: 3.61.1
  @payloadcms/translations: 3.61.1
  @payloadcms/ui/shared: 3.61.1
  react: 19.1.0
  react-dom: 19.1.0
Operating System:
  Platform: win32
  Arch: x64
  Version: Windows 11 Pro
  Available memory (MB): 32631
  Available CPU cores: 16

Metadata

Metadata

Assignees

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions