Skip to content

Conversation

@gigitux
Copy link
Contributor

@gigitux gigitux commented Aug 6, 2025

What

This PR introduces a new card layout for the DataForm component in the @wordpress/dataviews package. The card layout provides a collapsible, card-based UI for organizing form fields with improved visual hierarchy and user experience.

How

Added 'card' as a new layout type alongside existing 'regular' and 'panel' layouts.

Layout definition

form and field accepts a layout property that it is an object:

export type LayoutType = 'regular' | 'panel' | 'card';
export type LabelPosition = 'top' | 'side' | 'none';

export type RegularLayout = {
	type: 'regular';
	labelPosition: LabelPosition;
};

export type PanelLayout = {
	type: 'panel';
	labelPosition: LabelPosition;
};

export type CardLayout = {
	type: 'card';
	withHeader?: boolean;
	isOpened?: boolean;
};

export type Layout = RegularLayout | PanelLayout | CardLayout;

This allows building complex interfaces in a declarative approach by defining different layout types at multiple levels:

  1. Form-level layout (first layer): The form.layout property sets the default layout for all fields in the form. This affects how top-level fields are rendered. Certain layouts include nesting safeguards — for example, Card Layout automatically prevents child cards by defaulting children to 'regular' layout, avoiding problematic infinite nesting scenarios.

  2. Field-level layout overrides: Individual fields can override the form layout by specifying their own layout property, allowing mixed layouts within the same form.

  3. Nested layout inheritance: When using combined fields (fields with children), each child can have its own layout that overrides its parent's layout.

Examples

Check the storybook for more complex ones.

image
const form = {
  layout: { type: "card" },
  fields: [
    "title",
    {
      id: "status",
      label: "Status",
      layout: { type: "panel", labelPosition: "top" },
    },
  ],
};
image
const form = {
  layout: { type: "card" },
  fields: [
    {
      id: "customer-container",
      label: "Customer",
      children: [
        {
          id: "customer-information",
          label: "Customer Information",
          layout: { type: "panel", labelPosition: "top" },
          children: [ /* ... */ ],
        },
        {
          id: "customerType",
          layout: { type: "panel", labelPosition: "top" },
        },
        {
          id: "shippingAddress",
          layout: { type: "panel", labelPosition: "top" },
        },
        {
          id: "billingAddress",
          layout: { type: "panel", labelPosition: "top" },
        },
      ],
    },
  ],
};

How to test

Run the storybook locally and interact with the LayoutCard and LayoutMixed stories:

npm install && npm run storybook:dev

@github-actions
Copy link

github-actions bot commented Aug 6, 2025

Size Change: +818 B (+0.04%)

Total Size: 1.92 MB

Filename Size Change
build/edit-site/index.min.js 235 kB +389 B (+0.17%)
build/editor/index.min.js 127 kB +429 B (+0.34%)
ℹ️ View Unchanged
Filename Size
build-module/a11y/index.min.js 482 B
build-module/block-library/accordions/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.5 kB
build-module/interactivity/index.min.js 13.9 kB
build/a11y/index.min.js 952 B
build/annotations/index.min.js 2.13 kB
build/api-fetch/index.min.js 2.4 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/index.min.js 266 kB
build/block-editor/style-rtl.css 15.9 kB
build/block-editor/style.css 15.9 kB
build/block-library/blocks/accordions/style-rtl.css 591 B
build/block-library/blocks/accordions/style.css 590 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 349 B
build/block-library/blocks/form-input/style.css 349 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 566 B
build/block-library/blocks/navigation-link/editor.css 568 B
build/block-library/blocks/navigation-link/style-rtl.css 192 B
build/block-library/blocks/navigation-link/style.css 191 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 527 B
build/block-library/blocks/post-comments-form/style.css 528 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 404 B
build/block-library/blocks/query/editor.css 404 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 674 B
build/block-library/blocks/search/style.css 671 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.4 kB
build/block-library/editor.css 11.4 kB
build/block-library/elements-rtl.css 54 B
build/block-library/elements.css 54 B
build/block-library/index.min.js 232 kB
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.2 kB
build/commands/style-rtl.css 956 B
build/commands/style.css 953 B
build/components/index.min.js 250 kB
build/components/style-rtl.css 13.6 kB
build/components/style.css 13.6 kB
build/compose/index.min.js 12.8 kB
build/core-commands/index.min.js 3.09 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.67 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/posts-rtl.css 8.68 kB
build/edit-site/posts.css 8.68 kB
build/edit-site/style-rtl.css 14.7 kB
build/edit-site/style.css 14.7 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/style-rtl.css 9.2 kB
build/editor/style.css 9.21 kB
build/element/index.min.js 4.82 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.31 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.86 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 630 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.44 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

@gigitux gigitux changed the title Add Cart Layout support Add Card Layout support Aug 7, 2025
@gigitux gigitux force-pushed the add/dataviews-card-layout branch from fc5f900 to 07e5538 Compare August 7, 2025 10:51
@gigitux
Copy link
Contributor Author

