Skip to content

feat(richtext-lexical): separate configuration for lexical block icons#15632

Merged
AlessioGr merged 12 commits intopayloadcms:mainfrom
VeiaG:feat/richtext-lexical-add-icon-image-url
Mar 2, 2026
Merged

feat(richtext-lexical): separate configuration for lexical block icons#15632
AlessioGr merged 12 commits intopayloadcms:mainfrom
VeiaG:feat/richtext-lexical-add-icon-image-url

Conversation

@VeiaG
Copy link
Copy Markdown
Contributor

@VeiaG VeiaG commented Feb 14, 2026

This PR adds a new images property to BlockConfig, allowing developers to specify separate images for different UI contexts:

  • images.icon — small icon displayed in Lexical editor slash menus and toolbars (20x20px)
  • images.thumbnail — larger thumbnail shown in the block selection drawer (3:2 aspect ratio)

Why

Currently, imageURL serves dual purposes:

  1. Block selection drawer thumbnails (3:2 aspect ratio, e.g., 480x320px)
  2. Lexical editor icons (scaled down to 20x20px)

Citing documentation:

Display Contexts:
Block Selection Drawer: Images appear as thumbnails in a responsive grid when editors add blocks
Lexical Editor: Images are scaled down to 20x20px icons in menus and toolbars

This creates problem , where developer needs to choose either good looking icons (but worse UX on block drawers) or good looking thumnails, but scaled down images as icons.

Solution

Add a dedicated images property with a fallback chain:

Lexical editor icon: images.icon → images.thumbnail → imageURL (deprecated) → default BlockIcon
Block drawer thumbnail: images.thumbnail → imageURL (deprecated) → default placeholder

Now you can set different URL for block icons in lexical blocks:
image

Example:

  const QuoteBlock: Block = {
    slug: 'quote',
    images: {
      icon: 'https://example.com/icons/quote-20x20.svg',
      thumbnail: { url: 'https://example.com/thumbnails/quote-480x320.jpg', alt: 'Quote block' },
    },
    fields: [...],
  }

Backwards Compatibility

Fully backwards compatible — imageURL and imageAltText still work (marked as @deprecated), with automatic fallback to the new images property behavior.

@VeiaG VeiaG requested a review from AlessioGr as a code owner February 14, 2026 14:48
@VeiaG VeiaG changed the title feat(richtext-lexical):add separate fields for icons in lexical blocks feat(richtext-lexical): add separate fields for icons in lexical blocks Feb 14, 2026
Comment thread packages/payload/src/fields/config/types.ts Outdated
Copy link
Copy Markdown
Member

@AlessioGr AlessioGr left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's do the following:

  • mark imageURL and imageAltText properties as @deprecated, and add JSDocs
  • add one new property:
images?: {
   icon: { url: , alt: },
   thumbnail: { url: , alt: },
}

Comment thread packages/richtext-lexical/src/features/blocks/client/getBlockImageComponent.tsx Outdated
Comment thread docs/fields/blocks.mdx Outdated
Comment thread packages/richtext-lexical/src/features/blocks/client/index.tsx Outdated
Comment thread test/fields/collections/Blocks/int-iconImage.spec.ts Outdated
Comment thread packages/payload/src/fields/config/types.ts Outdated
@VeiaG
Copy link
Copy Markdown
Contributor Author

VeiaG commented Feb 25, 2026

@AlessioGr could you please check packages\richtext-lexical\src\features\blocks\client\getBlockImageComponent.tsx
I got some strange ts error, and only in this file. I don't really know how to fix it, something with ts config.

I moved images to admin.

image image

Moved images to admin properties table in docs, and moved image guidlines section under admin options table

@VeiaG
Copy link
Copy Markdown
Contributor Author

VeiaG commented Feb 25, 2026

About ts error on top, i added NonNullable on Block['admin']. (and removed ts-expect-error) , but i'm not sure if this can break something

export type ClientBlock = {
  admin?: Pick<NonNullable<Block['admin']>, 'custom' | 'disableBlockName' | 'group' | 'images'>
  fields: ClientField[]
  labels?: LabelsClient
} & Pick<Block, 'imageAltText' | 'imageURL' | 'jsx' | 'slug'>

@VeiaG VeiaG requested a review from AlessioGr February 25, 2026 23:30
AlessioGr
AlessioGr previously approved these changes Feb 26, 2026
Copy link
Copy Markdown
Member

@AlessioGr AlessioGr left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this looks good like that, thank you!

@AlessioGr AlessioGr enabled auto-merge (squash) February 26, 2026 00:56
auto-merge was automatically disabled February 26, 2026 11:38

Head branch was pushed to by a user without write access

@VeiaG VeiaG requested a review from AlessioGr February 26, 2026 11:39
@VeiaG
Copy link
Copy Markdown
Contributor Author

VeiaG commented Feb 27, 2026

@AlessioGr pinging, because i removed images config from test blocks configs, for e2e tests to pass.

Comment thread test/fields/collections/Blocks/index.ts
@VeiaG
Copy link
Copy Markdown
Contributor Author

VeiaG commented Mar 2, 2026

From claude code:

When a block has admin.images.thumbnail with an alt text (e.g. alt: 'Block thumbnail'), the browser includes that alt text in the button's accessible name. The addBlock helper selects blocks in the drawer using:

getByRole('button', { name: exactText(blockToSelect) })

So when searching for 'Content', it expects the button's accessible name to be exactly "Content", but it's now "Block thumbnail Content" — causing the locator to fail.

I moved images config to WithIcon block, and vibe-coded tests for it (sorry).
Locally tests for fields__collections__Blocks don't have same issue.

Pushing here to test.

Comment thread test/fields/collections/Blocks/e2e.spec.ts
@VeiaG VeiaG requested a review from AlessioGr March 2, 2026 20:34
@AlessioGr AlessioGr changed the title feat(richtext-lexical): add separate fields for icons in lexical blocks feat(richtext-lexical): separate configuration for lexical block icons Mar 2, 2026
@AlessioGr AlessioGr merged commit f0498f2 into payloadcms:main Mar 2, 2026
152 checks passed
@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented Mar 4, 2026

🚀 This is included in version v3.79.0

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants