Skip to content

Editor: Speed up the hierarchical term selector for large taxonomies - #81376

Open
Mamaduka wants to merge 2 commits into
trunkfrom
try/editor-build-terms-tree-perf
Open

Editor: Speed up the hierarchical term selector for large taxonomies#81376
Mamaduka wants to merge 2 commits into
trunkfrom
try/editor-build-terms-tree-perf

Conversation

@Mamaduka

@Mamaduka Mamaduka commented Aug 10, 2026

Copy link
Copy Markdown
Member

What

PR tries to speed up the Categories panel on sites with thousands of terms. With 5,000 categories, ticking a checkbox blocked the main thread for about 157ms.

How

Each row now uses content-visibility, so the browser skips layout for rows that are off-screen. The list is already a fixed-height scroll container, so this applies cleanly. Rows have padding on the top, left, and bottom, so paint containment does not clip the checkbox's focus ring.

Alongside that, in the same component:

  • buildTermsTree builds the tree in a single pass instead of cloning it twice
  • sortBySelected partitions the list instead of sorting with a comparator that rewalks each subtree on every comparison
  • each checkbox is memoized on primitive props, so ticking one term does not rerender the rest

Testing Instructions

  1. Create test data - wp term generate category --count=5000 --max_depth=3.
  2. Open a post.
  3. Try interacting with the Categories panel.
  4. Selection and filter should feel faster.

Testing Instructions for Keyboard

Same.

Screenshots or screencast

Before

CleanShot.2026-08-10.at.12.40.42.mp4

After

CleanShot.2026-08-10.at.12.38.37.mp4

Use of AI Tools

Assisted by Claude.

@Mamaduka Mamaduka self-assigned this Aug 10, 2026
@Mamaduka Mamaduka added [Type] Performance Related to performance efforts [Package] Editor /packages/editor labels Aug 10, 2026
@github-actions

github-actions Bot commented Aug 10, 2026

Copy link
Copy Markdown

Size Change: +335 B (0%)

Total Size: 7.65 MB

📦 View Changed
Filename Size Change
build/scripts/editor/index.min.js 509 kB +184 B (+0.04%)
build/styles/editor/style-rtl.css 31.5 kB +39 B (+0.12%)
build/styles/editor/style-rtl.min.css 26.8 kB +40 B (+0.15%)
build/styles/editor/style.css 31.6 kB +36 B (+0.11%)
build/styles/editor/style.min.css 26.8 kB +36 B (+0.13%)

compressed-size-action

@tyxla tyxla left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Thanks for working on this @Mamaduka.

While this is a perf change, it also changes how the list looks and how it behaves. That mix makes regressions easy to miss.

Should we perhaps split it - tree building and memoization in one PR, CSS and search changes in another?

);
} );

function TermRow( { term, selectedTerms, onToggle } ) {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I see we're memoizing TermCheckbox here but aren't we still recreating all TermRow elements and their child elements on every render? Is that the intent and why?

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.

The TermRow memoization had no real effect on performance. The memoed TermCheckbox ensures that only one item re-renders when selection changes.

Manual memoization is easy to break, so I decided to split it into smaller parts.

Comment on lines +396 to +397
debouncedFilterTerms.cancel();
setFilteredTermsTree( null );

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Are we intentionally missing the a11y announcements here?

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.

Good question. This was logical to me, no filter value, no announcement. I'll check which patterns we're using elsewhere.

// Only a few rows show at a time. Without this, every forced layout in the
// editor costs in proportion to the number of terms.
content-visibility: auto;
contain-intrinsic-size: auto $grid-unit-30 + $focus-ring-space * 2;

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

The contain-intrinsic-size: auto 36px is set on every .hierarchical-terms-choice, but some of those rows contain a whole subtree inside .hierarchical-terms-subchoices. So a skipped top-level row with 20 children is reported as 36px instead of ~500px.

The 36px value also may also be off for leaf rows on desktop. It comes from $grid-unit-30 (24px), which is the --checkbox-input-size for small viewports, but above the break-small breakpoint the checkbox is 16px, so a actual leaf row is about 28px.

Should we apply content-visibility only to rows without children?

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.

I'll have a look.

@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: Mamaduka <mamaduka@git.wordpress.org>
Co-authored-by: tyxla <tyxla@git.wordpress.org>

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

@Mamaduka

Copy link
Copy Markdown
Member Author

Should we perhaps split it - tree building and memoization in one PR, CSS and search changes in another?

Makes sense. I got a bit carried away, since the selection interaction improvements required overlapping changes.

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

Labels

[Package] Editor /packages/editor [Type] Performance Related to performance efforts

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants