Skip to content

Components: Update polymorphism types to allow all attributes when specifying as#80705

Open
aduth wants to merge 4 commits into
trunkfrom
update/components-polymorphism-flat-attributes
Open

Components: Update polymorphism types to allow all attributes when specifying as#80705
aduth wants to merge 4 commits into
trunkfrom
update/components-polymorphism-flat-attributes

Conversation

@aduth

@aduth aduth commented Jul 24, 2026

Copy link
Copy Markdown
Member

What?

Updates the polymorphism types used in @wordpress/components to expose all possible HTML attributes when as is specified, rather than narrowing the types based on the tagName provided to as.

The performance impact on TypeScript builds is significant, reducing memory usage by -47% (7.4GB to 4.0GB), TypeScript build time by -49% (13.7s to 7.0s), and internal instantiations by -54% (42.5M to 19.5M).

Why?

How?

As described in #80655 , these polymorphism types are a major contributor to overall TypeScript build times and memory consumption. While #80655 tried to fully maintain the original intent of the polymorphism types, the changes here propose a more drastic change: If as is provided, all valid HTML attributes are accessible on that component. This means someone could do something like <VisuallyHidden as="div" htmlFor="id" /> and TypeScript would consider it valid, which was not the case before now, as htmlFor is not a valid attribute for div elements.

This is meant to be a reasonable compromise given the circumstances, and how new development in @wordpress/ui leans on render props instead of as polymorphism.

This isn't all bad though, since:

  • Those additional HTML attributes only become known if as is provided, and otherwise the component's own props are the only ones available.
  • The attribute types are still accurately typed, so TypeScript validates that htmlFor is a string, for example.

Testing Instructions

Verify type-checking passes:

npm run build

For bonus points, try some of the scenarios described under "How", like how you can't assign htmlFor unless specifying as, or that htmlFor can be used with as="div", or how htmlFor can't be assigned to a type other than string.

Also check performance for yourself using snippets from #80364 "Testing Instructions":

If you want to validate performance yourself, you can compare the following set of commands on this branch and trunk:

rm -f packages/components/tsconfig.tsbuildinfo
/usr/bin/time -l npx tsc -p packages/components/tsconfig.json --extendedDiagnostics 2>&1 \
  | grep -E '^(Symbols|Instantiations|Memory used|Memory allocs):|maximum resident'

Or full project timings and memory usage:

npx tsc --build --clean >/dev/null 2>&1
rm -rf packages/*/build-types
/usr/bin/time -l npx tsc --build 2>&1 | grep -E 'maximum resident|real'

Use of AI Tools

Used Cursor IDE + Auto (likely Composer) model to research and implement, with manual iterations, particularly on the code comments.

@aduth aduth added the [Type] Build Tooling Issues or PRs related to build tooling label Jul 24, 2026
@aduth
aduth requested review from a team and ajitbohra as code owners July 24, 2026 20:02
@github-actions github-actions Bot added the [Package] Components /packages/components label Jul 24, 2026
@aduth
aduth requested a review from manzoorwanijk July 24, 2026 20:03
@aduth
aduth requested a review from Mamaduka July 24, 2026 20:04
@github-actions

github-actions Bot commented Jul 24, 2026

Copy link
Copy Markdown

Size Change: -7 B (0%)

Total Size: 7.75 MB

📦 View Changed
Filename Size Change
build/scripts/preferences/index.min.js 3.3 kB -7 B (-0.21%)

compressed-size-action

Comment on lines +13 to +16
/**
* The content to render inside the wrapper.
*/
children?: ReactNode;

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

From what I understand, this should have always been here, and the previous polymorphism types incorrectly typed children for non-polymorphic components. Generally it should be expected that components define their own children types, which we're more consistent about in @wordpress/ui (e.g. ComponentProps explicitly omits children)

@github-actions

Copy link
Copy Markdown

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>

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

@aduth

aduth commented Jul 24, 2026

Copy link
Copy Markdown
Member Author

Oof, type-checking failures in CI. Guessing some local cache might have misled me locally. I'll throw this back to draft temporarily and revisit it on Monday, unless someone wants to go ahead and carry the torch on this one.

Edit: Nevermind, decided to tackle it now.

@aduth
aduth marked this pull request as draft July 24, 2026 20:08
@github-actions github-actions Bot added the [Package] Preferences /packages/preferences label Jul 24, 2026
path={ `/${ tab.name }` }
// @ts-expect-error: Navigator.Button is currently typed in a way that prevents Item from being passed in
as={ Item }
isAction

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

This is safe:

- Removed `isAction` prop from `Item`. The component will now rely on `onClick` to render as a `button` ([35152](https://github.com/WordPress/gutenberg/pull/35152)).

Navigator.Button provides onClick:

@aduth
aduth marked this pull request as ready for review July 24, 2026 20:32
@aduth
aduth requested a review from talldan as a code owner July 24, 2026 20:32
@github-actions

Copy link
Copy Markdown

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

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

Labels

[Package] Components /packages/components [Package] Preferences /packages/preferences [Type] Build Tooling Issues or PRs related to build tooling

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant