Interactivity API and extensibility #62119
Replies: 5 comments 13 replies
-
This is an important discussion to have, thanks for starting it. To answer this type of question, let's build. Let's figure out the need to satisfy and explore the proposed solutions. What is difficult or impossible to build right now? I'd love to hear ideas from the community about that. It will help to understand what needs should be satisfied with extensibility. Let's build that. We can prototype with the proposed approaches so we can analyze their tradeoffs. That will inform this discussion and decision. |
Beta Was this translation helpful? Give feedback.
-
I've been thinking about this, and I believe the name of this directive should be very explicit, already conveying the disadvantages of using it. Something like Similar to the upcoming |
Beta Was this translation helpful? Give feedback.
-
Thanks for opening this discussion :) In addition to the topics you've outlined, I would like to highlight another area of extensibility. As it stands today, the Interactivity API is very powerful when building custom blocks. You have full control over the markup and, therefore, can easily add your own store/directives and just build whatever you want. However, it is very difficult to use the Interactivity API today to extend the behavior of core blocks/patterns with custom interactivity. There are a few things that contribute to this:
Here are some brief examples for each of these to hopefully better explain my point:
I hope these examples help showcase some of the challenges I'm currently running into :) |
Beta Was this translation helpful? Give feedback.
-
I have an interesting case. It is impossible to render a true tree structure using the Interactivity API as it is today. What's lacking is some concept of recursion. I could solve that with the right extensibility points. Consider my tree: interface Node {
nodeType: string,
childNodes: Node[]
} I'd like to create some HTML like this: <span data-wp-text="node.nodeType"></span>
<ul>
<template data-wp-each="node.childNodes">
<li>
<!-- here is where we should recurse -->
<span data-wp-text="context.item.nodeType"></span>
<ul>
<template data-wp-each--child="context.item.childNodes">
<!-- … -->
</template>
</ul>
</li>
</template>
</ul> This is rather trivial to implement with recursion, but it's impossible (or close enough) that the Interactivity API today is completely unsuited to this. I'd like to define a custom directive like this: <template data-wp-node="state.tree"></template> Where that directive renders this (see how it self-references to recursively handle the tree): <span data-wp-text="context.node.nodeType"></span>
<ul>
<template data-wp-each="context.node.childNodes">
<li>
<!-- vvv here we self-reference to recurse vvv -->
<template data-wp-node="context.item"></template>
</li>
</template>
</ul> |
Beta Was this translation helpful? Give feedback.
-
In WooCommerce, we've considered using the interactivity API in areas of the admin such as the product editor. This is purely conceptual and full disclosure- not something that we've even explored fully, but I wanted to offer another perspective in favor of components. The interactivity API in this case allows us to sprinkle in interactivity within the existing page structure without replacing the entire application immediately with a React app. This means that we can also continue to use existing hooks for extensibility and potentially add basic interactivity to content rendered from those hooks using the HTML processor API. Additionally, the interactivity API requires less mental overhead and build processes for 3PDs who do not yet have those in place. <div class="form-field">
<label>Regular price</label>
<input type="text" data-wp-on--change="actions.handleInputChange" data-wp-bind--value="state.product.regular_price" />
</div>
<?php do_action( 'woocommerce_product_options_pricing' ); ?> However, since we also want consistency within the WordPress admin, the product editor relies heavily on the But having some level of consistency in the "components" (even if those are not React) is important in the case of the product editor to improve the UI/UX. I can see an argument where that could be mostly handled in PHP and is less the responsibility of the Interactivity API, but having these readily available in the Interactivity API is both convenient and offers a level of progressive enhancement for applications transitioning between experiences. |
Beta Was this translation helpful? Give feedback.
-
"Extensibility" is one of the touted benefits of using the Interactivity API.
However, developers can only extend the API in very limited ways. I want to discuss 2 possible ways of extending the Interactivity API here:
Custom components
Previously, as discussed in #60418, it was possible to pass a Preact component to a
data-wp-text
directive, which would render that component on the front end. However, this functionality was later removed in #57879. This was a sound decision at the time and aligns with the "cautious" philosophy of only exposing the minimum necessary primitives in any new API and only adding new ones once there is sufficient need from the users. This minimizes the risk of shipping the wrong abstraction and lessens the backward compatibility burden if the new API is indeed inadequate in some way.Without concern for "how" the components API would look (
data-wp-component
or something else?) I would like to discuss the merits of exposing it (or not exposing it).👍 "For" components
Users are inevitably going to want to use Preact components in their code. It might be because they have a legitimate use case for functionality that does not have a meaningful representation on the server. It might be because they are more comfortable writing components. They will inevitably find workarounds (like this one), so it would be better to expose an official way to ship components because:
👎 "Against" components
Using Preact components together with the Interactivity API is often an antipattern. The vast majority of use cases for the Interactivity API do not require using Preact components and can likely be accomplished with just the Interactivity API. Thus, there is a significant risk that we are encouraging bad practices by making components easy to use.
An API should guide users towards the pit of success, providing guardrails that prevent abuse and encourage best coding practices.
Custom directives
To be brief, most of the discussion above also relates to custom directives. The difference is that creating custom directives gives users even more freedom than just allowing components (you can create a custom directive that renders components, but not the other way around).
In principle, we could expose a
registerDirective()
function that is different from thedirective()
function in the framework. This hypotheticalregisterDirective()
function might be more limited in functionality and scope and, e.g., disallow returning components from it or perform additional validation checks.Personal opinion: We should allow for the creation of custom components. I'm not convinced about custom directives yet, as they are even more powerful and require more thought about how to approach them. However, as this is a discussion of the philosophy of how we write software, I'd like to hear people's thoughts on this, especially if they disagree 🙂 .
Beta Was this translation helpful? Give feedback.
All reactions