CARVIEW |
Navigation Menu
-
Notifications
You must be signed in to change notification settings - Fork 4.6k
Add support for ValidatedFormTokenField #71350
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
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 If you're merging code through a pull request on GitHub, copy and paste the following into the bottom of the merge commit message.
To understand the WordPress project's expectations around crediting contributors, please review the Contributor Attribution page in the Core Handbook. |
cc @mirka |
There was a problem hiding this comment.
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! 🙏
packages/components/src/validated-form-controls/components/array-control.tsx
Outdated
Show resolved
Hide resolved
packages/components/src/validated-form-controls/components/stories/input-control.story.tsx
Outdated
Show resolved
Hide resolved
customValidity={ customValidity } | ||
getValidityTarget={ getInputElement } | ||
> | ||
<div ref={ formTokenFieldRef }> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Certain props are passed down from ControlWithError
to the inner control, so this simple div wrapper is not going to be sufficient. (I notice this wasn't mentioned anywhere in the documentation, so I'll add it at #71392.)
gutenberg/packages/components/src/validated-form-controls/control-with-error.tsx
Lines 223 to 231 in 775f0ce
{ cloneElement( children, { | |
label: appendRequiredIndicator( | |
children.props.label, | |
required, | |
markWhenOptional | |
), | |
onChange, | |
required, | |
} ) } |
As for the ref passing, we can now make changes to the @wordpress/components
components directly (unlike when I was working on the other controls 😅), so I think it would be cleaner to enhance FormTokenField
itself so it forwards a ref to the underlying input
. Right now FormTokenField
doesn't take a ref at all. We should also enhance it so the required
prop on FormTokenField
would also be passed down to the underlying input
. This would allow us to be less hacky in this implementation. Could you try that?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thank you for the review!
I looked into this, and this component is somewhat more challenging than the others. Since the checks for the required field only verify the input's value (i.e., not the tokens), it would always trigger an error, even when the field contains tokens.
I made some changes to disable the default required
checks, but I'm unsure if this is the best approach or if you have other suggestions I can try.
Thank you!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I see! This has happened on two other components (ToggleGroupControl
and CustomSelectControl
), and I worked around it by using a hidden "delegate" element. At the time I thought it was hacky, but I later discovered that at least one other library uses a similar technique for all their validated form components, so I guess it isn't that weird.
I think we could try a normal <input type="text">
delegate here, since the built-in error message for required
("Please fill out this field.") is generic enough for FormTokenField
. A <select multiple>
delegate would be a better match for our array data type, but the built-in error message ("Please select an item in the list.") doesn't fit cases where FormTokenField
can accept new items generated by the user.
Basically you append a hidden <input value={ hasTokens ? "has value" : "" }>
or something so the required
check reflects the selected token state. Does that make sense?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Gotcha! Thank you 🙏 I pushed changes in b6c9b91, let me know how that looks
/** | ||
* Internal dependencies | ||
*/ | ||
import { ControlWithError } from '../control-with-error'; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I noticed some Sass variable handling is wrong in the stylesheet, so I'll fix it in #71391. With that in mind though, I think we'll need some error styles for FormTokenField
as well, similar to what we have for ComboboxControl
.
gutenberg/packages/components/src/validated-form-controls/style.scss
Lines 16 to 21 in 775f0ce
// For ComboboxControl | |
.components-combobox-control__suggestions-container:has( | |
input:user-invalid | |
):not(:has([aria-expanded="true"])) { | |
border-color: $alert-red; | |
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I pushed some styles we can use in abc76d7.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looking good! It's working as expected once the changes to FormTokenField
itself are reverted.
packages/components/src/validated-form-controls/components/index.ts
Outdated
Show resolved
Hide resolved
packages/components/src/validated-form-controls/components/stories/input-control.story.tsx
Show resolved
Hide resolved
packages/components/src/validated-form-controls/components/form-token-field.tsx
Outdated
Show resolved
Hide resolved
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think we can revert the changes here in FormTokenField
, since we're going with the delegate now. Passing down the required
prop is actually problematic now, because it creates a required input that can never be filled 😄
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think only the required
passing can be reverted, not the whole file. Done in ba0bd0f
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think the ref forwarding is strictly necessary for the functionality in this PR? It's more of an unrelated enhancement for FormTokenField
at this point. No strong opinion though.
packages/components/src/validated-form-controls/components/stories/form-token-field.story.tsx
Show resolved
Hide resolved
/** | ||
* Internal dependencies | ||
*/ | ||
import { ControlWithError } from '../control-with-error'; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I pushed some styles we can use in abc76d7.
…gutenberg into add/array-form-control
Looks good after the recent changes, thank you for your help @mirka ! CleanShot.2025-09-09.at.17.09.45.mp4 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for all the follow-ups! Looks great 🚀
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think the ref forwarding is strictly necessary for the functionality in this PR? It's more of an unrelated enhancement for FormTokenField
at this point. No strong opinion though.
* Add ValidatedArrayControl component * Export ValidatedArrayControl component from validated-form-controls index file * Add ArrayControl story for ValidatedArrayControl component with validation logic * add changelog * Rename UnforwardedValidatedArrayControl to UnforwardedValidatedFormTokenField * Rename to form-token-field * Correct changelog place * Add a separate storybook page for the new component * Update FormTokenFieldProps interface to include 'required' prop * Refactor FormTokenField to use forwardRef and include 'required' prop * Enhance FormTokenField validation logic and refactor refs management * Replace HTML5 overriding with the delegate solution to match other components * Move changelog to unreleased * Add error styles * Move the export down for alphabetical order * revert changes in input-control story * Remove unnecessary use of name attribute * Revert passing required down * Add __experimentalExpandOnFocus for discoverability * Remove forward ref functionality * Add forwardedRef to div --------- Co-authored-by: elazzabi <elazzabi@git.wordpress.org> Co-authored-by: mirka <0mirka00@git.wordpress.org> Co-authored-by: oandregal <oandregal@git.wordpress.org>
https://github.com/WordPress/gutenberg/blob/trunk/CONTRIBUTING.md -->
What?
This adds support for the ValidatedArrayControl
Why?
This add a validated control to be used in different parts of the admin, including the country selector.
How?
CleanShot.2025-08-26.at.10.47.25.mp4
Testing Instructions
ValidatedInputControl
and scroll down to Array ControlTesting Instructions for Keyboard
Screenshots or screencast
Included above