gigitux commented Aug 7, 2025

@oandregal let me know your thoughts on this and if everything makes sense. Tomorrow I want to try to implement the row layout following this approach.

@mtias mtias added the [Feature] DataViews Work surrounding upgrading and evolving views in the site editor and beyond label Aug 7, 2025
@oandregal oandregal added the [Type] Enhancement A suggestion for improvement. label Aug 8, 2025
@oandregal
Copy link
Member

Hey @gigitux, thanks for implementing the changes we discussed yesterday. I feel direction is good — just removing "innerLayout" nesting and using the fields instead is much clearer. This approach extends what we have and accommodates potential future layouts (e.g., rows and others). I've pushed some changes to storybook to cover/highlight more of the combinations we talked about. We only need to clarify/fix some edge cases, I'll leave comments in place for them.

@@ -0,0 +1,20 @@
export type LayoutType = 'regular' | 'panel' | 'card';
Copy link
Member

@oandregal oandregal Aug 8, 2025

Choose a reason for hiding this comment

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

Perhaps splitting types into files would be good. However, if we do so, I'd rather consider higher-level entities: DataViews types, Field types, DataForm types. I'd add these types in src/types.ts for now.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yeah, we need to split the types. The file is big. For now, I moved them in src/types.ts

Comment on lines 15 to 17
type: 'card';
labelPosition?: Extract< LabelPosition, 'top' | 'none' >;
opened?: boolean;
Copy link
Member

@oandregal oandregal Aug 8, 2025

Choose a reason for hiding this comment

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

labelPosition: I understand where this is coming from, but this is a boolean camouflaged as a set. The semantics of this prop are different from the semantics of labelPosition in regular and panel layouts, and so I think its name should reflect that. Some options: withHeader, hasHeader, etc. Specially considering that the layout object needs to have different props per layout type given its different characteristics (opened is not translatable to regular/panel layouts).

opened: this is a small nit. isOpened would better communicate that is a boolean.

Copy link
Member

Choose a reason for hiding this comment

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

I've seen designs with and without a collapsible header. If we were to support both, I think we could just add a new isCollapsible prop in the CardLayout to control that specific aspect. No need to do anything in this PR, just wanted to share for our future selves.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

It makes sense. I used isOpened and withHeader 👍

