Open manzoorwanijk opened 11 months ago
@ciampo @mirka this issue was part of the Extensibility Issues Triage today and it wasn't clear if this was still on your radar. It is a developer experience-related issue.
... removed it from the IGE board as it's not a blocker for extensibility.
Hey @bph , thank you for the ping!
It is indeed true that many components only work in controlled mode. They were built this way to follow the needs of the editor, where all values of those controls are tied to the editor and block settings.
Ideally, we'd like consumers of the package to be able to use all components in controlled or uncontrolled mode. Unfortunately, it's not always an easy task, since some of the changes that are needed would introduce backward compatibility issues.
Since @mirka and I started to work on the components package, we recognised this gap and tried to improve it where possible — for example, we recently enhanced controlled/uncontrolled support for ToggleGroupControl
, and we added controlled mode to TabPanel
(by replacing it with a new component, Tabs
).
Given all of the above, this doesn't represent a priority at the moment, although we're always open to find ways to improve the situation a step at the time.
Even the new components like FormToggle
don't work in uncontrolled mode 🤦
new components like
FormToggle
AFAIK FormToggle
was added to the package 6 years ago, and prior to that was already part of the Gutenberg repository — so I wouldn't call it "new" necessarily.
As mentioned above, we can't do much about existing components, because it would often require a non-trivial amount of changes (usually breaking) and it would introduce API inconsistencies too.
The good news is that we are aware of this need, and we're making sure that new components (and new versions of existing components) support both controlled and uncontrolled mode.
Unfortunately, it's not always an easy task, since some of the changes that are needed would introduce backward compatibility issues.
As mentioned above, we can't do much about existing components, because it would often require a non-trivial amount of changes (usually breaking) and it would introduce API inconsistencies too.
I don't agree with that at all.
I'm willing to work on those "non-trivial amount of changes" if the team is up for it.
The point is, instead of creating new components for "the" basic use case, why not fix the existing ones?
The breaking changes we're worrying about is around the fact that some components support an implicit controlled/uncontrolled switch through a single value
prop (#47473).
If we adopt this pattern on components that don't currently have it, it would introduce behavior changes in controlled usage when the consumer passes an undefined
value (to explicity signify an "empty" value, rather than to signify uncontrolled usage).
But I'm starting to feel strongly that not supporting uncontrolled mode is inacceptable, so I think we should consider using the defaultValue
pattern if necessary. We'll have to investigate, but it is possible that this can be added onto existing components in a non-breaking and consistent way. Even on components that already have the implicit mode switching on value
.
We will first need to audit the current form components to understand the feasibility and impact. I believe we would need to know:
useControlledValue
, useControlledState
, or custom implementation)Then, we can maybe test out adding a defaultValue
prop on a component that already has the mode switching, ideally with already good test coverage, and see if there are any blockers.
@WordPress/gutenberg-components Any thoughts about this plan of action?
@mirka your plan makes sense to me. I'd love to have a better idea what we're fighting with here, and the audit you proposed should help with that, and answer questions like:
And I agree with this sentiment:
But I'm starting to feel strongly that not supporting uncontrolled mode is inacceptable
mostly because the @wordpress/components
package is turning into a general-purpose admin library to cover all the modern admin design use cases, and we need our components to be more flexible. With that in mind, supporting both controlled and uncontrolled versions sounds like an essential use case.
Hey @manzoorwanijk, as Lena also explained, some older components were written only to support controlled mode, which means that they don't offer a way to easily differentiate "empty value but controlled" from "uncontrolled value" (see this issue that Lena also linked above).
As an example, you can take a look at the utility function that I wrote to "patch" ToggleGroupControl
's behavior in a way that preserved backwards compatibility:
@tyxla and @mirka , I agree that supporting controlled/uncontrolled mode for a component should be a commodity in 2024, and is quite essential for a component library that wants to become more general purpose.
We should definitely gather some extra info, but my gut feeling tells me that we may need to introduce some breaking changes if we want to support the canonical value
/ defaultValue
/ onChange
pattern, in particular around how passing an undefined
value affects components.
Thank you for the explanation. Yes, I think breaking change might be a step in the right direction.
My hope is that it turns out we can do it without breaking changes though. Leave the value
behavior as is on all components, and using the new defaultValue
prop would be an opt in to standard uncontrolled behavior that ignores value
.
@manzoorwanijk If you're willing to do some initial investigation, it would be great if we could have a list of control components with the following information:
- Does it support uncontrolled?
- Does it have roughly equivalent unit tests for both controlled/uncontrolled? (If not, uncontrolled support may not be "complete")
- How does it support uncontrolled? (
useControlledValue
,useControlledState
, or custom implementation)
If you don't have the bandwidth, even just the first bullet point would be helpful!
Description
I was trying to play around with
@wordpress/components
for a plugin settings page in React for a demo for a WordCamp talk and I immediately noticed some problems in the current state of the components needed to build a form.The package and some of the components mentioned here have been around for years but still do not support the fundamental web standards. Using the components as uncontrolled is nearly impossible. One is forced to make the components controlled which is not very performant for large and complex forms.
Also, someone may want to stick to web fundamentals for building forms for plugin/theme settings pages.
Someone would argue that we:
It is not a valid argument because the responsibility of that warning goes to the consumer component and that is how the native form elements work.
Let us start:
Step-by-step reproduction instructions
TextControl
Issues:
Uncaught TypeError: onChange is not a function
TextareaControl
Same as
TextControl
__experimentalInputControl
One would argue that we have a better replacement for
TextControl
in the name of__experimentalInputControl
but it again fails:Issues
ToggleControl
Issues
Uncaught TypeError: onChange is not a function
CheckboxControl
Issues
onChange
issue.ToggleControl
RadioControl
Issues
Uncaught TypeError: onChange is not a function
defaultChecked
for theoptions
prop or in the component propsScreenshots, screen recording, code snippet
Codesandbox: https://codesandbox.io/p/sandbox/wordpress-components-issues-h5lgy8?file=%2Fsrc%2FApp.tsx
Environment info
No response
Please confirm that you have searched existing issues in the repo.
Yes
Please confirm that you have tested with all plugins deactivated except Gutenberg.
Yes