Skip to content

Allow stable block IDs in the block editor store #74623

@alecgeatches

Description

@alecgeatches

What problem does this address?

See previous PR discussions #72405 (comment) and #73737 (comment).

Block client IDs are not stable within templates, and this can cause issues:

  1. When identifying blocks by ID in real-time collaboration in "Show Template" mode.
  2. When navigating between a synced template and post content.

This is a result of block cloning used when blocks are displayed within a template, which will randomize client IDs.

This is currently required, because the block editor breaks if we attempt to show a section with the same client ID twice:

Screenshot 2025-10-23 at 3 40 10 PM
Screen.Recording.2025-10-23.at.3.40.48.PM.mov

Everything breaks because input and block control rendering only expects a single block per client ID. Because we don't have a single place to render Gutenberg controls, the editor is unhappy. The workaround currently in the editor is to clone blocks that may have conflicting IDs.

Here's a quick summary of the problem:

  1. The block editor store expects every block to have a unique client ID.
  2. When templates are displayed, the editor randomizes client IDs to avoid the possibility of displaying a block with the same block ID twice.
  3. This block ID instability causes block navigation and real-time collaboration issues in these modes because they lose stable references to blocks.

What is your proposed solution?

@youknowriad suggested an internal/external client ID mapping here:

Why do the uuids used within the block-editor store matter? Maybe these are temporary uids, and the cloning persists but it also can persist in both ways. In other words when onChange (or onInput is called), useBlockSync would actually restore the original uids when calling the onChange and the "cloned" ones are only internal to block-editor store. In other words, we'd need to keep two "uids" per block in the block-editor store or have a map of uids (external to internal) in useBlockSync. I'm not certain which issues this could cause (I think there are probably issues related to immutability as we rely on immutability of blocks in a few places), but maybe it's a decent approach that we can try.

This suggests adding a mapping in useBlockSync that will allow blocks in templates to retain their unchanged block IDs externally, but use an internal mapping to treat the blocks as logically separate.


@youknowriad and @tellthemachines if you have anything else to add or correct, please let me know! This is a tricky problem to wrap my head around.

Metadata

Metadata

Assignees

Labels

Type

No type
No fields configured for issues without a type.

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions