Skip to content

UI: Implement Box component as part of new UI package#72984

Merged
aduth merged 7 commits intotrunkfrom
add/box-component
Nov 11, 2025
Merged

UI: Implement Box component as part of new UI package#72984
aduth merged 7 commits intotrunkfrom
add/box-component

Conversation

@aduth
Copy link
Member

@aduth aduth commented Nov 4, 2025

What?

Adds a new Box component as part of a new @wordpress/ui package, a common primitive component that can be used as a low-level basis for design systems-based components based on shared design standards for e.g. spacing, color, etc.

Partially completes #72784 (some features excluded for follow-on)
Related to #71196

Why?

See rationale for this approach in the related issues #72784 and #71196

The included changes also elaborate on the rationale for introducing a new package:

While similar in scope to `@wordpress/components`, there are a few key differences:
- `@wordpress/components` grew organically as a collection of unrelated UI elements for WordPress screens. In contrast, this package is an implementation of a design system that guarantees user- and developer-facing cohesion between components.
- Unlike `@wordpress/components`, this package is not bundled as a WordPress script available on the `window.wp` global and is instead distributed as an npm package that follows [semantic versioning](https://semver.org/) for release changes.

How?

  • Adds a new @wordpress/ui package with documented "core design principles" for design system components
  • Adds a new Box component as part of this package following those core design principles and extending theme tokens
  • Expands theme tokens to introduce a handful of new semantic spacing tokens as an initial demonstration of tokens-based customization, and explicitly marking the existing set as "primitive" (private) tokens

Note that this is intended to be an early iteration and doesn't fully implement all of the features outlined in #72784

Additionally, there are a number of things I'd like to explore separately for further enhancement, like default "density" integration with ThemeProvider and responsive customization.

Testing Instructions

Verify behavior of Box component in the included Storybook stories.

  1. Run npm run storybook:dev
  2. Go to http://localhost:50240/?path=/docs/design-system-components-box--docs

Screenshots or screencast

Storybook screenshot

@aduth aduth requested review from a team and jameskoster November 4, 2025 22:03
@github-actions
Copy link

github-actions bot commented Nov 4, 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: aduth <aduth@git.wordpress.org>
Co-authored-by: aaronrobertshaw <aaronrobertshaw@git.wordpress.org>
Co-authored-by: getdave <get_dave@git.wordpress.org>
Co-authored-by: ramonjd <ramonopoly@git.wordpress.org>
Co-authored-by: scruffian <scruffian@git.wordpress.org>
Co-authored-by: tyxla <tyxla@git.wordpress.org>
Co-authored-by: jameskoster <jameskoster@git.wordpress.org>

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

Comment on lines +40 to +47
type DimensionVariant< T > = {
block?: T;
blockStart?: T;
blockEnd?: T;
inline?: T;
inlineStart?: T;
inlineEnd?: T;
};
Copy link
Member Author

Choose a reason for hiding this comment

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

Here I'm taking inspiration from @gigitux's direction for an optional object of directions adopted in #72511. It was made generic with the expectation we could reuse it for margin, though I'm not 100% sure if we want margin support.

Comment on lines +10 to +38
type BackgroundColor =
| 'neutral'
| 'neutral-strong'
| 'neutral-weak'
| 'brand'
| 'success'
| 'success-weak'
| 'info'
| 'info-weak'
| 'warning'
| 'warning-weak'
| 'caution'
| 'caution-weak'
| 'error'
| 'error-weak';

type ForegroundColor =
| 'neutral'
| 'neutral-weak'
| 'success'
| 'success-weak'
| 'info'
| 'info-weak'
| 'warning'
| 'warning-weak'
| 'caution'
| 'caution-weak'
| 'error'
| 'error-weak';
Copy link
Member Author

Choose a reason for hiding this comment

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

In earlier iterations I tried building these up from the color scheme options, but we don't actually support all the combinations within "surface" background or foreground colors. I think that's intentional, but it requires more effort to explicitly list out the tokens which are supported. The way this was implemented also imagines that we might allow for more "families" to be introduced in the future like a "card" family, which would require some revisions to the typings if those other families support different options.

Earlier iteration of color scheme types
type ColorTone =
  | "neutral"
  | "brand"
  | "success"
  | "info"
  | "warning"
  | "caution"
  | "error";

type ColorEmphasis = "weak" | "strong";

type ColorState = "active" | "disabled";

type ColorString =
  | `${ColorTone}`
  | `${ColorTone}-${ColorEmphasis}`
  | `${ColorTone}-${ColorEmphasis}-${ColorState}`;

Comment on lines 55 to 65
/**
* The surface background design token for box background color.
*
* Shorthand for `background`.
*/
bg?: BackgroundColor;

/**
* The surface background design token for box background color.
*/
background?: BackgroundColor;
Copy link
Member Author

Choose a reason for hiding this comment

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

I'm not fixed to this idea of supporting both short-form and long-form props, but it seems like a nice balance between explicitness and ergonomics for frequent usage. We also use shorthand like "bg" in our tokens, so I wanted to be consistent.

Copy link
Contributor

Choose a reason for hiding this comment

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

I’m not fully up to speed with the new UI package, so this may not be an issue, but it might be worth considering how this prop maps to the underlying CSS. In the past, early implementations of the background color block support used the shorthand background property, which later conflicted with the background-image support — especially when both were combined.

If these props are intended to define only the background color, would it make sense to name them more explicitly (e.g. backgroundColor / bgColor) to avoid similar issues down the line?

Copy link
Member Author

Choose a reason for hiding this comment

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

That's a great observation @aaronrobertshaw ! I'll put some more thought into this, and at least come up with a plan for if / how we'd reconcile if we needed to expand to cover different aspects of background or text.

Copy link
Member Author

Choose a reason for hiding this comment

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

After thinking about this a bit more, I think bg could work as-is:

  • The purpose of this component is in providing an integration to the design system tokens, and specifically (in this implementation) color and spacing tokens. I don't see "image" (in background-image) or most other background-related properties being tokenized in the same way as color.
  • Even if we needed to expand this, we could support those variations as suffixed properties (e.g. bgImage)
  • For context, a motivation for keeping this name as-is is ergonomics for common usage patterns, <Box bg="brand" /> is concise and easy to grok

But I agree in some regards:

  • Maybe, like in how similar shorthand is used in e.g. Chakra UI, we should have the long-form variant fully-spelled out as backgroundColor, or at the very least backgroundColor available as an alias
  • We'll want to be clear in documentation that bg maps to color. As it stands, the documentation is largely exposed through Storybook stories, which do inherit the TSDoc comment above that references "box background color"

It also got me on a rabbit-hole of thinking of a "clever" solution involving aligning these props one-to-one with the underlying CSSStyleProperties interface, i.e. element.style.backgroundColor = '...' and whether we could have the internal behavior be a more generalized pass-through to style properties with a layer to map values to tokens. This might create some unnecessary complexity or have some conflicts, but I'll plan to do a time-boxed exploration of the idea.

Copy link
Member

Choose a reason for hiding this comment

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

later conflicted with the background-image support — especially when both were combined.

For visibility, here's the old issue.

One of the main pain points is that gradient values are set with background as well. Not sure when, but we'd really like to fix this one day to support transparent layers.

Copy link
Member Author

Choose a reason for hiding this comment

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

  • Maybe, like in how similar shorthand is used in e.g. Chakra UI, we should have the long-form variant fully-spelled out as backgroundColor, or at the very least backgroundColor available as an alias

In b09519f, I revised the long-form names from background and foreground to backgroundColor and color.

Here's how I'm thinking we can approach this:

  • Supported props should align to the CSS property that they control
  • Short-hand props should be limited to a few select, very common props

In this way, we could easily expand to add backgroundImage or other styles, and those would not be expected to have short-hand props anyways.

It occurred to me that this is something we'll soon encounter with handling borders, where we'll likely want to support at least both borderColor and borderRadius.

Copy link
Member

Choose a reason for hiding this comment

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

Coming in late to this, but I think there are a lot of small downsides to having prop aliases, and I'm not sure the benefits will outweigh the downsides here.

  • Adds complexity when doing any kind of AST analysis or modification (e.g. lint rules, codemods, prop usage stats).
  • Has a learning curve for humans who see the shorthand for the first time.
  • Consistency concerns within a single file will subtly add to the cognitive load ("which prop version should I use here?") and affect searchability.
  • Adds noise to documentation.
  • Subtle bugs when both the canonical prop and alias prop are added mistakenly with different values.

I would also note that "shorthand" as in CSS properties are not aliases, they are shorthands for setting multiple properties at once. CSS would be even more chaotic if it had property aliases.

So I think we should pick a canonical prop name and stick with it. And given that fewer people are typing out their code letter by letter these days, maybe there isn't much benefit to abbreviating them to the shortest possible string.

Copy link
Member Author

Choose a reason for hiding this comment

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

I think those are valid points. It's occurred to me as well in reflecting on how the idea with shorthands is often to enable "power users" to have a more expressive APIs, that's not really very considerate of the people who end up maintaining said "power users" code down the line, who may benefit from the more verbose alternative and the consistency of having a consistent way of interacting with these components.

Maybe we can just remove it and evaluate whether it's a problem. We can always revisit it down the line and add it as a backwards-compatible enhancement if we think it'd prove valuable.

Copy link
Member Author

Choose a reason for hiding this comment

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

Follow-up at #73529

@github-actions
Copy link

github-actions bot commented Nov 4, 2025

Size Change: +312 B (+0.01%)

Total Size: 2.42 MB

Filename Size Change
build/modules/boot/index.min.js 79.9 kB +315 B (+0.4%)
build/scripts/theme/index.min.js 21.5 kB -3 B (-0.01%)
ℹ️ View Unchanged
Filename Size
build/modules/a11y/index.min.js 355 B
build/modules/block-editor/utils/fit-text-frontend.min.js 440 B
build/modules/block-library/accordion/view.min.js 528 B
build/modules/block-library/file/view.min.js 346 B
build/modules/block-library/form/view.min.js 528 B
build/modules/block-library/image/view.min.js 1.95 kB
build/modules/block-library/navigation/view.min.js 1.03 kB
build/modules/block-library/query/view.min.js 518 B
build/modules/block-library/search/view.min.js 498 B
build/modules/block-library/tabs/view.min.js 776 B
build/modules/interactivity-router/full-page.min.js 451 B
build/modules/interactivity-router/index.min.js 11.5 kB
build/modules/interactivity/index.min.js 14.9 kB
build/modules/latex-to-mathml/index.min.js 56.5 kB
build/modules/latex-to-mathml/loader.min.js 131 B
build/modules/lazy-editor/index.min.js 12.1 kB
build/scripts/a11y/index.min.js 1.06 kB
build/scripts/annotations/index.min.js 2.38 kB
build/scripts/api-fetch/index.min.js 2.83 kB
build/scripts/autop/index.min.js 2.18 kB
build/scripts/blob/index.min.js 631 B
build/scripts/block-directory/index.min.js 8.03 kB
build/scripts/block-editor/index.min.js 296 kB
build/scripts/block-library/index.min.js 273 kB
build/scripts/block-serialization-default-parser/index.min.js 1.16 kB
build/scripts/block-serialization-spec-parser/index.min.js 3.08 kB
build/scripts/blocks/index.min.js 56.1 kB
build/scripts/commands/index.min.js 17.4 kB
build/scripts/components/index.min.js 271 kB
build/scripts/compose/index.min.js 13.8 kB
build/scripts/core-commands/index.min.js 4.13 kB
build/scripts/core-data/index.min.js 86 kB
build/scripts/customize-widgets/index.min.js 12.3 kB
build/scripts/data-controls/index.min.js 793 B
build/scripts/data/index.min.js 9.61 kB
build/scripts/date/index.min.js 23.6 kB
build/scripts/deprecated/index.min.js 752 B
build/scripts/dom-ready/index.min.js 476 B
build/scripts/dom/index.min.js 4.91 kB
build/scripts/edit-post/index.min.js 16.4 kB
build/scripts/edit-site/index.min.js 229 kB
build/scripts/edit-widgets/index.min.js 20 kB
build/scripts/editor/index.min.js 283 kB
build/scripts/element/index.min.js 5.19 kB
build/scripts/escape-html/index.min.js 586 B
build/scripts/format-library/index.min.js 10.7 kB
build/scripts/hooks/index.min.js 1.83 kB
build/scripts/html-entities/index.min.js 494 B
build/scripts/i18n/index.min.js 2.46 kB
build/scripts/is-shallow-equal/index.min.js 568 B
build/scripts/keyboard-shortcuts/index.min.js 1.57 kB
build/scripts/keycodes/index.min.js 1.53 kB
build/scripts/list-reusable-blocks/index.min.js 2.44 kB
build/scripts/media-utils/index.min.js 64.9 kB
build/scripts/notices/index.min.js 1.11 kB
build/scripts/nux/index.min.js 1.88 kB
build/scripts/patterns/index.min.js 7.88 kB
build/scripts/plugins/index.min.js 2.14 kB
build/scripts/preferences-persistence/index.min.js 2.15 kB
build/scripts/preferences/index.min.js 3.31 kB
build/scripts/primitives/index.min.js 1.01 kB
build/scripts/priority-queue/index.min.js 1.61 kB
build/scripts/private-apis/index.min.js 1.1 kB
build/scripts/react-i18n/index.min.js 832 B
build/scripts/react-refresh-entry/index.min.js 9.44 kB
build/scripts/react-refresh-runtime/index.min.js 3.59 kB
build/scripts/redux-routine/index.min.js 3.36 kB
build/scripts/reusable-blocks/index.min.js 2.93 kB
build/scripts/rich-text/index.min.js 12.9 kB
build/scripts/router/index.min.js 5.96 kB
build/scripts/server-side-render/index.min.js 1.91 kB
build/scripts/shortcode/index.min.js 1.58 kB
build/scripts/style-engine/index.min.js 2.32 kB
build/scripts/token-list/index.min.js 739 B
build/scripts/undo-manager/index.min.js 917 B
build/scripts/url/index.min.js 3.98 kB
build/scripts/vendors/react-dom.min.js 43 kB
build/scripts/vendors/react-jsx-runtime.min.js 691 B
build/scripts/vendors/react.min.js 4.27 kB
build/scripts/viewport/index.min.js 1.22 kB
build/scripts/warning/index.min.js 454 B
build/scripts/widgets/index.min.js 7.81 kB
build/scripts/wordcount/index.min.js 1.04 kB
build/styles/block-directory/style-rtl.css 1.05 kB
build/styles/block-directory/style.css 1.05 kB
build/styles/block-editor/content-rtl.css 4.79 kB
build/styles/block-editor/content.css 4.79 kB
build/styles/block-editor/default-editor-styles-rtl.css 224 B
build/styles/block-editor/default-editor-styles.css 224 B
build/styles/block-editor/style-rtl.css 16 kB
build/styles/block-editor/style.css 15.9 kB
build/styles/block-library/accordion-heading/style-rtl.css 395 B
build/styles/block-library/accordion-heading/style.css 395 B
build/styles/block-library/accordion-item/style-rtl.css 213 B
build/styles/block-library/accordion-item/style.css 213 B
build/styles/block-library/accordion-panel/style-rtl.css 121 B
build/styles/block-library/accordion-panel/style.css 121 B
build/styles/block-library/archives/editor-rtl.css 61 B
build/styles/block-library/archives/editor.css 61 B
build/styles/block-library/archives/style-rtl.css 90 B
build/styles/block-library/archives/style.css 90 B
build/styles/block-library/audio/editor-rtl.css 149 B
build/styles/block-library/audio/editor.css 151 B
build/styles/block-library/audio/style-rtl.css 132 B
build/styles/block-library/audio/style.css 132 B
build/styles/block-library/audio/theme-rtl.css 134 B
build/styles/block-library/audio/theme.css 134 B
build/styles/block-library/avatar/editor-rtl.css 115 B
build/styles/block-library/avatar/editor.css 115 B
build/styles/block-library/avatar/style-rtl.css 104 B
build/styles/block-library/avatar/style.css 104 B
build/styles/block-library/breadcrumbs/style-rtl.css 203 B
build/styles/block-library/breadcrumbs/style.css 203 B
build/styles/block-library/button/editor-rtl.css 265 B
build/styles/block-library/button/editor.css 265 B
build/styles/block-library/button/style-rtl.css 554 B
build/styles/block-library/button/style.css 554 B
build/styles/block-library/buttons/editor-rtl.css 291 B
build/styles/block-library/buttons/editor.css 291 B
build/styles/block-library/buttons/style-rtl.css 349 B
build/styles/block-library/buttons/style.css 349 B
build/styles/block-library/calendar/style-rtl.css 239 B
build/styles/block-library/calendar/style.css 239 B
build/styles/block-library/categories/editor-rtl.css 132 B
build/styles/block-library/categories/editor.css 131 B
build/styles/block-library/categories/style-rtl.css 152 B
build/styles/block-library/categories/style.css 152 B
build/styles/block-library/classic-rtl.css 179 B
build/styles/block-library/classic.css 179 B
build/styles/block-library/code/editor-rtl.css 53 B
build/styles/block-library/code/editor.css 53 B
build/styles/block-library/code/style-rtl.css 139 B
build/styles/block-library/code/style.css 139 B
build/styles/block-library/code/theme-rtl.css 122 B
build/styles/block-library/code/theme.css 122 B
build/styles/block-library/columns/editor-rtl.css 108 B
build/styles/block-library/columns/editor.css 108 B
build/styles/block-library/columns/style-rtl.css 421 B
build/styles/block-library/columns/style.css 421 B
build/styles/block-library/comment-author-avatar/editor-rtl.css 124 B
build/styles/block-library/comment-author-avatar/editor.css 124 B
build/styles/block-library/comment-author-name/style-rtl.css 72 B
build/styles/block-library/comment-author-name/style.css 72 B
build/styles/block-library/comment-content/style-rtl.css 120 B
build/styles/block-library/comment-content/style.css 120 B
build/styles/block-library/comment-date/style-rtl.css 65 B
build/styles/block-library/comment-date/style.css 65 B
build/styles/block-library/comment-edit-link/style-rtl.css 70 B
build/styles/block-library/comment-edit-link/style.css 70 B
build/styles/block-library/comment-reply-link/style-rtl.css 71 B
build/styles/block-library/comment-reply-link/style.css 71 B
build/styles/block-library/comment-template/style-rtl.css 191 B
build/styles/block-library/comment-template/style.css 191 B
build/styles/block-library/comments-pagination-numbers/editor-rtl.css 122 B
build/styles/block-library/comments-pagination-numbers/editor.css 121 B
build/styles/block-library/comments-pagination/editor-rtl.css 168 B
build/styles/block-library/comments-pagination/editor.css 168 B
build/styles/block-library/comments-pagination/style-rtl.css 201 B
build/styles/block-library/comments-pagination/style.css 201 B
build/styles/block-library/comments-title/editor-rtl.css 75 B
build/styles/block-library/comments-title/editor.css 75 B
build/styles/block-library/comments/editor-rtl.css 842 B
build/styles/block-library/comments/editor.css 842 B
build/styles/block-library/comments/style-rtl.css 637 B
build/styles/block-library/comments/style.css 637 B
build/styles/block-library/common-rtl.css 1.11 kB
build/styles/block-library/common.css 1.11 kB
build/styles/block-library/cover/editor-rtl.css 631 B
build/styles/block-library/cover/editor.css 631 B
build/styles/block-library/cover/style-rtl.css 1.7 kB
build/styles/block-library/cover/style.css 1.69 kB
build/styles/block-library/details/editor-rtl.css 65 B
build/styles/block-library/details/editor.css 65 B
build/styles/block-library/details/style-rtl.css 86 B
build/styles/block-library/details/style.css 86 B
build/styles/block-library/editor-elements-rtl.css 75 B
build/styles/block-library/editor-elements.css 75 B
build/styles/block-library/editor-rtl.css 11.8 kB
build/styles/block-library/editor.css 11.8 kB
build/styles/block-library/elements-rtl.css 54 B
build/styles/block-library/elements.css 54 B
build/styles/block-library/embed/editor-rtl.css 331 B
build/styles/block-library/embed/editor.css 331 B
build/styles/block-library/embed/style-rtl.css 448 B
build/styles/block-library/embed/style.css 448 B
build/styles/block-library/embed/theme-rtl.css 133 B
build/styles/block-library/embed/theme.css 133 B
build/styles/block-library/file/editor-rtl.css 324 B
build/styles/block-library/file/editor.css 324 B
build/styles/block-library/file/style-rtl.css 278 B
build/styles/block-library/file/style.css 278 B
build/styles/block-library/footnotes/style-rtl.css 198 B
build/styles/block-library/footnotes/style.css 197 B
build/styles/block-library/form-input/editor-rtl.css 229 B
build/styles/block-library/form-input/editor.css 229 B
build/styles/block-library/form-input/style-rtl.css 366 B
build/styles/block-library/form-input/style.css 366 B
build/styles/block-library/form-submission-notification/editor-rtl.css 344 B
build/styles/block-library/form-submission-notification/editor.css 341 B
build/styles/block-library/form-submit-button/style-rtl.css 69 B
build/styles/block-library/form-submit-button/style.css 69 B
build/styles/block-library/freeform/editor-rtl.css 2.59 kB
build/styles/block-library/freeform/editor.css 2.59 kB
build/styles/block-library/gallery/editor-rtl.css 615 B
build/styles/block-library/gallery/editor.css 616 B
build/styles/block-library/gallery/style-rtl.css 1.84 kB
build/styles/block-library/gallery/style.css 1.84 kB
build/styles/block-library/gallery/theme-rtl.css 108 B
build/styles/block-library/gallery/theme.css 108 B
build/styles/block-library/group/editor-rtl.css 335 B
build/styles/block-library/group/editor.css 335 B
build/styles/block-library/group/style-rtl.css 103 B
build/styles/block-library/group/style.css 103 B
build/styles/block-library/group/theme-rtl.css 79 B
build/styles/block-library/group/theme.css 79 B
build/styles/block-library/heading/style-rtl.css 205 B
build/styles/block-library/heading/style.css 205 B
build/styles/block-library/html/editor-rtl.css 440 B
build/styles/block-library/html/editor.css 441 B
build/styles/block-library/image/editor-rtl.css 763 B
build/styles/block-library/image/editor.css 763 B
build/styles/block-library/image/style-rtl.css 1.6 kB
build/styles/block-library/image/style.css 1.59 kB
build/styles/block-library/image/theme-rtl.css 137 B
build/styles/block-library/image/theme.css 137 B
build/styles/block-library/latest-comments/style-rtl.css 355 B
build/styles/block-library/latest-comments/style.css 354 B
build/styles/block-library/latest-posts/editor-rtl.css 139 B
build/styles/block-library/latest-posts/editor.css 138 B
build/styles/block-library/latest-posts/style-rtl.css 520 B
build/styles/block-library/latest-posts/style.css 520 B
build/styles/block-library/list/style-rtl.css 107 B
build/styles/block-library/list/style.css 107 B
build/styles/block-library/loginout/style-rtl.css 61 B
build/styles/block-library/loginout/style.css 61 B
build/styles/block-library/math/editor-rtl.css 105 B
build/styles/block-library/math/editor.css 105 B
build/styles/block-library/math/style-rtl.css 61 B
build/styles/block-library/math/style.css 61 B
build/styles/block-library/media-text/editor-rtl.css 321 B
build/styles/block-library/media-text/editor.css 320 B
build/styles/block-library/media-text/style-rtl.css 543 B
build/styles/block-library/media-text/style.css 542 B
build/styles/block-library/more/editor-rtl.css 393 B
build/styles/block-library/more/editor.css 393 B
build/styles/block-library/navigation-link/editor-rtl.css 645 B
build/styles/block-library/navigation-link/editor.css 647 B
build/styles/block-library/navigation-link/style-rtl.css 190 B
build/styles/block-library/navigation-link/style.css 188 B
build/styles/block-library/navigation-submenu/editor-rtl.css 295 B
build/styles/block-library/navigation-submenu/editor.css 294 B
build/styles/block-library/navigation/editor-rtl.css 2.24 kB
build/styles/block-library/navigation/editor.css 2.24 kB
build/styles/block-library/navigation/style-rtl.css 2.27 kB
build/styles/block-library/navigation/style.css 2.25 kB
build/styles/block-library/nextpage/editor-rtl.css 392 B
build/styles/block-library/nextpage/editor.css 392 B
build/styles/block-library/page-list/editor-rtl.css 356 B
build/styles/block-library/page-list/editor.css 356 B
build/styles/block-library/page-list/style-rtl.css 192 B
build/styles/block-library/page-list/style.css 192 B
build/styles/block-library/paragraph/editor-rtl.css 251 B
build/styles/block-library/paragraph/editor.css 251 B
build/styles/block-library/paragraph/style-rtl.css 341 B
build/styles/block-library/paragraph/style.css 340 B
build/styles/block-library/post-author-biography/style-rtl.css 74 B
build/styles/block-library/post-author-biography/style.css 74 B
build/styles/block-library/post-author-name/style-rtl.css 69 B
build/styles/block-library/post-author-name/style.css 69 B
build/styles/block-library/post-author/style-rtl.css 188 B
build/styles/block-library/post-author/style.css 189 B
build/styles/block-library/post-comments-count/style-rtl.css 72 B
build/styles/block-library/post-comments-count/style.css 72 B
build/styles/block-library/post-comments-form/editor-rtl.css 96 B
build/styles/block-library/post-comments-form/editor.css 96 B
build/styles/block-library/post-comments-form/style-rtl.css 525 B
build/styles/block-library/post-comments-form/style.css 525 B
build/styles/block-library/post-comments-link/style-rtl.css 71 B
build/styles/block-library/post-comments-link/style.css 71 B
build/styles/block-library/post-content/style-rtl.css 61 B
build/styles/block-library/post-content/style.css 61 B
build/styles/block-library/post-date/style-rtl.css 62 B
build/styles/block-library/post-date/style.css 62 B
build/styles/block-library/post-excerpt/editor-rtl.css 71 B
build/styles/block-library/post-excerpt/editor.css 71 B
build/styles/block-library/post-excerpt/style-rtl.css 155 B
build/styles/block-library/post-excerpt/style.css 155 B
build/styles/block-library/post-featured-image/editor-rtl.css 719 B
build/styles/block-library/post-featured-image/editor.css 717 B
build/styles/block-library/post-featured-image/style-rtl.css 347 B
build/styles/block-library/post-featured-image/style.css 347 B
build/styles/block-library/post-navigation-link/style-rtl.css 215 B
build/styles/block-library/post-navigation-link/style.css 214 B
build/styles/block-library/post-template/style-rtl.css 414 B
build/styles/block-library/post-template/style.css 414 B
build/styles/block-library/post-terms/style-rtl.css 96 B
build/styles/block-library/post-terms/style.css 96 B
build/styles/block-library/post-time-to-read/style-rtl.css 70 B
build/styles/block-library/post-time-to-read/style.css 70 B
build/styles/block-library/post-title/style-rtl.css 162 B
build/styles/block-library/post-title/style.css 162 B
build/styles/block-library/preformatted/style-rtl.css 125 B
build/styles/block-library/preformatted/style.css 125 B
build/styles/block-library/pullquote/editor-rtl.css 133 B
build/styles/block-library/pullquote/editor.css 133 B
build/styles/block-library/pullquote/style-rtl.css 365 B
build/styles/block-library/pullquote/style.css 365 B
build/styles/block-library/pullquote/theme-rtl.css 176 B
build/styles/block-library/pullquote/theme.css 176 B
build/styles/block-library/query-pagination-numbers/editor-rtl.css 121 B
build/styles/block-library/query-pagination-numbers/editor.css 118 B
build/styles/block-library/query-pagination/editor-rtl.css 154 B
build/styles/block-library/query-pagination/editor.css 154 B
build/styles/block-library/query-pagination/style-rtl.css 237 B
build/styles/block-library/query-pagination/style.css 237 B
build/styles/block-library/query-title/style-rtl.css 64 B
build/styles/block-library/query-title/style.css 64 B
build/styles/block-library/query-total/style-rtl.css 64 B
build/styles/block-library/query-total/style.css 64 B
build/styles/block-library/query/editor-rtl.css 438 B
build/styles/block-library/query/editor.css 438 B
build/styles/block-library/quote/style-rtl.css 238 B
build/styles/block-library/quote/style.css 238 B
build/styles/block-library/quote/theme-rtl.css 233 B
build/styles/block-library/quote/theme.css 236 B
build/styles/block-library/read-more/style-rtl.css 131 B
build/styles/block-library/read-more/style.css 131 B
build/styles/block-library/reset-rtl.css 472 B
build/styles/block-library/reset.css 472 B
build/styles/block-library/rss/editor-rtl.css 126 B
build/styles/block-library/rss/editor.css 126 B
build/styles/block-library/rss/style-rtl.css 284 B
build/styles/block-library/rss/style.css 283 B
build/styles/block-library/search/editor-rtl.css 199 B
build/styles/block-library/search/editor.css 199 B
build/styles/block-library/search/style-rtl.css 665 B
build/styles/block-library/search/style.css 666 B
build/styles/block-library/search/theme-rtl.css 113 B
build/styles/block-library/search/theme.css 113 B
build/styles/block-library/separator/editor-rtl.css 100 B
build/styles/block-library/separator/editor.css 100 B
build/styles/block-library/separator/style-rtl.css 248 B
build/styles/block-library/separator/style.css 248 B
build/styles/block-library/separator/theme-rtl.css 195 B
build/styles/block-library/separator/theme.css 195 B
build/styles/block-library/shortcode/editor-rtl.css 286 B
build/styles/block-library/shortcode/editor.css 286 B
build/styles/block-library/site-logo/editor-rtl.css 773 B
build/styles/block-library/site-logo/editor.css 770 B
build/styles/block-library/site-logo/style-rtl.css 218 B
build/styles/block-library/site-logo/style.css 218 B
build/styles/block-library/site-tagline/editor-rtl.css 87 B
build/styles/block-library/site-tagline/editor.css 87 B
build/styles/block-library/site-tagline/style-rtl.css 65 B
build/styles/block-library/site-tagline/style.css 65 B
build/styles/block-library/site-title/editor-rtl.css 85 B
build/styles/block-library/site-title/editor.css 85 B
build/styles/block-library/site-title/style-rtl.css 143 B
build/styles/block-library/site-title/style.css 143 B
build/styles/block-library/social-link/editor-rtl.css 314 B
build/styles/block-library/social-link/editor.css 314 B
build/styles/block-library/social-links/editor-rtl.css 339 B
build/styles/block-library/social-links/editor.css 338 B
build/styles/block-library/social-links/style-rtl.css 1.51 kB
build/styles/block-library/social-links/style.css 1.51 kB
build/styles/block-library/spacer/editor-rtl.css 346 B
build/styles/block-library/spacer/editor.css 346 B
build/styles/block-library/spacer/style-rtl.css 48 B
build/styles/block-library/spacer/style.css 48 B
build/styles/block-library/style-rtl.css 16.5 kB
build/styles/block-library/style.css 16.5 kB
build/styles/block-library/tab/style-rtl.css 202 B
build/styles/block-library/tab/style.css 202 B
build/styles/block-library/table-of-contents/style-rtl.css 83 B
build/styles/block-library/table-of-contents/style.css 83 B
build/styles/block-library/table/editor-rtl.css 394 B
build/styles/block-library/table/editor.css 394 B
build/styles/block-library/table/style-rtl.css 641 B
build/styles/block-library/table/style.css 640 B
build/styles/block-library/table/theme-rtl.css 152 B
build/styles/block-library/table/theme.css 152 B
build/styles/block-library/tabs/editor-rtl.css 236 B
build/styles/block-library/tabs/editor.css 236 B
build/styles/block-library/tabs/style-rtl.css 983 B
build/styles/block-library/tabs/style.css 983 B
build/styles/block-library/tag-cloud/editor-rtl.css 92 B
build/styles/block-library/tag-cloud/editor.css 92 B
build/styles/block-library/tag-cloud/style-rtl.css 248 B
build/styles/block-library/tag-cloud/style.css 248 B
build/styles/block-library/template-part/editor-rtl.css 368 B
build/styles/block-library/template-part/editor.css 368 B
build/styles/block-library/template-part/theme-rtl.css 113 B
build/styles/block-library/template-part/theme.css 113 B
build/styles/block-library/term-count/style-rtl.css 63 B
build/styles/block-library/term-count/style.css 63 B
build/styles/block-library/term-description/style-rtl.css 126 B
build/styles/block-library/term-description/style.css 126 B
build/styles/block-library/term-name/style-rtl.css 62 B
build/styles/block-library/term-name/style.css 62 B
build/styles/block-library/term-template/editor-rtl.css 225 B
build/styles/block-library/term-template/editor.css 225 B
build/styles/block-library/term-template/style-rtl.css 114 B
build/styles/block-library/term-template/style.css 114 B
build/styles/block-library/text-columns/editor-rtl.css 95 B
build/styles/block-library/text-columns/editor.css 95 B
build/styles/block-library/text-columns/style-rtl.css 165 B
build/styles/block-library/text-columns/style.css 165 B
build/styles/block-library/theme-rtl.css 715 B
build/styles/block-library/theme.css 719 B
build/styles/block-library/verse/style-rtl.css 98 B
build/styles/block-library/verse/style.css 98 B
build/styles/block-library/video/editor-rtl.css 415 B
build/styles/block-library/video/editor.css 416 B
build/styles/block-library/video/style-rtl.css 202 B
build/styles/block-library/video/style.css 202 B
build/styles/block-library/video/theme-rtl.css 134 B
build/styles/block-library/video/theme.css 134 B
build/styles/commands/style-rtl.css 1.72 kB
build/styles/commands/style.css 1.72 kB
build/styles/components/style-rtl.css 14 kB
build/styles/components/style.css 14 kB
build/styles/customize-widgets/style-rtl.css 1.44 kB
build/styles/customize-widgets/style.css 1.44 kB
build/styles/edit-post/classic-rtl.css 426 B
build/styles/edit-post/classic.css 427 B
build/styles/edit-post/style-rtl.css 3.33 kB
build/styles/edit-post/style.css 3.33 kB
build/styles/edit-site/posts-rtl.css 9.85 kB
build/styles/edit-site/posts.css 9.84 kB
build/styles/edit-site/style-rtl.css 15.4 kB
build/styles/edit-site/style.css 15.4 kB
build/styles/edit-widgets/style-rtl.css 4.59 kB
build/styles/edit-widgets/style.css 4.59 kB
build/styles/editor/style-rtl.css 18.1 kB
build/styles/editor/style.css 18.1 kB
build/styles/format-library/style-rtl.css 326 B
build/styles/format-library/style.css 326 B
build/styles/list-reusable-blocks/style-rtl.css 1.02 kB
build/styles/list-reusable-blocks/style.css 1.02 kB
build/styles/nux/style-rtl.css 622 B
build/styles/nux/style.css 618 B
build/styles/patterns/style-rtl.css 611 B
build/styles/patterns/style.css 611 B
build/styles/preferences/style-rtl.css 415 B
build/styles/preferences/style.css 415 B
build/styles/reusable-blocks/style-rtl.css 275 B
build/styles/reusable-blocks/style.css 275 B
build/styles/widgets/style-rtl.css 1.17 kB
build/styles/widgets/style.css 1.18 kB

compressed-size-action

}

if ( fg ) {
style.color = `var(--wpds-color-fg-${ family }-${ fg }, var(--wpds-color-fg-content-${ fg }))`;
Copy link
Member Author

Choose a reason for hiding this comment

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

There is no "surface" family for foreground tokens, but this fallback behavior works nicely for allowing us to define "surface" as the default family, as well as future or custom families that may define some or all of their own tokens.

@aduth aduth added [Type] Experimental Experimental feature or API. [Feature] Component System WordPress component system labels Nov 4, 2025
@youknowriad youknowriad requested a review from a team November 4, 2025 23:19
@jameskoster
Copy link
Contributor

This looks great 😊

@aduth
Copy link
Member Author

aduth commented Nov 5, 2025

Highlighting a few specific things I'm interested in feedback on:

  • We can iterate on spacing tokens more, but I'm interested in initial thoughts on the proposal here for primitive and semantic tokens
    • Do we really want to keep the same steps like what we have in @wordpress/base-styles (05, 10, etc.) or should we adopt a different convention? Since these will be private (truly private with Theme: Inline values for primitive tokens in CSS output #72890), maybe we can make a greenfield choice here without much impact?
    • The values I chose for the padding-surface semantic values were pretty arbitrary and I'm happy to revise them. Similarly if we want to add more or use different naming for the steps (currently x-small, small, medium, large). These are mostly inherited from base-styles and while these are public-facing and we should be mindful to migration pathways, we could consider revisiting if there's a compelling argument (e.g. aligning terminology across future potential tokens like viewport sizes, aligning around short-hand vs. long-hand naming, etc.)
      • Example: I'm considering ideas around future responsive support and a "prop based modifier" convention similar to Chakra UI, where we'd want some alignment if we chose to go with names like medium / md to use consistently across tokens, while having good ergonomics (e.g. <Box p={ { default: 'md', md: 'lg' } } /> or <Box padding={ { default: 'medium', medium: 'large' } } />)
  • I introduced the idea of "family" here to capture the groupings we have (e.g. surface, interactive, content). Does the term "family" and its usage here make sense?
    • If so, we likely want to adapt the documentation of the color naming scheme to incorporate this, breaking down "element" into "property" + "family"
    • Part of the expectation here is that in how some components would use Box, they may introduce their own family of tokens, like a Card component using Box and having its own card-specific spacing tokens


### Custom Rendering

Every component supports the `render` prop for complete control over the underlying HTML element:
Copy link
Contributor

Choose a reason for hiding this comment

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

I'm curious - why do we not utilise React.children here? It still allows for complete flexibility about underlying HTML and follows a more "natural" HTML-like syntax?

Copy link
Member Author

Choose a reason for hiding this comment

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

I'm curious - why do we not utilise React.children here? It still allows for complete flexibility about underlying HTML and follows a more "natural" HTML-like syntax?

The behavior described here is when you want to control the rendering of the wrapper element itself. A good example of this would be if you wanted to render a <Button /> to appear visually like a button but have link semantics, you could do something like <Button render={ <a /> } />. This is similar to what we've done historically with as="a" props (also popular in libraries like Radix), and similar to what other libraries like Ariakit supports.

Many (most?) components would still accept children to render as the descendants of the element.

Curious if you have any suggestions on how to clarify the language here.

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 render as a propr would almost always suggest to me "this is for controlling the rendering of the inner html" rather than "this is how you control the rendering of the component in question".

If we have a precedent for using as then why not use that again here? It would seem clearer to me.

Copy link
Contributor

Choose a reason for hiding this comment

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

or element?

Copy link
Member Author

@aduth aduth Nov 6, 2025

Choose a reason for hiding this comment

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

For what it's worth, there's precedent of both: The Composite, Menu, and Tabs components all provide a render prop.

The issue with as is that it's pretty limited in its flexibility, and not as compatible with type-checking out of the box.

Using a <Button /> and <a /> example again, we'd ideally want href to be a prop of the link and not the Button, where a render prop allows us to accept props applied to the link without defining them on the Button types.

<Button render={ <a href="/" /> } />
// vs. <Button render="a" href="/" />

Regarding flexibility, with this example, you could also imagine someone wanting to use a component abstraction to handle the link behaviors, like a Tanstack Link. If the polymorphism only supports string values, we can't do that.

Some of this we might be able to work around or find some middle-ground (e.g. inferring props using TypeScript generics, allowing as to accept values other than strings).

Another consideration is related to the "Maintenance cost" point raised in #71196, specifically around leveraging third-party libraries to reduce our own maintenance burden. I would expect we may want to increasingly build upon established libraries, and aligning this behavior would make that more seamless. We're already using Ariakit quite a bit, which uses render props. Up-and-coming libraries like Base UI adopt a similar approach for composition.

Copy link
Contributor

Choose a reason for hiding this comment

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

Thanks for the clear explanation @aduth. It seems I'm a little behind on this render being an established pattern.

I absolutely agree that we need fully flexibility for this custom rendering. If as only supports strings then it's a no go.

So in summary

  • render allows you to customise the element itself
  • React.children and Composite components pattern allows for full control over inner HTML

Copy link
Member Author

Choose a reason for hiding this comment

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

So in summary

  • render allows you to customise the element itself
  • React.children and Composite components pattern allows for full control over inner HTML

Yeah, precisely.

The compound component approach also pairs nicely because you can potentially mix-and-match both first-party and completely custom component combinations, which is difficult to do with monolithic components.


### Ref Forwarding

All components forward refs to their underlying DOM elements:
Copy link
Contributor

Choose a reason for hiding this comment

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

Will there be scenarios where we might wish to pass a ref to more than one underlying element? The scenario I've hit in the past is when you have a form element which has a wrapper div (or something) and then the input itself. You might want access to either of those.

Copy link
Member Author

Choose a reason for hiding this comment

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

Will there be scenarios where we might wish to pass a ref to more than one underlying element? The scenario I've hit in the past is when you have a form element which has a wrapper div (or something) and then the input itself. You might want access to either of those.

It's not explicitly documented here, but I expect we'll continue to lean heavily on the compound components approach with components in this package, so that in the example you mention, you would apply the ref directly to the rendered subcomponent.

We'll probably want to document a reference to the existing component guidelines and any deviations we'd want to consider.

Copy link
Contributor

Choose a reason for hiding this comment

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

...continue to lean heavily on the compound components approach with components in this package

I really appreciate this approach to writing components. The flexibility it affords is huge and it is this kind of thing that will avoid a million and one hacks and an ever expanding list of props.

Copy link
Member Author

Choose a reason for hiding this comment

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

In 685fd84, I added a CONTRIBUTING.md to this package which describes how we're inheriting from existing component guidelines, while also reserving space to build upon those with package-specific conventions (for example, folder structure iterations).

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.

Adds a new @wordpress/ui package with documented "core design principles" for design system components

Overall I'm very much in favour of this new package. A clear design system has been missing for some time and this feels like the first step to rectifying that.

The benefits this could delivery are potentially huge in terms of consistency, maintainability and avoidance of bugs.

--wpds-spacing-private-50: 40px; /* 10x base spacing */
--wpds-spacing-private-60: 48px; /* 12x base spacing */
--wpds-spacing-private-70: 56px; /* 14x base spacing */
--wpds-spacing-private-80: 64px; /* 16x base spacing */
Copy link
Contributor

Choose a reason for hiding this comment

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

Is it worth making these explicit calc calls, so that a change to the base spacing will propagate across all variables?

Copy link
Member Author

Choose a reason for hiding this comment

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

This file is autogenerated using Terrazzo based on the set of token values, where the actual value is maintained in packages/theme/tokens/spacing.json.

Although your suggestion makes sense and I wondered if we could specify this in the token value itself. Unfortunately from what I found, the DTCG format standard doesn't seem to support this.

If it's any consolation, these values are not intended to be part of a public API or properties that we'd expect anyone to actually use, and as of #72890 they'd not be included in the CSS files at all.

@jameskoster
Copy link
Contributor

For the spacing primitives I think the existing 'grid-unit-*' values are mostly okay, but I'd consider iterating slightly to include increments of 4 up to 24px, then increments of 8 from there. I'd also make 48px the max, because afaik we're not using spacing values any larger than that.

I suppose we could also think about width and height. Should we add these as primitives too? E.g.:

{
  "dimension": {
    "$type": "dimension",
    "primitive": {
      "space": {
        "0":   { "$value": "0px" },
        "10":  { "$value": "4px" },
        "20":  { "$value": "8px" },
        "30":  { "$value": "12px" },
        "40":  { "$value": "16px" },
        "50":  { "$value": "20px" },
        "60":  { "$value": "24px" },
        "70":  { "$value": "32px" },
        "80":  { "$value": "40px" },
        "90":  { "$value": "48px" }
      },
      "measure": {
        "1": { "$value": "240px" },
        "2": { "$value": "280px" },
        "3": { "$value": "320px" },
        "4": { "$value": "360px" },
        "5": { "$value": "480px" },
        "6": { "$value": "640px" },
        "7": { "$value": "800px" },
        "8": { "$value": "960px" }
      },
      "block": {
        "10": { "$value": "24px" },
        "20": { "$value": "32px" },
        "30": { "$value": "40px" },
        "40": { "$value": "64px" }
      }
    }
  }
}

The example above includes two additional primitive ramps for other dimensions: measure and block. These correspond to the inline and block axes, aligning with CSS logical properties (inline-size and block-size) rather than physical ones. We could alternatively name these groups width and height for immediate familiarity, but the chosen terminology better reflects a logical, direction-agnostic system. Measure would be used for preset surface widths, and block for our preset heights for things like buttons, inputs, and the Editor header.


For the semantic surface padding tokens, here are some considerations based on existing UI:

  • Menus use 4px padding
  • Technically I think Card supports 8px padding, but it doesn't work particularly well, and I don't think we use 8px padding for any other surfaces. 16px is much more common.
  • 24px seems like a good base value for cards.
  • 32px is currently used for modals dialogs.
  • 48px is used currently in 'admin' sections of the site editor.

Ultimately I think we may end up needing to iterate on this.

Should we incorporate gaps and measure/width here too? E.g.:

{
  "dimension": {
    "$type": "dimension",
    "semantic": {
      "padding": {
        "surface": {
          "card": {
            "default": {
              "inline": { "$value": "{dimension.primitive.space.60}" },
              "block":  { "$value": "{dimension.primitive.space.60}" }
            }
          },
          "dialog": {
            "default": {
              "inline": { "$value": "{dimension.primitive.space.70}" },
              "block":  { "$value": "{dimension.primitive.space.70}" }
            }
          }
        }
      },

      "gap": {
        "surface": {
          "default": { "$value": "{dimension.primitive.space.50}" },
          "compact": { "$value": "{dimension.primitive.space.40}" }
        }
      },

      "width": {
        "surface": {
          "modal": {
            "sm":  { "$value": "{dimension.primitive.measure.5}" },  // 480px
            "md":  { "$value": "{dimension.primitive.measure.6}" },  // 640px
            "lg":  { "$value": "{dimension.primitive.measure.7}" },  // 800px
          },
          "sidebar": {
            "narrow":  { "$value": "{dimension.primitive.measure.2}" }, // 280px
            "default": { "$value": "{dimension.primitive.measure.3}" }, // 320px
            "wide":    { "$value": "{dimension.primitive.measure.4}" }  // 360px
          },
          "card": {
            "default": { "$value": "{dimension.primitive.measure.6}" }, // 640px
            "wide":    { "$value": "{dimension.primitive.measure.7}" }  // 800px
          }
        }
      }
    }
  }
}


Maybe “family” is more about "target": surface, interactive, and (optionally) content.

  • Surface → containers (card, dialog, modal, sidebar)
  • Interactive → controls (buttons, inputs, toggles) — if/when you add them
  • Content → content constraints like paragraph max width

If we introduce content constraints, we could add a small textMeasure primitive ramp in ch to keep line length readable (e.g., 55–75ch). That edges into typography, so we can probably defer; but the structure would look like:

{
  "dimension": {
    "$type": "dimension",
    "primitive": {
      "textMeasure": {
        "40": { "$value": "40ch" },
        "55": { "$value": "55ch" },
        "60": { "$value": "60ch" },
        "65": { "$value": "65ch" },
        "75": { "$value": "75ch" }
      }
    }
  }
}

and a semantic like width.content.paragraph.default = {dimension.primitive.textMeasure.65}.

@aduth
Copy link
Member Author

aduth commented Nov 6, 2025

@jameskoster I appreciate the deep review and feedback for the tokens!

I'd consider iterating slightly to include increments of 4 up to 24px, then increments of 8 from there.

This makes sense to me, particularly if we can keep this an internal implementation detail withheld from the public API 👍

I suppose we could also think about width and height. Should we add these as primitives too?

I think probably yes, and certainly something we want to be aware and ensure compatibility with, though also balancing with trying to keep this pull request as narrow in scope as possible to get the package established and an MVP demonstration of the token usage. I fully expect we'll have several more iterations here (radius, typography, etc.) and we'll want to track those follow-on tasks.

Do you think width and height could be saved for a follow-on?

To the point of compatibility, I think it could make sense to rename spacing to dimension.

For the full example of what you shared with dimension, a few thoughts:

  • I was previously viewing card and dialog as the "family" alternative surface (a peer), although based on your explanation I could see it being a subtype. With how this is currently implemented and how tokens are compiled as dash-delimited, this could be passed as family="surface-card" for example.
  • With Design System: Support for admin redesign #71196 requirements outlining future goals around density, that's another variable to throw into the mix of all this in terms of how we manage tokens 😅 I would sorta imagine we'd have a different set of semantic tokens for density values that card and others would reference, and then we can update the value of that semantic token at runtime.
  • I'm not entirely sure I follow the need to specify distinct values for inline and block paddings, although I suppose I can see how that might be useful for some cases (e.g. input fields usually having more horizontal padding than vertical padding). Not as clear to me if that exists at the system tokens level or more component-specific.

Here's some action items I'm seeing:

  • Change private spacing scale "to include increments of 4 up to 24px, then increments of 8 from there" up to a max of 48px
    • When: In this pull request
  • Change token structure to define padding as a grouping, with surface as a sub-type
    • When: In this pull request
  • Rename family prop to target
    • When: In this pull request
  • Rename spacing to dimensions.
    • When: Preferably a quick follow-on pull request. This is a "simple" change, but it'll cause a lot of changes that make this harder to review
  • Add width, height, gap, and other customization options of Component: Box #72784
    • When: As follow-on pull requests, each associated with a tracking issue

@aduth
Copy link
Member Author

aduth commented Nov 6, 2025

  • Change private spacing scale "to include increments of 4 up to 24px, then increments of 8 from there" up to a max of 48px

    • When: In this pull request

Implemented as part of e3969a6.

  • Change token structure to define padding as a grouping, with surface as a sub-type

    • When: In this pull request

Implemented as part of e3969a6.

  • Rename family prop to target

    • When: In this pull request

Updated in 7836d9f.

  • Rename spacing to dimensions.

    • When: Preferably a quick follow-on pull request. This is a "simple" change, but it'll cause a lot of changes that make this harder to review

I ended up implementing this here as part of e3969a6, since we're making so many changes to tokens anyways that this diff is unavoidable.

  • Add width, height, gap, and other customization options of Component: Box #72784

    • When: As follow-on pull requests, each associated with a tracking issue

I'm thinking we can keep #72784 open as the tracking issue and include anything there that's missing, likely as a task checklist.

With these changes, how do we feel about this as an initial iteration?

@github-actions
Copy link

github-actions bot commented Nov 6, 2025

Flaky tests detected in 7a71b80.
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/19268423920
📝 Reported issues:

@jameskoster
Copy link
Contributor

Looking great, excited about this! :)

Copy link
Member

@tyxla tyxla 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 work, folks 👍 Let's merge and keep iterating.

@aduth aduth force-pushed the add/box-component branch from b09519f to 7a71b80 Compare November 11, 2025 14:14
@aduth aduth mentioned this pull request Nov 11, 2025
7 tasks
@aduth aduth merged commit 4c432e1 into trunk Nov 11, 2025
43 of 44 checks passed
@aduth aduth deleted the add/box-component branch November 11, 2025 15:41
@aduth
Copy link
Member Author

aduth commented Nov 11, 2025

I updated #72784 to remain open and include a task list of features excluded from this initial pull request.

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

Labels

[Feature] Component System WordPress component system [Package] UI /packages/ui [Type] Experimental Experimental feature or API.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

8 participants