Skip to content
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

TextField and TextArea: add error prop #2347

Open
wants to merge 12 commits into
base: main
Choose a base branch
from
Open

Conversation

beaesguerra
Copy link
Member

@beaesguerra beaesguerra commented Oct 15, 2024

Summary:

Adds an error prop to TextField and TextArea components so they can be put in an error state declaratively. This is useful for validation that happens after a form submission.

Related to the LabeledField work:

  • By having an error prop, the LabeledField component will set the error prop to true if it is provided with an error message (will do this in a separate PR for LabeledField work)
  • The error prop is consistent with other fields such as the SingleSelect, MultiSelect, and Combobox components. I'll be updating SearchField in another PR (with other updates)!
  • These changes can be released separately from the LabeledField changes since they are incremental changes to existing components

Issue: WB-1777

Test plan:

TextField

  • Setting the error prop puts the component in an error state (aria-invalid is set to true and error styling is applied) (?path=/story/packages-form-textfield--error)
  • Validation continues to put the component in an error state if the value is not valid (?path=/story/packages-form-textfield--error-from-validation)
  • Required prop continues to put the component in an error state if a value is cleared (?path=/story/packages-form-textfield--required)

TextArea

  • Setting the error prop puts the component in an error state (aria-invalid is set to true and error styling is applied) (?path=/story/packages-form-textarea--error)
  • Validation continues to put the component in an error state if the value is not valid (?path=/story/packages-form-textarea--error-from-validation)
  • Required prop continues to put the component in an error state if a value is cleared (?path=/story/packages-form-textarea--required)

@beaesguerra beaesguerra self-assigned this Oct 15, 2024
Copy link

changeset-bot bot commented Oct 15, 2024

🦋 Changeset detected

Latest commit: 3240bef

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 4 packages
Name Type
@khanacademy/wonder-blocks-form Minor
@khanacademy/wonder-blocks-search-field Patch
@khanacademy/wonder-blocks-dropdown Patch
@khanacademy/wonder-blocks-birthday-picker Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

Copy link
Contributor

github-actions bot commented Oct 15, 2024

Size Change: +38 B (+0.04%)

Total Size: 101 kB

Filename Size Change
packages/wonder-blocks-form/dist/es/index.js 6.25 kB +38 B (+0.61%)
ℹ️ View Unchanged
Filename Size
packages/wonder-blocks-accordion/dist/es/index.js 3.78 kB
packages/wonder-blocks-banner/dist/es/index.js 1.53 kB
packages/wonder-blocks-birthday-picker/dist/es/index.js 1.77 kB
packages/wonder-blocks-breadcrumbs/dist/es/index.js 887 B
packages/wonder-blocks-button/dist/es/index.js 4.04 kB
packages/wonder-blocks-cell/dist/es/index.js 2.01 kB
packages/wonder-blocks-clickable/dist/es/index.js 3.06 kB
packages/wonder-blocks-core/dist/es/index.js 3.44 kB
packages/wonder-blocks-data/dist/es/index.js 6.24 kB
packages/wonder-blocks-dropdown/dist/es/index.js 18.2 kB
packages/wonder-blocks-grid/dist/es/index.js 1.36 kB
packages/wonder-blocks-i18n/dist/es/index.js 4.76 kB
packages/wonder-blocks-icon-button/dist/es/index.js 3 kB
packages/wonder-blocks-icon/dist/es/index.js 828 B
packages/wonder-blocks-labeled-field/dist/es/index.js 72 B
packages/wonder-blocks-layout/dist/es/index.js 1.82 kB
packages/wonder-blocks-link/dist/es/index.js 2.28 kB
packages/wonder-blocks-modal/dist/es/index.js 5.36 kB
packages/wonder-blocks-pill/dist/es/index.js 1.65 kB
packages/wonder-blocks-popover/dist/es/index.js 4.87 kB
packages/wonder-blocks-progress-spinner/dist/es/index.js 1.52 kB
packages/wonder-blocks-search-field/dist/es/index.js 1.3 kB
packages/wonder-blocks-switch/dist/es/index.js 1.94 kB
packages/wonder-blocks-testing-core/dist/es/index.js 3.74 kB
packages/wonder-blocks-testing/dist/es/index.js 1.07 kB
packages/wonder-blocks-theming/dist/es/index.js 693 B
packages/wonder-blocks-timing/dist/es/index.js 1.8 kB
packages/wonder-blocks-tokens/dist/es/index.js 2.1 kB
packages/wonder-blocks-toolbar/dist/es/index.js 827 B
packages/wonder-blocks-tooltip/dist/es/index.js 7.08 kB
packages/wonder-blocks-typography/dist/es/index.js 1.23 kB

compressed-size-action

@@ -10,8 +10,6 @@ import {TextArea} from "@khanacademy/wonder-blocks-form";
/**
* The following stories are used to generate the pseudo states for the
* TextArea component. This is only used for visual testing in Chromatic.
*
* Note: Error state is not shown on initial render if the TextArea value is empty.
Copy link
Member Author

@beaesguerra beaesguerra Oct 15, 2024

Choose a reason for hiding this comment

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

Since we can explicitly put the component in an error state, the variants stories can properly show the error styling in all cases now! Previously, we weren't able to show an empty field with an error state since validation wouldn't be triggered yet in that case.

Screenshot 2024-10-15 at 5 22 58 PM

Copy link
Contributor

github-actions bot commented Oct 15, 2024

A new build was pushed to Chromatic! 🚀

https://5e1bf4b385e3fb0020b7073c-piwkdvgisf.chromatic.com/

Chromatic results:

Metric Total
Captured snapshots 39
Tests with visual changes 13
Total stories 501
Inherited (not captured) snapshots [TurboSnap] 335
Tests on the build 374

@beaesguerra beaesguerra marked this pull request as ready for review October 15, 2024 23:25
@khan-actions-bot khan-actions-bot requested a review from a team October 15, 2024 23:26
@khan-actions-bot
Copy link
Contributor

khan-actions-bot commented Oct 15, 2024

Gerald

Required Reviewers
  • @Khan/wonder-blocks for changes to .changeset/cold-cows-sit.md, __docs__/wonder-blocks-form/text-area-variants.stories.tsx, __docs__/wonder-blocks-form/text-area.stories.tsx, __docs__/wonder-blocks-form/text-field-variants.stories.tsx, __docs__/wonder-blocks-form/text-field.argtypes.ts, __docs__/wonder-blocks-form/text-field.stories.tsx, packages/wonder-blocks-form/src/components/text-area.tsx, packages/wonder-blocks-form/src/components/text-field.tsx, packages/wonder-blocks-form/src/components/__tests__/text-area.test.tsx, packages/wonder-blocks-form/src/components/__tests__/text-field.test.tsx

Don't want to be involved in this pull request? Comment #removeme and we won't notify you of further changes.

Copy link
Contributor

github-actions bot commented Oct 15, 2024

npm Snapshot: Published

🎉 Good news!! We've packaged up the latest commit from this PR (ad3dd5d) and published all packages with changesets to npm.

You can install the packages in webapp by running:

./services/static/dev/tools/deploy_wonder_blocks.js --tag="PR2347"

Packages can also be installed manually by running:

yarn add @khanacademy/wonder-blocks-<package-name>@PR2347

Comment on lines 142 to 145
/**
* Whether the textarea is in an error state.
*/
error?: boolean;
Copy link
Member

Choose a reason for hiding this comment

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

I feel that we could get into a tricky situation here.

Have you found a situation where a component instance needs to use both error and validate?

I'm thinking if we need to add more guardrails to prevent a case where these two props could collide.

It's tricky from the API perspective that the validation function would pass but the user would still see an error, and I wonder if this case is expected or not (and if not, then we should prevent from this to happen from the dev perspective).

Here's an example:
https://5e1bf4b385e3fb0020b7073c-kwxacxtfdq.chromatic.com/iframe.html?args=error:!true&id=packages-form-textarea--error-from-validation&viewMode=story

Screenshot 2024-10-16 at 11 23 04 AM

The email pattern is now valid, but the input is still showing its error state.

I wonder if/how we need to cover this case. wdyt?

Copy link
Member Author

Choose a reason for hiding this comment

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

Great question! I think this scenario is behaving as I would have expected (remaining in an error state after the email is in a valid format because the error prop is set to true). An example use case for this could be a sign up form where even if the email is valid, there could still be an error after form submission like the email provided is already associated with an account.

The workaround I used for backend validation errors before was to keep track of whether there is an error in the component state, check for that error in the validate function, and then also set the key on the component to whether there was an error so that the component would re-mount to trigger the validate function. Here is an example from webapp where I ran into this issue!

Part of the confusion could also be there is no error message in the story. The error message isn't part of the component, but it is shown in the story for example purposes. I'll update the story so another error message is shown if the error control is set!

Let me know what you think or if you have some ideas on other alternatives!

Copy link
Member

Choose a reason for hiding this comment

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

oh I see, thanks for the context.

Given your example, I still see that the user could get into an state where they use an email that is not associated with an account and they use valid email. Should the input update to its valid state? or should it remain using the error state?

Copy link
Member Author

Choose a reason for hiding this comment

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

The input would return to a valid state when the error prop is set to false (since in that case the email is fine to use).

I'll put together another story that has both error and validate props configured with logic so we can see how it will behave!

Copy link
Member

@jandrade jandrade Oct 16, 2024

Choose a reason for hiding this comment

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

The input would return to a valid state when the error prop is set to false (since in that case the email is fine to use).

That's the point I'm trying to get into.... this could lead into an "make impossible states impossible" situation. We would need to make sure that both error and validate are in sync and there might be cases where it would be confusing for the developer implementing a feature with these characteristics.

I wonder if there's a way to refactor this API to make it more predictable (even if it means changing validate/onValidate).

Copy link
Member Author

Choose a reason for hiding this comment

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

Thanks for the feedback, Juan! From our pairing session, we decided that:

  • it makes sense to support both error and validate props in the TextField and TextArea components since there are use cases for using both
  • we will need documentation around when to use these props
  • we will leave validation up to the field components instead of having LabeledField pass it down. This means LabeledField will only have an error prop for the error message and the validate prop will stay on TextField/TextArea
  • it will be helpful to have a shared utility/hook for the shared logic around validation: when to trigger validation, support for async validation, etc (will be explored in another PR).

I've added some more documentation around when to use error vs validate props, and have added examples for when both are used (TextField example and TextArea example)! I'll update the implementation spec as well!

Let me know what you think!

… ControlledTextArea to show a different error message if the error control is enabled
…e ErrorRender exampleto show a different error message if the error control is enabled
@khan-actions-bot khan-actions-bot requested a review from a team October 16, 2024 22:09
…rror prop is set to true. also updating docs to focus more on the error state rather than error messages (since the error messages are part of LabeledField)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants