Skip to content

Conversation

@talldan
Copy link
Contributor

@talldan talldan commented Sep 10, 2025

What?

Experiments with an API for #71557.
Built on top of #71512
Related: #58233.
Similar: #60779.

The goal is to make role: content attributes editable in the block inspector in contentOnly mode, as per this design:

Image

This PR starts with the content fields for heading and paragraph blocks.

Why?

See #71517 for the full reasoning.

How?

For this PR I'm proposing a new API in the block.json, for each attribute a control property can be specified. At the moment only RichText control is supported, and to start with this renders a TextBox control, so not a rich text, but it's something to build on.

The exact API might need refinement, for example, should it be in block.json or index.js? I like block.json because it co-locates with the attribute.

I expect blocks will also need custom controls for more specific things, in which case moving to the index.js might be better, or adding a way to register controls.

In the future this could expand beyond contentOnly and the inspector.

Testing Instructions

First, enable the experiment in Gutenberg's experiment settings page:

image
  1. Create a new post
  2. Open the inserter
  3. Add an unsynced pattern that has a heading and a paragraph
  4. With the pattern selected in the canvas, open the block inspector
  5. Edit the heading/paragraphs in the inspector

Screenshots or screencast

Kapture.2025-09-10.at.17.36.52.mp4

@talldan talldan self-assigned this Sep 10, 2025
@talldan talldan added [Type] Experimental Experimental feature or API. [Feature] Patterns A collection of blocks that can be synced (previously reusable blocks) or unsynced labels Sep 10, 2025
const resetValue = {};

