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

Automatically apply HTML validation attributes based on zod schema #44

Closed
kentcdodds opened this issue Oct 26, 2022 · 6 comments
Closed

Comments

@kentcdodds
Copy link
Contributor

Is it possible to have the conform.input utility auto-apply HTML validation attributes based on the schema?

@kentcdodds
Copy link
Contributor Author

Along with this, it would be cool if you could give me a conform.label so I don't have to manually set the id and htmlFor to be the same between the label and input.

Something similar to remix-validity-state: https://github.com/brophdawg11/remix-validity-state#usevalidatedinput

Also, note the use of "Prop Getters" over "Prop Collections": https://kentcdodds.com/blog/how-to-give-rendering-control-to-users-with-prop-getters (just a suggestion).

Thanks!

@edmundhung
Copy link
Owner

edmundhung commented Oct 27, 2022

Hi @kentcdodds, welcome!

Update1: I just notice you were reviewing conform on your stream. Thanks! and sorry that it looks confusing because I am about to release a new version (v0.4) and I have updated the examples before the doc is ready. 😅

Update2: The resolve(zodSchema) API is no longer available on the new version and is replaced by some lower level APIs. I will update the docs asap.

Is it possible to have the conform.input utility auto-apply HTML validation attributes based on the schema?

Yes. The conform.input(config) helper can already apply the validation attributes if it knows about the constraint. For now, this requires some manual setup:

// This API is available only on pre-release (v0.4.0) due to some API changes lately.
import { getFieldsetConstraint } from '@conform-to/zod';

function LoginForm() {
  const { email, password } = useFieldset(ref, {
    constraint: getFieldsetConstraint(schema),
  });

  // ...
}

I am not sure if it is worth documented because of 2 major concerns:

  1. Zod schema is almost not analyzable. The helpers mentioned above is just best effort as this only works if you have the most basic schema, i.e. z.object({ email: z.string() }). But once you try to use some more advance features, e.g. pick / discriminatedUnion, The inner shape definition will be almost impossible to retrieve.
  2. The validation done by Zod is not directly comparable with the browser constraint. There are also issues with each validation attributes is supported by a subset of the input only. If we want to get this right, we will have to translate zod to a certain format that could apply the attributes with a runtime that polyfill the validation logic based on the actual input field used.

The usages I see for the derived constraint would be:

  1. Make it easy to style using CSS, e.g. :required
  2. Have some basic validation working before/without JS. But the message is not customizable and it might be simpler and cleaner relying on server validation.

Along with this, it would be cool if you could give me a conform.label so I don't have to manually set the id and htmlFor to be the same between the label and input.

Do you mean an auto-generated id? I agree this is handy as I wanted to do the same with the form id too. But I notice remix-validity-state is generating it based on useId() which requires react 18+.. 🤔

Also, note the use of "Prop Getters" over "Prop Collections": https://kentcdodds.com/blog/how-to-give-rendering-control-to-users-with-prop-getters (just a suggestion).

Thanks for the suggestion. I will definitely look into it.


I don't have a good story utilizing the native constraint yet unfortunately. In long term, I will properly try building a schema validation library with a browser runtime that utilize the native constraint. But it has to wait until I lay the groundwork with the validation flow.

@brandonpittman
Copy link
Contributor

Reach UI has an Auto ID module you could copy. I'd rather the IDs not be automatically added though, because you might be using something like React Aria that handles IDs itself.

@kentcdodds
Copy link
Contributor Author

using something like React Aria that handles IDs itself.

Most UI libraries allow you to override the ID. In any case, just because you can use a UI library that handles IDs, doesn't mean it wouldn't be handy to have this capability for when you're not using a UI library for basic fields as well.

Seems like it's difficult to convert a zod schema into HTML validations which is unfortunate. I may have to go with something more like remix-validity-state if that's important to me. Still evaluating 😅

@edmundhung
Copy link
Owner

Most UI libraries allow you to override the ID. In any case, just because you can use a UI library that handles IDs, doesn't mean it wouldn't be handy to have this capability for when you're not using a UI library for basic fields as well.

That makes sense. I will take a deeper look into the reach implementation. I think there are some limitations on these userland solutions. I might also make it a opt-in feature instead.

Seems like it's difficult to convert a zod schema into HTML validations which is unfortunate. I may have to go with something more like remix-validity-state if that's important to me. Still evaluating sweat_smile

This is the same story with yup as well. Since each of them has its own validation logic, e.g. ab@cd is considered a valid email in the browser but very likely not on yup or zod. I agree it would be really powerful if there is a solution that can lead the user to utilise these native browser constraint and understand when they are opting to custom validation. (e.g. In favor type and pattern to validate email instead of custom validate function).

I have started working on a draft APIs for it last 2 days. I will share more details once I have a concrete proposal. 😃

@edmundhung
Copy link
Owner

I think this can be considered done now as we have the getFieldsetConstraint(schema) helper together with empty value stripped which makes the model of mapping zod feature to each validation attributes much cleaner (e.g. required -> required instead of min(1) -> required). We are also configuring id for you if you provide an id to the useForm() hook.

I am still interested in a validation solution based on the validation attributes similar to this but it is a different story in the future.

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

No branches or pull requests

3 participants