@gigitux gigitux self-assigned this Aug 8, 2025
( {
layout: {
type: 'card',
// labelPosition: 'none',
Copy link
Member

Choose a reason for hiding this comment

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

Note this bug: if I set labelPosition: none the 1st and 3rd card still display the header. The second doesn't (whether or not the field overrides, as I've added). I haven't checked implementation yet, but I suppose this is because we're checking if the card has a label. I think the labelPosition should trump label: this is something that would be clearer the name was something like withHeader (see other 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.

I fixed the code. This is how the story looks:

image

To keep the logic simple, if a field specifies a layout but omits some keys, those keys fall back to the default values of that layout type, not to form.layout.

For example, even if form.layout.withHeader is false, the taxConfiguration field has the header.

Copy link
Member

Choose a reason for hiding this comment

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

To keep the logic simple, if a field specifies a layout but omits some keys, those keys fall back to the default values of that layout type, not to form.layout.

👍 I think this is also easier to reason about when you are a form author.

Copy link
Member

Choose a reason for hiding this comment

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

I've tested nesting layouts a bit more and it works as expected. It doesn't mean it creates "good designs" (see examples about nesting a card within a card), it means this is ready for when we introduce more container-like layouts (e.g., tabs, rows, etc.) that need nesting.

Some examples include nesting cards within other cards, panel, or regular layouts:

Screenshot 2025-08-08 at 14 07 16 Screenshot 2025-08-08 at 14 04 40 Screenshot 2025-08-08 at 13 32 27

label: 'Taxes',
layout: {
type: 'card',
opened: false, // TODO: it does not work.
Copy link
Member

Choose a reason for hiding this comment

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

I've tried to collapse this card, and it didn't work.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Fixed 👍

Comment on lines +733 to +739
{ id: 'order', layout: { type: 'card' } },
{
id: 'authorDateCard',
label: 'Author & Date',
layout: {
type: 'card',
},
children: [ 'author', 'date' ],
},
Copy link
Member

Choose a reason for hiding this comment

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

Note this: both the single field order and the combined field authorDateCard set the layout to card without setting anything else. However, order gets the label rendered for its control, but authorDateCard doesn't for its children:

Screenshot 2025-08-08 at 10 59 40

I know it is doable to configure it, and why it happens (it's optimized for the panel layout). But a better default in this case would be the opposite: cards with a single field don't get the control's label displayed, and cards with multiple fields do. Alternatively, defaulting to always display the label sounds fine as well because cards with many controls will be more common than cards with a single control.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Fixed:

Image

opened: false, // TODO: it does not work.
},
children: [
// TODO: default values.
Copy link
Member

Choose a reason for hiding this comment

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

@gigitux
Copy link
Contributor Author

gigitux commented Aug 8, 2025

Thanks for confirming the direction! I'm working on clean up the code and address your feedback. I want to get your tought on this: based on this configuration

image

Should the taxConfiguration card inherit withHeader from form.layout, or fall back to the default withHeader of the card layout?

@gigitux
Copy link
Contributor Author

gigitux commented Aug 8, 2025

Thanks for confirming the direction! I'm working on clean up the code and address your feedback. I want to get your tought on this: based on this configuration

image Should the `taxConfiguration` card inherit `withHeader` from `form.layout`, or fall back to the default `withHeader` of the card layout?

I added my opinion in this comment.

@gigitux
Copy link
Contributor Author

gigitux commented Aug 8, 2025

The only weird thing that I noticed is that with isOpened:false and withHeader:false, the card looks like this:

Markup 2025-08-08 at 11 52 29

The card can't be expanded because the “collapse” behavior is attached to the header. I would not focus too much on this in this PR. We can iterate on it.

@oandregal
Copy link
Member

oandregal commented Aug 8, 2025

The only weird thing that I noticed is that with isOpened:false and withHeader:false, the card looks like this:

The combination is possible, so we need to cover this case, even if it's a mistake on the consumer side. Can we return null, so no component is rendered?

@gigitux
Copy link
Contributor Author

gigitux commented Aug 8, 2025

The only weird thing that I noticed is that with isOpened:false and withHeader:false, the card looks like this:

The combination is possible, so we need to cover this case, even if it's a mistake on the consumer side. Can we return null, so no component is rendered?

This can be more confusing, especially if the consumer marks the field as required. The form would be invalid, but the reason might not be obvious to the consumer.

Can we refine the type so that if withHeader is false, isOpened cannot be false? At least, the consumer would see the error on the IDE.

@github-actions
Copy link

github-actions bot commented Aug 8, 2025

Flaky tests detected in 13e7318.
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/16935682561
📝 Reported issues:

@gigitux gigitux marked this pull request as ready for review August 8, 2025 12:07
@github-actions
Copy link

github-actions bot commented Aug 8, 2025

The following accounts have interacted with this PR and/or linked issues. I will continue to update these lists as activity occurs. You can also manually ask me to refresh this list by adding the props-bot label.

If you're merging code through a pull request on GitHub, copy and paste the following into the bottom of the merge commit message.

Co-authored-by: gigitux <[email protected]>
Co-authored-by: oandregal <[email protected]>

To understand the WordPress project's expectations around crediting contributors, please review the Contributor Attribution page in the Core Handbook.

@gigitux gigitux mentioned this pull request Aug 8, 2025
@oandregal
Copy link
Member

The only weird thing that I noticed is that with isOpened:false and withHeader:false
Can we refine the type so that if withHeader is false, isOpened cannot be false? At least, the consumer would see the error on the IDE.

I've updated the types as suggested, but also prevented this from happening by keeping the card open if the header is not present.

@oandregal oandregal force-pushed the add/dataviews-card-layout branch from 13e7318 to d430080 Compare August 13, 2025 12:39
@oandregal oandregal force-pushed the add/dataviews-card-layout branch from 9f8cb83 to f9e1609 Compare August 14, 2025 14:17
@oandregal oandregal changed the title Add Card Layout support DataForm: add new card layout Aug 14, 2025
typeof child === 'string' || ! isCombinedField( child )
);

if ( simpleChildren.length === 0 ) {
Copy link
Member

Choose a reason for hiding this comment

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

This fixes a bug with the panel layout that threw an error at runtime when it didn't have any children that were not "combined fields".

fields: [ { id: field.id } ],
};
}, [ field ] );

Copy link
Member

Choose a reason for hiding this comment

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

This is a simplification: the form field normalization is already performed by DataFormLayout.

}

const labelPosition = field.labelPosition ?? 'side';
const layout: NormalizedPanelLayout = normalizeLayout( {
Copy link
Member

@oandregal oandregal Aug 14, 2025

Choose a reason for hiding this comment

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

Centralized every layout normalization in a single place because there were bugs related to having different defaults per layout (depending on the field being at the top-level or nested). I think this can be improved further because the types and the runtime behavior are out of sync: the fields are already normalized at this point. It was a bit involved to change the pre-existing types, so this can be a follow-up.

@oandregal oandregal merged commit de14dd4 into trunk Aug 14, 2025
92 of 130 checks passed
@oandregal oandregal deleted the add/dataviews-card-layout branch August 14, 2025 16:04
@github-actions github-actions bot added this to the Gutenberg 21.5 milestone Aug 14, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

[Feature] DataViews Work surrounding upgrading and evolving views in the site editor and beyond [Type] Enhancement A suggestion for improvement.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants