Skip to content

Conversation

@sethrubenstein
Copy link
Contributor

@sethrubenstein sethrubenstein commented Feb 19, 2025

What?

This is Pew Research Center's approach to Tabs in the block editor and would fulfill much of the needs requested in #34079.

Before getting started with testing, some additional work is needed that I'll be following up with in a few weeks but I wanted to get this PR started.

Additional tasks:

  • Finish the default styling.
  • Update the tab label block binding to the latest binding API (I started this months ago).
  • Implement minimal state management for the last active tab by creating a custom WordPress/data store for core/tabs. This will allow core/tab to recognize which block was last selected within its core/tabs parent when the user no longer has either in focus. Currently, when you exit your selection, we only display the first tab.
  • Address accessibility handlers in the editing interface and resolve styling inconsistencies in the editor.
  • Strengthen any accessibility concerns on the frontend.

This builds upon work started by @creativecoder in #63689 and expands on making this concept even more extensible for developers.

The major changes from this original concept are the following:

  • An overhaul of tab editing has been implemented. A slotfill (thanks @fabiankaegy for the idea) is now used to manage the tabs list and individual tab items. This enhances the user experience in two key ways:
      1. Selecting a tab now highlights the entire block, making it easier to start editing.
      1. Perhaps more importantly, we're not monitoring changes to innerblocks content to manage the tabs list, which caused significant performance issues when there were more than 10 tabs. Additionally, with the new slotfill selection method, we no longer render the innerblocks if the tab is not selected. This also improves the overall editing performance of the block.
  • Some attribute changes were made, notably the removal of tabIndex. We now add the tab index to each tab during render time. This change allows for greater programmatic usage of tabs and simplifies the process of copying and pasting new tab panes in the editor.
  • Structural changes to the core/tab block will allow it to degrade more gracefully by enabling the core/tabs block to control all Interactivity API adoption. If a core/tab block is displayed outside of core/tabs, it should simply show the tab content without any issues or modifications.
  • The addition of various tab state colors as attributes and color controls enhances the user interface. Now, there are color controls and simple styles to support tab hover, tab active, tab background, text, and more.
  • The addition of "deep linking" support allows for URL activation of a specific tab for content sharing. For example, adding the tab-hash found in the tab to the URL as ...?activeTabIndex=TXkgc2Vjb25kIHRhYl9fMQ== will open the second tab, as demonstrated in the screencast below.
  • Addition of core/paragraph and core/heading block binding variations to display the block label within each tab.

Why?

As the block editor and the concept of "full site editing" matures, I'm a strong believer that some basic ui concepts and paradigms should be available in the block library. Tabs is one such basic ui concept, dialog/modals are another.

How?

Testing Instructions

  1. Open a post
  2. Add a tabs block
  3. To start, two sample tabs are generated; click the plus icon in the tabs list to create a new tab
  4. Add content
  5. Preview and ensure tabs are selectable.

Testing Instructions for Keyboard

TK, working on keyboard handlers next.

Screenshots or screencast

In WP env:

CleanShot.2025-02-19.at.18.45.08.mp4

This is a screencast of the tabs block in action on the upcoming RLS site. Here you'll see Tabs that are generated dynamically on the server. The tab block is placed and styled in the editor, but it's individual tabs and contents are generated by logic on the server. Making Tabs as extensible as possible was our main goal:

CleanShot.2025-02-19.at.18.51.55.mp4

…finements in the editor interface and overall cleanup.
…ion/element-grouping. Will come back in later this week to add key handlers
…tore for remembering the last active tab when i get back from vacation
@github-actions
Copy link

github-actions bot commented Feb 19, 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.

Unlinked Accounts

The following contributors have not linked their GitHub and WordPress.org accounts: @gutenbergplugin.

Contributors, please read how to link your accounts to ensure your work is properly credited in WordPress releases.

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

Unlinked contributors: gutenbergplugin.