attributes.forEach( ( attribute ) => {
resetValue[ attribute.key ] = getDefaultValue( attribute );
Copy link
Contributor Author

Choose a reason for hiding this comment

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

I think the reset options in the tools panel would be better if they reset to the pattern's original content (similar to how synced patterns work) rather than the attribute's default.

I haven't explored it yet, but I think it'll be pretty difficult to do. 😬

@talldan talldan requested a review from scruffian September 10, 2025 09:54
@talldan talldan requested review from getdave and jeryj September 10, 2025 09:54
@github-actions
Copy link

Size Change: +478 B (+0.02%)

Total Size: 1.94 MB

Filename Size Change
build/block-editor/index.min.js 267 kB +442 B (+0.17%)
build/block-library/index.min.js 234 kB +36 B (+0.02%)
ℹ️ View Unchanged
Filename Size
build-module/a11y/index.min.js 482 B
build-module/block-library/accordion/view.min.js 427 B
build-module/block-library/file/view.min.js 466 B
build-module/block-library/form/view.min.js 533 B
build-module/block-library/image/view.min.js 1.78 kB
build-module/block-library/navigation/view.min.js 1.19 kB
build-module/block-library/query/view.min.js 767 B
build-module/block-library/search/view.min.js 639 B
build-module/interactivity-router/full-page.min.js 565 B
build-module/interactivity-router/index.min.js 11.4 kB
build-module/interactivity/debug.min.js 17.6 kB
build-module/interactivity/index.min.js 14 kB
build/a11y/index.min.js 925 B
build/annotations/index.min.js 2.13 kB
build/api-fetch/index.min.js 2.41 kB
build/autop/index.min.js 2.12 kB
build/blob/index.min.js 579 B
build/block-directory/index.min.js 7.18 kB
build/block-directory/style-rtl.css 1.03 kB
build/block-directory/style.css 1.03 kB
build/block-editor/content-rtl.css 4.43 kB
build/block-editor/content.css 4.42 kB
build/block-editor/default-editor-styles-rtl.css 392 B
build/block-editor/default-editor-styles.css 392 B
build/block-editor/style-rtl.css 15.9 kB
build/block-editor/style.css 15.9 kB
build/block-library/blocks/accordion/style-rtl.css 573 B
build/block-library/blocks/accordion/style.css 573 B
build/block-library/blocks/archives/editor-rtl.css 61 B
build/block-library/blocks/archives/editor.css 61 B
build/block-library/blocks/archives/style-rtl.css 90 B
build/block-library/blocks/archives/style.css 90 B
build/block-library/blocks/audio/editor-rtl.css 149 B
build/block-library/blocks/audio/editor.css 151 B
build/block-library/blocks/audio/style-rtl.css 132 B
build/block-library/blocks/audio/style.css 132 B
build/block-library/blocks/audio/theme-rtl.css 134 B
build/block-library/blocks/audio/theme.css 134 B
build/block-library/blocks/avatar/editor-rtl.css 115 B
build/block-library/blocks/avatar/editor.css 115 B
build/block-library/blocks/avatar/style-rtl.css 104 B
build/block-library/blocks/avatar/style.css 104 B
build/block-library/blocks/button/editor-rtl.css 265 B
build/block-library/blocks/button/editor.css 265 B
build/block-library/blocks/button/style-rtl.css 554 B
build/block-library/blocks/button/style.css 554 B
build/block-library/blocks/buttons/editor-rtl.css 291 B
build/block-library/blocks/buttons/editor.css 291 B
build/block-library/blocks/buttons/style-rtl.css 349 B
build/block-library/blocks/buttons/style.css 349 B
build/block-library/blocks/calendar/style-rtl.css 239 B
build/block-library/blocks/calendar/style.css 239 B
build/block-library/blocks/categories/editor-rtl.css 132 B
build/block-library/blocks/categories/editor.css 131 B
build/block-library/blocks/categories/style-rtl.css 152 B
build/block-library/blocks/categories/style.css 152 B
build/block-library/blocks/code/editor-rtl.css 53 B
build/block-library/blocks/code/editor.css 53 B
build/block-library/blocks/code/style-rtl.css 139 B
build/block-library/blocks/code/style.css 139 B
build/block-library/blocks/code/theme-rtl.css 122 B
build/block-library/blocks/code/theme.css 122 B
build/block-library/blocks/columns/editor-rtl.css 108 B
build/block-library/blocks/columns/editor.css 108 B
build/block-library/blocks/columns/style-rtl.css 420 B
build/block-library/blocks/columns/style.css 420 B
build/block-library/blocks/comment-author-avatar/editor-rtl.css 124 B
build/block-library/blocks/comment-author-avatar/editor.css 124 B
build/block-library/blocks/comment-author-name/style-rtl.css 72 B
build/block-library/blocks/comment-author-name/style.css 72 B
build/block-library/blocks/comment-content/style-rtl.css 120 B
build/block-library/blocks/comment-content/style.css 120 B
build/block-library/blocks/comment-date/style-rtl.css 65 B
build/block-library/blocks/comment-date/style.css 65 B
build/block-library/blocks/comment-edit-link/style-rtl.css 70 B
build/block-library/blocks/comment-edit-link/style.css 70 B
build/block-library/blocks/comment-reply-link/style-rtl.css 71 B
build/block-library/blocks/comment-reply-link/style.css 71 B
build/block-library/blocks/comment-template/style-rtl.css 191 B
build/block-library/blocks/comment-template/style.css 191 B
build/block-library/blocks/comments-pagination-numbers/editor-rtl.css 122 B
build/block-library/blocks/comments-pagination-numbers/editor.css 121 B
build/block-library/blocks/comments-pagination/editor-rtl.css 168 B
build/block-library/blocks/comments-pagination/editor.css 168 B
build/block-library/blocks/comments-pagination/style-rtl.css 201 B
build/block-library/blocks/comments-pagination/style.css 201 B
build/block-library/blocks/comments-title/editor-rtl.css 75 B
build/block-library/blocks/comments-title/editor.css 75 B
build/block-library/blocks/comments/editor-rtl.css 842 B
build/block-library/blocks/comments/editor.css 842 B
build/block-library/blocks/comments/style-rtl.css 637 B
build/block-library/blocks/comments/style.css 637 B
build/block-library/blocks/cover/editor-rtl.css 631 B
build/block-library/blocks/cover/editor.css 631 B
build/block-library/blocks/cover/style-rtl.css 1.7 kB
build/block-library/blocks/cover/style.css 1.69 kB
build/block-library/blocks/details/editor-rtl.css 65 B
build/block-library/blocks/details/editor.css 65 B
build/block-library/blocks/details/style-rtl.css 86 B
build/block-library/blocks/details/style.css 86 B
build/block-library/blocks/embed/editor-rtl.css 331 B
build/block-library/blocks/embed/editor.css 331 B
build/block-library/blocks/embed/style-rtl.css 419 B
build/block-library/blocks/embed/style.css 419 B
build/block-library/blocks/embed/theme-rtl.css 133 B
build/block-library/blocks/embed/theme.css 133 B
build/block-library/blocks/file/editor-rtl.css 326 B
build/block-library/blocks/file/editor.css 326 B
build/block-library/blocks/file/style-rtl.css 278 B
build/block-library/blocks/file/style.css 278 B
build/block-library/blocks/footnotes/style-rtl.css 198 B
build/block-library/blocks/footnotes/style.css 197 B
build/block-library/blocks/form-input/editor-rtl.css 229 B
build/block-library/blocks/form-input/editor.css 229 B
build/block-library/blocks/form-input/style-rtl.css 366 B
build/block-library/blocks/form-input/style.css 366 B
build/block-library/blocks/form-submission-notification/editor-rtl.css 344 B
build/block-library/blocks/form-submission-notification/editor.css 341 B
build/block-library/blocks/form-submit-button/style-rtl.css 69 B
build/block-library/blocks/form-submit-button/style.css 69 B
build/block-library/blocks/freeform/editor-rtl.css 2.59 kB
build/block-library/blocks/freeform/editor.css 2.59 kB
build/block-library/blocks/gallery/editor-rtl.css 615 B
build/block-library/blocks/gallery/editor.css 616 B
build/block-library/blocks/gallery/style-rtl.css 1.83 kB
build/block-library/blocks/gallery/style.css 1.83 kB
build/block-library/blocks/gallery/theme-rtl.css 108 B
build/block-library/blocks/gallery/theme.css 108 B
build/block-library/blocks/group/editor-rtl.css 334 B
build/block-library/blocks/group/editor.css 334 B
build/block-library/blocks/group/style-rtl.css 103 B
build/block-library/blocks/group/style.css 103 B
build/block-library/blocks/group/theme-rtl.css 79 B
build/block-library/blocks/group/theme.css 79 B
build/block-library/blocks/heading/style-rtl.css 188 B
build/block-library/blocks/heading/style.css 188 B
build/block-library/blocks/html/editor-rtl.css 353 B
build/block-library/blocks/html/editor.css 354 B
build/block-library/blocks/image/editor-rtl.css 763 B
build/block-library/blocks/image/editor.css 763 B
build/block-library/blocks/image/style-rtl.css 1.6 kB
build/block-library/blocks/image/style.css 1.59 kB
build/block-library/blocks/image/theme-rtl.css 137 B
build/block-library/blocks/image/theme.css 137 B
build/block-library/blocks/latest-comments/style-rtl.css 355 B
build/block-library/blocks/latest-comments/style.css 354 B
build/block-library/blocks/latest-posts/editor-rtl.css 139 B
build/block-library/blocks/latest-posts/editor.css 138 B
build/block-library/blocks/latest-posts/style-rtl.css 520 B
build/block-library/blocks/latest-posts/style.css 520 B
build/block-library/blocks/list/style-rtl.css 107 B
build/block-library/blocks/list/style.css 107 B
build/block-library/blocks/loginout/style-rtl.css 61 B
build/block-library/blocks/loginout/style.css 61 B
build/block-library/blocks/media-text/editor-rtl.css 321 B
build/block-library/blocks/media-text/editor.css 320 B
build/block-library/blocks/media-text/style-rtl.css 543 B
build/block-library/blocks/media-text/style.css 542 B
build/block-library/blocks/more/editor-rtl.css 393 B
build/block-library/blocks/more/editor.css 393 B
build/block-library/blocks/navigation-link/editor-rtl.css 625 B
build/block-library/blocks/navigation-link/editor.css 628 B
build/block-library/blocks/navigation-link/style-rtl.css 190 B
build/block-library/blocks/navigation-link/style.css 188 B
build/block-library/blocks/navigation-submenu/editor-rtl.css 295 B
build/block-library/blocks/navigation-submenu/editor.css 294 B
build/block-library/blocks/navigation/editor-rtl.css 2.23 kB
build/block-library/blocks/navigation/editor.css 2.24 kB
build/block-library/blocks/navigation/style-rtl.css 2.27 kB
build/block-library/blocks/navigation/style.css 2.26 kB
build/block-library/blocks/nextpage/editor-rtl.css 392 B
build/block-library/blocks/nextpage/editor.css 392 B
build/block-library/blocks/page-list/editor-rtl.css 356 B
build/block-library/blocks/page-list/editor.css 356 B
build/block-library/blocks/page-list/style-rtl.css 192 B
build/block-library/blocks/page-list/style.css 192 B
build/block-library/blocks/paragraph/editor-rtl.css 251 B
build/block-library/blocks/paragraph/editor.css 251 B
build/block-library/blocks/paragraph/style-rtl.css 341 B
build/block-library/blocks/paragraph/style.css 340 B
build/block-library/blocks/post-author-biography/style-rtl.css 74 B
build/block-library/blocks/post-author-biography/style.css 74 B
build/block-library/blocks/post-author-name/style-rtl.css 69 B
build/block-library/blocks/post-author-name/style.css 69 B
build/block-library/blocks/post-author/style-rtl.css 188 B
build/block-library/blocks/post-author/style.css 189 B
build/block-library/blocks/post-comments-count/style-rtl.css 72 B
build/block-library/blocks/post-comments-count/style.css 72 B
build/block-library/blocks/post-comments-form/editor-rtl.css 96 B
build/block-library/blocks/post-comments-form/editor.css 96 B
build/block-library/blocks/post-comments-form/style-rtl.css 525 B
build/block-library/blocks/post-comments-form/style.css 525 B
build/block-library/blocks/post-comments-link/style-rtl.css 71 B
build/block-library/blocks/post-comments-link/style.css 71 B
build/block-library/blocks/post-content/style-rtl.css 61 B
build/block-library/blocks/post-content/style.css 61 B
build/block-library/blocks/post-date/style-rtl.css 62 B
build/block-library/blocks/post-date/style.css 62 B
build/block-library/blocks/post-excerpt/editor-rtl.css 71 B
build/block-library/blocks/post-excerpt/editor.css 71 B
build/block-library/blocks/post-excerpt/style-rtl.css 155 B
build/block-library/blocks/post-excerpt/style.css 155 B
build/block-library/blocks/post-featured-image/editor-rtl.css 715 B
build/block-library/blocks/post-featured-image/editor.css 712 B
build/block-library/blocks/post-featured-image/style-rtl.css 347 B
build/block-library/blocks/post-featured-image/style.css 347 B
build/block-library/blocks/post-navigation-link/style-rtl.css 215 B
build/block-library/blocks/post-navigation-link/style.css 214 B
build/block-library/blocks/post-template/style-rtl.css 414 B
build/block-library/blocks/post-template/style.css 414 B
build/block-library/blocks/post-terms/style-rtl.css 96 B
build/block-library/blocks/post-terms/style.css 96 B
build/block-library/blocks/post-time-to-read/style-rtl.css 70 B
build/block-library/blocks/post-time-to-read/style.css 70 B
build/block-library/blocks/post-title/style-rtl.css 162 B
build/block-library/blocks/post-title/style.css 162 B
build/block-library/blocks/preformatted/style-rtl.css 125 B
build/block-library/blocks/preformatted/style.css 125 B
build/block-library/blocks/pullquote/editor-rtl.css 133 B
build/block-library/blocks/pullquote/editor.css 133 B
build/block-library/blocks/pullquote/style-rtl.css 365 B
build/block-library/blocks/pullquote/style.css 365 B
build/block-library/blocks/pullquote/theme-rtl.css 176 B
build/block-library/blocks/pullquote/theme.css 176 B
build/block-library/blocks/query-pagination-numbers/editor-rtl.css 121 B
build/block-library/blocks/query-pagination-numbers/editor.css 118 B
build/block-library/blocks/query-pagination/editor-rtl.css 154 B
build/block-library/blocks/query-pagination/editor.css 154 B
build/block-library/blocks/query-pagination/style-rtl.css 237 B
build/block-library/blocks/query-pagination/style.css 237 B
build/block-library/blocks/query-title/style-rtl.css 64 B
build/block-library/blocks/query-title/style.css 64 B
build/block-library/blocks/query-total/style-rtl.css 64 B
build/block-library/blocks/query-total/style.css 64 B
build/block-library/blocks/query/editor-rtl.css 432 B
build/block-library/blocks/query/editor.css 432 B
build/block-library/blocks/quote/style-rtl.css 238 B
build/block-library/blocks/quote/style.css 238 B
build/block-library/blocks/quote/theme-rtl.css 233 B
build/block-library/blocks/quote/theme.css 236 B
build/block-library/blocks/read-more/style-rtl.css 131 B
build/block-library/blocks/read-more/style.css 131 B
build/block-library/blocks/rss/editor-rtl.css 126 B
build/block-library/blocks/rss/editor.css 126 B
build/block-library/blocks/rss/style-rtl.css 284 B
build/block-library/blocks/rss/style.css 283 B
build/block-library/blocks/search/editor-rtl.css 199 B
build/block-library/blocks/search/editor.css 199 B
build/block-library/blocks/search/style-rtl.css 665 B
build/block-library/blocks/search/style.css 666 B
build/block-library/blocks/search/theme-rtl.css 113 B
build/block-library/blocks/search/theme.css 113 B
build/block-library/blocks/separator/editor-rtl.css 100 B
build/block-library/blocks/separator/editor.css 100 B
build/block-library/blocks/separator/style-rtl.css 248 B
build/block-library/blocks/separator/style.css 248 B
build/block-library/blocks/separator/theme-rtl.css 195 B
build/block-library/blocks/separator/theme.css 195 B
build/block-library/blocks/shortcode/editor-rtl.css 286 B
build/block-library/blocks/shortcode/editor.css 286 B
build/block-library/blocks/site-logo/editor-rtl.css 773 B
build/block-library/blocks/site-logo/editor.css 770 B
build/block-library/blocks/site-logo/style-rtl.css 218 B
build/block-library/blocks/site-logo/style.css 218 B
build/block-library/blocks/site-tagline/editor-rtl.css 87 B
build/block-library/blocks/site-tagline/editor.css 87 B
build/block-library/blocks/site-tagline/style-rtl.css 65 B
build/block-library/blocks/site-tagline/style.css 65 B
build/block-library/blocks/site-title/editor-rtl.css 85 B
build/block-library/blocks/site-title/editor.css 85 B
build/block-library/blocks/site-title/style-rtl.css 143 B
build/block-library/blocks/site-title/style.css 143 B
build/block-library/blocks/social-link/editor-rtl.css 314 B
build/block-library/blocks/social-link/editor.css 314 B
build/block-library/blocks/social-links/editor-rtl.css 339 B
build/block-library/blocks/social-links/editor.css 338 B
build/block-library/blocks/social-links/style-rtl.css 1.51 kB
build/block-library/blocks/social-links/style.css 1.51 kB
build/block-library/blocks/spacer/editor-rtl.css 346 B
build/block-library/blocks/spacer/editor.css 346 B
build/block-library/blocks/spacer/style-rtl.css 48 B
build/block-library/blocks/spacer/style.css 48 B
build/block-library/blocks/table-of-contents/style-rtl.css 83 B
build/block-library/blocks/table-of-contents/style.css 83 B
build/block-library/blocks/table/editor-rtl.css 394 B
build/block-library/blocks/table/editor.css 394 B
build/block-library/blocks/table/style-rtl.css 640 B
build/block-library/blocks/table/style.css 639 B
build/block-library/blocks/table/theme-rtl.css 152 B
build/block-library/blocks/table/theme.css 152 B
build/block-library/blocks/tag-cloud/editor-rtl.css 92 B
build/block-library/blocks/tag-cloud/editor.css 92 B
build/block-library/blocks/tag-cloud/style-rtl.css 248 B
build/block-library/blocks/tag-cloud/style.css 248 B
build/block-library/blocks/template-part/editor-rtl.css 368 B
build/block-library/blocks/template-part/editor.css 368 B
build/block-library/blocks/template-part/theme-rtl.css 113 B
build/block-library/blocks/template-part/theme.css 113 B
build/block-library/blocks/term-description/style-rtl.css 126 B
build/block-library/blocks/term-description/style.css 126 B
build/block-library/blocks/text-columns/editor-rtl.css 95 B
build/block-library/blocks/text-columns/editor.css 95 B
build/block-library/blocks/text-columns/style-rtl.css 165 B
build/block-library/blocks/text-columns/style.css 165 B
build/block-library/blocks/verse/style-rtl.css 98 B
build/block-library/blocks/verse/style.css 98 B
build/block-library/blocks/video/editor-rtl.css 413 B
build/block-library/blocks/video/editor.css 414 B
build/block-library/blocks/video/style-rtl.css 202 B
build/block-library/blocks/video/style.css 202 B
build/block-library/blocks/video/theme-rtl.css 134 B
build/block-library/blocks/video/theme.css 134 B
build/block-library/classic-rtl.css 179 B
build/block-library/classic.css 179 B
build/block-library/common-rtl.css 1.08 kB
build/block-library/common.css 1.08 kB
build/block-library/editor-elements-rtl.css 75 B
build/block-library/editor-elements.css 75 B
build/block-library/editor-rtl.css 11.5 kB
build/block-library/editor.css 11.5 kB
build/block-library/elements-rtl.css 54 B
build/block-library/elements.css 54 B
build/block-library/reset-rtl.css 472 B
build/block-library/reset.css 472 B
build/block-library/style-rtl.css 15.4 kB
build/block-library/style.css 15.4 kB
build/block-library/theme-rtl.css 715 B
build/block-library/theme.css 719 B
build/block-serialization-default-parser/index.min.js 1.12 kB
build/block-serialization-spec-parser/index.min.js 2.87 kB
build/blocks/index.min.js 52.6 kB
build/commands/index.min.js 16.3 kB
build/commands/style-rtl.css 956 B
build/commands/style.css 953 B
build/components/index.min.js 252 kB
build/components/style-rtl.css 13.7 kB
build/components/style.css 13.7 kB
build/compose/index.min.js 12.8 kB
build/core-commands/index.min.js 3.24 kB
build/core-data/index.min.js 74.9 kB
build/customize-widgets/index.min.js 11 kB
build/customize-widgets/style-rtl.css 1.43 kB
build/customize-widgets/style.css 1.43 kB
build/data-controls/index.min.js 641 B
build/data/index.min.js 8.7 kB
build/date/index.min.js 18 kB
build/deprecated/index.min.js 458 B
build/dom-ready/index.min.js 325 B
build/dom/index.min.js 4.68 kB
build/edit-post/classic-rtl.css 577 B
build/edit-post/classic.css 578 B
build/edit-post/index.min.js 13.4 kB
build/edit-post/style-rtl.css 2.69 kB
build/edit-post/style.css 2.69 kB
build/edit-site/index.min.js 239 kB
build/edit-site/posts-rtl.css 9.37 kB
build/edit-site/posts.css 9.37 kB
build/edit-site/style-rtl.css 15.4 kB
build/edit-site/style.css 15.4 kB
build/edit-widgets/index.min.js 17.8 kB
build/edit-widgets/style-rtl.css 4.05 kB
build/edit-widgets/style.css 4.06 kB
build/editor/index.min.js 132 kB
build/editor/style-rtl.css 9.2 kB
build/editor/style.css 9.21 kB
build/element/index.min.js 4.86 kB
build/escape-html/index.min.js 537 B
build/format-library/index.min.js 8.23 kB
build/format-library/style-rtl.css 472 B
build/format-library/style.css 472 B
build/hooks/index.min.js 1.65 kB
build/html-entities/index.min.js 467 B
build/i18n/index.min.js 2.23 kB
build/is-shallow-equal/index.min.js 526 B
build/keyboard-shortcuts/index.min.js 1.32 kB
build/keycodes/index.min.js 1.46 kB
build/list-reusable-blocks/index.min.js 2.13 kB
build/list-reusable-blocks/style-rtl.css 847 B
build/list-reusable-blocks/style.css 848 B
build/media-utils/index.min.js 3.69 kB
build/notices/index.min.js 946 B
build/nux/index.min.js 1.62 kB
build/nux/style-rtl.css 767 B
build/nux/style.css 763 B
build/patterns/index.min.js 7.36 kB
build/patterns/style-rtl.css 687 B
build/patterns/style.css 685 B
build/plugins/index.min.js 1.87 kB
build/preferences-persistence/index.min.js 2.06 kB
build/preferences/index.min.js 2.9 kB
build/preferences/style-rtl.css 562 B
build/preferences/style.css 562 B
build/primitives/index.min.js 829 B
build/priority-queue/index.min.js 1.54 kB
build/private-apis/index.min.js 978 B
build/react-i18n/index.min.js 640 B
build/react-refresh-entry/index.min.js 9.47 kB
build/react-refresh-runtime/index.min.js 6.76 kB
build/redux-routine/index.min.js 2.7 kB
build/reusable-blocks/index.min.js 2.53 kB
build/reusable-blocks/style-rtl.css 255 B
build/reusable-blocks/style.css 255 B
build/rich-text/index.min.js 12.2 kB
build/router/index.min.js 5.47 kB
build/server-side-render/index.min.js 1.6 kB
build/shortcode/index.min.js 1.4 kB
build/style-engine/index.min.js 2.04 kB
build/token-list/index.min.js 581 B
build/url/index.min.js 3.97 kB
build/vendors/react-dom.min.js 41.7 kB
build/vendors/react-jsx-runtime.min.js 556 B
build/vendors/react.min.js 4.02 kB
build/viewport/index.min.js 965 B
build/vips/index.min.js 36.2 kB
build/warning/index.min.js 250 B
build/widgets/index.min.js 7.16 kB
build/widgets/style-rtl.css 1.16 kB
build/widgets/style.css 1.16 kB
build/wordcount/index.min.js 1.04 kB

compressed-size-action

"role": "content"
"role": "content",
"control": {
"type": "RichText",
Copy link
Contributor

Choose a reason for hiding this comment

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

Rather than specifying the type of control that the attribute needs, I wonder if we should be more semantic, and let Gutenberg decide what control to display for each different piece of semantic content, for example:

  • Media
  • Link
  • Text
  • etc.

Copy link
Contributor

Choose a reason for hiding this comment

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

I agree. I really think we should lean into semantics here. The more semantics we can have blocks give us, the more we can generate an appropriate UI. Then, we're also not locked into a certain approach, but yet we have enough information to infer the right controls.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I agree about the idea of more semantic names. The upstream issue specifies that formatting should be possible so that's why I went with RichText vs. Text (which might represent Plain Text).

It could also just be Text and inferred as rich text from the attribute.type.

Something else to consider is that Media updates the id, src and potentially others like caption and alt, so the idea of one control per attribute may not work. Or it does work, but we need to allow a control to read and write to other attributes, not just its own.

@github-actions
Copy link

Flaky tests detected in 04a67c2.
Some tests passed with failed attempts. The failures may not be related to this commit but are still reported for visibility. See the documentation for more information.

🔍 Workflow run URL: https://github.com/WordPress/gutenberg/actions/runs/17609960850
📝 Reported issues:

Copy link
Contributor

@getdave getdave left a comment

Choose a reason for hiding this comment

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

This is great. Thank for working on it.

I also started exploring in #71567, but mine was just a quick mockup and yours seems a lot more fleshed out.

I'm wondering if the API for this could be applied in the following priority:

  • use control defined in index.js (if available)
  • use control from Block JSON to render predefined control (if available - as shown in this PR)
  • attempt to automatically infer control by type

This would allow the block author to opt-in to ever greater levels of fidelity for their controls.

Comment on lines +19 to +23
"control": {
"type": "RichText",
"label": "Content",
"shownByDefault": true
}
Copy link
Contributor

Choose a reason for hiding this comment

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

I wonder if we can infer a suitable field based on the type of the attribute? I did a very basic MVP for that in #71567.

I definately think your plan to be able to manually specify or override the control component is required though.

A scenario I've been thinking about is attributes such as url. This would typically map to a <LinkControl> but that component needs to know the type of entity being searched for. So ultimately we to be able to either:

  • provide this data via the block json
  • configure it manually via JSX

I saw you suggested using index.js for this which I think might be a good opt-in API for these kinds of edge cases.

Copy link
Contributor

@jeryj jeryj left a comment

Choose a reason for hiding this comment

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

I've been letting this percolate in my brain a bit. I think we should do all we can to have this be inferred controls based on the existing block.json. I think if we require all third party blocks to be updated to have write mode work, then write mode fails.

Example:

  • We launch write mode
  • Most sites use third party blocks
  • User switches on write mode
  • Only core blocks work/all their third party blocks are broken

If we can infer the controls, the write mode will automatically work for third party blocks.


const blockTitle = useBlockDisplayTitle( {
clientId,
context: 'list-view',
Copy link
Contributor

Choose a reason for hiding this comment

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

This feels odd since we're not in the list view. Maybe we need to change the whatever the context is of this list-view name to something more generic?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I haven't thought too much about it, it's just code I lifted from the BlockQuickNavigation component.

Comment on lines +19 to +23
"control": {
"type": "RichText",
"label": "Content",
"shownByDefault": true
}
Copy link
Contributor

Choose a reason for hiding this comment

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

I think this works for now to get design feedback, but I'm not sure we should rely on the idea of having all block authors updating their blocks to get their block to work with write mode if we can avoid it.

However, they will need to make updates to their block code if they want any block tools to show, so maybe adding to the block.json is the simplest way to define this.

"role": "content"
"role": "content",
"control": {
"type": "RichText",
Copy link
Contributor

Choose a reason for hiding this comment

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

I agree. I really think we should lean into semantics here. The more semantics we can have blocks give us, the more we can generate an appropriate UI. Then, we're also not locked into a certain approach, but yet we have enough information to infer the right controls.

@youknowriad
Copy link
Contributor

How possible would it be to use a DataForm for this UI?

setValue,
value,
} ) {
const Control = getControlForAttribute( attributeDefinition );
Copy link
Contributor

Choose a reason for hiding this comment

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

This logic is basically repeating what DataForm does, so it's probably wiser to just use it.

Copy link
Contributor Author

@talldan talldan Sep 11, 2025

Choose a reason for hiding this comment

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

Yeah, I think we should use DataForm. We probably need some way to show/hide controls from the UI a bit like ToolsPanel does, and some custom controls for some things, but I that work is beneficial.

Copy link
Member

Choose a reason for hiding this comment

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

Related discussion

A patterns with a lot of blocks would be the same as a block with a lot of settings.

The potential is not just a lot of blocks, but also lots of content in the value field too.

What do folks think a minimal and realistic enhancement looks like? An accordian/hide show wrapper around Data form fields for example?

Copy link
Member

Choose a reason for hiding this comment

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

Another inevitability is the request that clicking on a block on the canvas focusses or opens the editable fields. Take this contrived example:

Kapture.2025-09-11.at.14.40.10.mp4

Copy link
Contributor

Choose a reason for hiding this comment

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

I'd like to try merging all those separate Paragraph items into one rich text field that then builds text blocks. Basically a markdown-like textfield that will generate paragraph and list blocks off of it, so it's treated as one "content box."

Again, very very experimental and no idea if it will work. But, I imagine it like:

  • if there is a paragraph or list block
  • create a content area in the sidebar
  • check for siblings to find the content boundary (wherever the paragraph or list blocks end)
  • translate these paragraph and lists into simple text (paragraph, line break, paragraph, line break, list, line break, etc) in the content area
  • When changes are made to the sidebar content area, they get updated on the canvas as blocks

Copy link
Member

Choose a reason for hiding this comment

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

I'd like to try merging all those separate Paragraph items into one rich text field that then builds text blocks.

Interesting. I'm very curious to see how you'd approach it!

Copy link
Contributor

Choose a reason for hiding this comment

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

When exploring this, I think we'll need to take into account RTL and vertical languages as well (#71517 (comment))

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Another inevitability is the request that clicking on a block on the canvas focusses or opens the editable fields. Take this contrived example:

This is on my mind too. Perhaps we can soft-select the matching block while editing in the sidebar (show the outline but not focus).

Maybe we can scroll to or show some kind of selection indication in the inspector when a block is selected in the canvas.

@tellthemachines
Copy link
Contributor

I've been letting this percolate in my brain a bit. I think we should do all we can to have this be inferred controls based on the existing block.json. I think if we require all third party blocks to be updated to have write mode work, then write mode fails.

Unfortunately it will be necessary for third party blocks to update anyway, because blocks are only editable in write mode if they have "role": "content" in any of their attributes. This is not something that third party blocks have, because up to now it hasn't really been useful for any purpose. The content role was introduced experimentally in #30469 for some pattern-related transform functionality, but I'm not sure that ever became a full feature 😅

I had a go a testing a bunch of third party blocks recently, and the only ones that worked in write mode were ones using core blocks inside (like, a block that wraps around a Paragraph and a Heading or something).

I don't believe there's a viable way of inferring that a block is content without the explicit role. There are just too many different types of blocks for that to work out without ending up in spaghetti logic and likely a bunch of hard-coded edge case blocks 😬

User switches on write mode

The good news here is that given the direction set in #71517, it's looking likely that there won't be a write mode switch, but the mode will be a default for patterns only. This may somewhat mitigate the issues with third party block compatibility, because anything that's not in a pattern with a patternName (proposed in #71512) will still be fully editable.

@andrewserong
Copy link
Contributor

andrewserong commented Sep 11, 2025

I don't believe there's a viable way of inferring that a block is content without the explicit role.

I wonder how far we can get by still using the explicit role ("role": "content") but infer some of the other details, i.e. make the label be a 'sentence case'd display of the block attribute's key? Looks like we already use the change-case package in a few places, so we might be able to pass the attribute key through sentenceCase or capitalCase?

That way for third party blocks, they only need to add the content role and not worry about any other details.

shownByDefault might be hard to infer, though 🤔

@talldan
Copy link
Contributor Author

talldan commented Sep 11, 2025

make the label be a 'sentence case'd display of the block attribute's key

I think block bindings does something like this, but that's a very advanced feature. contentOnly is supposed to be the opposite and a very simple feature.

It'll need to be internationalized - I don't know whether that's possible or how it'd work. Translators would probably need to work with a camel cased version of the attribute key. I think some of the existing keys are also not quite right as labels, some like src and rel are closer to the html attribute names. Maybe as a fallback it would be ok.

I think we need proper labels. The investment will, I expect, be worth it. Block Bindings could use it too. I don't think it'll take long either, we just need to decide the API first. Could probably get an AI agent to do a first pass and then human refinements. It also doesn't have to be perfect first time, just good enough.

I do like the idea of inferring the type of control, but I think realistically we'll hit issues soon enough, and we might want some level of curation of the controls.

@ramonjd
Copy link
Member

ramonjd commented Sep 11, 2025

Great discussions,

I wonder how far we can get by still using the explicit role ("role": "content") but infer some of the other details
I do like the idea of inferring the type of control, but I think realistically we'll hit issues soon enough, and we might want some level of curation of the controls.

I've only just begun to look at this PR and @getdave and @jeryj's PR, and have made some notes. I hope I'm grokking this all so far:

With inference:

  • centralization: the same logic applies to all blocks to start with, requiring little or no block.json changes
  • no further config (aside from role: content)

Manual config:

  • finer-grained block.json props blocks can specify exactly which control and labels to use, probably can cover more edge cases
  • a bit of an adoption barrier?

I'll revisit to test my assumptions, but so far I'm slightly leaning towards inference in the first iteration, or perhaps some hybrid model, e.g., try automatic inference first, then later, create a system to allow optional manual overrides in block.json or JS for blocks that require custom editing experiences or advanced data types.

For the latter, @talldan already mentioned index.js, and something like block.json's "viewScriptModule" came to mind if it's a separate file. You'd get i18n that way too. I like!

We have short-term goals but with long-term consequences, so I'm wondering if we should — at least in the first round — assume simple needs and avoid maintenance overhead, and go for what covers the most number of cases.

After that, spend quality time on an API in index.js or otherwise to manually override the defaults?

@talldan
Copy link
Contributor Author

talldan commented Sep 11, 2025

Example:

  • We launch write mode
  • Most sites use third party blocks
  • User switches on write mode
  • Only core blocks work/all their third party blocks are broken

If we can infer the controls, the write mode will automatically work for third party blocks.

@jeryj I definitely get the concerns. At the same time, if the inferred controls are wrong then the third party blocks are probably more broken, users will be able to add incorrect block data and possibly invalidate the blocks or cause errors to be thrown.

Even core blocks are very inconsistent in their implementation and I expect it to be a challenge, so I'm not sure we'll be able to solve every problem for third party blocks who might be using different practices (like different naming conventions).

I'm not saying there's no merit to the idea, but I think we might need to be careful and get the balance right.

Base automatically changed from try/content-only-patterns-by-default to trunk September 11, 2025 05:29
@jeryj
Copy link
Contributor

jeryj commented Sep 11, 2025

@talldan

At the same time, if the inferred controls are wrong then the third party blocks are probably more broken, users will be able to add incorrect block data and possibly invalidate the blocks or cause errors to be thrown.

For sure! That's a huge concern of mine too. I want to know where it beaks down so we can make the best decision we can for now. Maybe there's a way we can do both - automatically infer and offer a way to override with your own control.

@talldan
Copy link
Contributor Author

talldan commented Sep 12, 2025

Closing this as I don't want to duplicate efforts - #71567 is where dev will happen now.

@talldan talldan closed this Sep 12, 2025
@talldan talldan deleted the add/content-only-block-controls branch September 12, 2025 06:57
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

[Feature] Patterns A collection of blocks that can be synced (previously reusable blocks) or unsynced [Type] Experimental Experimental feature or API.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

10 participants