Co-authored-by: sethrubenstein <[email protected]>
Co-authored-by: Mamaduka <[email protected]>
Co-authored-by: Infinite-Null <[email protected]>
Co-authored-by: felixarntz <[email protected]>
Co-authored-by: shail-mehta <[email protected]>
Co-authored-by: kellymears <[email protected]>
Co-authored-by: huubl <[email protected]>
Co-authored-by: juanmaguitar <[email protected]>
Co-authored-by: im3dabasia <[email protected]>
Co-authored-by: Rishit30G <[email protected]>
Co-authored-by: carolinan <[email protected]>
Co-authored-by: t-hamano <[email protected]>
Co-authored-by: shimotmk <[email protected]>
Co-authored-by: afercia <[email protected]>
Co-authored-by: ockham <[email protected]>
Co-authored-by: davilera <[email protected]>
Co-authored-by: benazeer-ben <[email protected]>
Co-authored-by: SainathPoojary <[email protected]>
Co-authored-by: yogeshbhutkar <[email protected]>
Co-authored-by: himanshupathak95 <[email protected]>
Co-authored-by: fabiankaegy <[email protected]>
Co-authored-by: stokesman <[email protected]>
Co-authored-by: kasparsd <[email protected]>
Co-authored-by: bschneidewind <[email protected]>
Co-authored-by: HILAYTRIVEDI <[email protected]>
Co-authored-by: cbravobernal <[email protected]>
Co-authored-by: sabbir1991 <[email protected]>
Co-authored-by: Anuj-Rathore24 <[email protected]>
Co-authored-by: luisherranz <[email protected]>
Co-authored-by: hanneslsm <[email protected]>

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

@sethrubenstein sethrubenstein mentioned this pull request Feb 19, 2025
*/
get isActiveTab() {
const context = getContext();
const { attributes } = getElement();
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Note to self: Now that I think about it, there’s really no reason to not give each tab iAPI context with its index value instead of relying on getElement.

Copy link
Member

@luisherranz luisherranz Feb 20, 2025

Choose a reason for hiding this comment

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

Either way is fine. The only advantage of using context is that the child elements of the element in question can also access the index/id, whereas with the element's attribute, you need to know if you are in the element or in one of the children.

// using context in both the element and their children
get isActiveTab() {
  const { activeTabIndex, tabIndex } = getContext();
  return activeTabIndex === tabIndex;
}

// using an attribute, scoped to the element
get isActiveTab() {
  const { activeTabIndex } = getContext();
  const { attributes } = getElement();
  return activeTabIndex === attributes['data-tab-index'];
}

// using an attribute, scoped to a child of the element
get isActiveTab() {
  const { activeTabIndex } = getContext();
  const { ref } = getElement();
  return activeTabIndex === ref?.closest('[data-tab-index]').dataset.tabIndex;
}

// or joining both
get isActiveTab() {
  const { activeTabIndex } = getContext();
  const { ref, attributes } = getElement();
  const tabIndex = attributes['data-tab-index'] || ref?.closest('[data-tab-index]').dataset.tabIndex
  return activeTabIndex === tabIndex;
}

Remember also that ref is null during the first hydration (same as in React/Preact), so it usually causes problems for this type of case.

@carolinan carolinan added the New Block Suggestion for a new block label Feb 20, 2025
Mamaduka and others added 2 commits February 20, 2025 19:36
Co-authored-by: Mamaduka <[email protected]>
Co-authored-by: tyxla <[email protected]>
Co-authored-by: TimothyBJacobs <[email protected]>
* Enhance 404 message styling with Notice component

* Improve 404 error message

* Remove color style from `.edit-site-layout__area__404`

* Update 404 notice implementation with reusable component

* Fixed DOM nesting validation error by replacing p with div

Co-authored-by: Infinite-Null <[email protected]>
Co-authored-by: t-hamano <[email protected]>
Co-authored-by: joedolson <[email protected]>
Co-authored-by: carolinan <[email protected]>
@t-hamano t-hamano added the [Type] Enhancement A suggestion for improvement. label Feb 20, 2025
@sethrubenstein
Copy link
Contributor Author

Added controls for setting the default starting tab index. The attribute for this resides in core/tabs, but I'm surfacing the control in each tab so it can set it's own index as the attribute value in the parent.

CleanShot.2025-02-20.at.09.17.47.mp4

* Replace them with your own styles or remove the file completely.
*/

.wp-block-prc-block-tabs.wp-block {

Choose a reason for hiding this comment

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

the prc slug should probably be removed.

@hanneslsm
Copy link

hanneslsm commented Feb 20, 2025

Thank you for the amazing work! Looking forward for this new block!

Some feedback:

  1. In the details block we have Type / to add a hidden block as the inserter text. It could make sense to change the text also in the tabs to something like Type / to add a block in the tab.
  2. I'm not a big fan of the block styles and would vote for only adding a very limited amount and remove as many styling as possible. In my opinion this is theme territory and I know that I'd unregister probably all of them first. Especially pills, underlined pills and tabbed outline have very opinionated styles and it will lead to many frustrations when users won't be able to change the styles like border radius. tabbed and underline should be enough for a core block. I'd also rename tabbed to filled to be more descriptive and consistent with the button block (note .is-style-filled is already taken by the button). We could also think about adding a outline style, to be even more consistent with the button block
    3) If no title is set and content added, the block shouldn't be rendered in the front end (ignore, it could actually become very handy having a tab without a label, especially when it's set as default.)

felixarntz and others added 9 commits February 20, 2025 12:44
…ject whenever it is not used (WordPress#68097)

* Implement withSyncEvent action wrapper utility.

* Prepare Interactivity API infrastructure for awareness of action prior to evaluating it.

* Proxy event object when withSyncEvent() is not used.

* Ensure generator functions using withSyncEvent() are wrapped correctly to still be recognized as generator functions.

* Update Interactivity API documentation to reference withSyncEvent().

* Use withSyncEvent() in all built-in actions that require it.

* Minor fixes for withSyncEvent docs.

* Clarify documentation.

Co-authored-by: Weston Ruter <[email protected]>

* Enhance withSyncEvent implementation and ensure the sync flag is maintained when proxying functions via withScope.

* Add doc block for wrapEventAsync().

* Use more specific types for event proxy handler.

* Amend callback in withSyncEvent instead of wrapping it.

* Revert "Prepare Interactivity API infrastructure for awareness of action prior to evaluating it."

This reverts commit dba93ec.

* Update evaluate() to no longer invoke functions (except where needed for BC) and move responsibility to the caller.

* Export withSyncEvent

* Fix evaluate to return scoped function and always reset scope.

* Update custom directives for e2e tests to account for evaluate behavior change.

* Update release version number in documentation.

---------

Co-authored-by: Weston Ruter <[email protected]>
Co-authored-by: Luis Herranz <[email protected]>
* Post Comments Count: Add Border Support

Co-authored-by: shail-mehta <[email protected]>
Co-authored-by: carolinan <[email protected]>
Code samples correctly identify `PluginSidebar` as requiring the `wp-editor` dependency, but the how-to text still references `wp-edit-post`.

Co-authored-by: kellymears <[email protected]>
Co-authored-by: t-hamano <[email protected]>
…ss#68521)

* Allow :focus-visible pseudo-selector to be set in theme.json

Co-authored-by: huubl <[email protected]>
Co-authored-by: carolinan <[email protected]>
Co-authored-by: audrasjb <[email protected]>
Co-authored-by: joedolson <[email protected]>
Co-authored-by: sabernhardt <[email protected]>
Co-authored-by: afercia <[email protected]>
Co-authored-by: Bovelett <[email protected]>
* Update javascript-in-the-block-editor.md - fix link

* Fix Links in remaining two files

* Revert Changes in javascript-in-the-block-editor.md file

* Added Suggested Changes

Co-authored-by: juanmaguitar <[email protected]>
Co-authored-by: shail-mehta <[email protected]>
Co-authored-by: t-hamano <[email protected]>

---------

Co-authored-by: shail-mehta <[email protected]>
)

* fix: Alignment issue of first header in dataviews

* fix: Remove span parent of title field

* fix: Remove inline css and remove extra css code

Co-authored-by: im3dabasia <[email protected]>
Co-authored-by: t-hamano <[email protected]>
Co-authored-by: hbhalodia <[email protected]>
Co-authored-by: ecgan <[email protected]>
Co-authored-by: Rishit30G <[email protected]>
Co-authored-by: Mamaduka <[email protected]>
Co-authored-by: hanneslsm <[email protected]>
Co-authored-by: yogeshbhutkar <[email protected]>
Co-authored-by: Infinite-Null <[email protected]>
Co-authored-by: carolinan <[email protected]>
)

* Post formats: Make title and description human readable

Co-authored-by: carolinan <[email protected]>
Co-authored-by: t-hamano <[email protected]>
Co-authored-by: Mamaduka <[email protected]>
…tor for RTL languages (WordPress#68561)

* fix: add ltr for email and url in the textcontrol component

* doc: Add changelog

* doc: Add changelog in unreleased section

* doc: Update changelog

Co-authored-by: im3dabasia <[email protected]>
Co-authored-by: t-hamano <[email protected]>
@sethrubenstein
Copy link
Contributor Author

Whoopsies, my rebase messed up here. Closing this in favor of a new, and completed PR here #69789

@sethrubenstein sethrubenstein deleted the new-block/tabs branch September 8, 2025 21:14
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

New Block Suggestion for a new block [Type] Enhancement A suggestion for improvement.

Projects

None yet

Development

Successfully merging this pull request may close these issues.