valibot icon indicating copy to clipboard operation
valibot copied to clipboard

feat: add formData schema, checkbox action, and formDataEntries action

Open EskiMojo14 opened this issue 7 months ago • 6 comments

Given a form:

<form enctype="multipart/form-data" method="post">
  <input name="username" type="text" />
  <label>
    <input type="checkbox" name="accepted" />
    Accept T&Cs
  </label>
  <fieldset>
    <legend>Contact me</legend>
    <label>
      <input type="checkbox" name="contact" value="SMS" />
      SMS
    </label>
    <label>
      <input type="checkbox" name="contact" value="Email" />
      Email
    </label>
  </fieldset>
</form>

You could validate it:

const FormSchema = v.pipe(
  v.formData(),
  v.formDataEntries(["contact"]),
  v.object({
    username: v.string(),
    accepted: v.pipe(v.string(), v.checkbox(), v.literal(true))
    contact: v.array(v.string())
  })
)

EskiMojo14 avatar Apr 09 '25 10:04 EskiMojo14

The latest updates on your projects. Learn more about Vercel for Git ↗︎

Name Status Preview Comments Updated (UTC)
valibot ❌ Failed (Inspect) May 20, 2025 1:39pm

vercel[bot] avatar Apr 09 '25 10:04 vercel[bot]

Thanks your for this PR! I think I would recommend using a library like decode-formdata instead for such use cases: https://github.com/fabian-hiller/decode-formdata

What do you think?

fabian-hiller avatar Apr 10 '25 05:04 fabian-hiller

Thanks your for this PR! I think I would recommend using a library like decode-formdata instead for such use cases: https://github.com/fabian-hiller/decode-formdata

What do you think?

For more complex forms, I agree:

https://github.com/fabian-hiller/valibot/blob/0e9fd56013c8fe94de392db4d4119f164b1115e6/library/src/actions/formDataEntries/formDataEntries.ts#L40

I still think there could be room for a built-in alternative for simpler forms, and then the user can switch when they need.

Alternatively, it could be interesting to have an action wrapper for decode-formdata:

v.pipe(
  v.formData(),  
  decodeFormData({
    arrays: ['tags', 'images'],
    booleans: ['active'],
    dates: ['created', 'images.$.created'],
    files: ['images.$.file'],
    numbers: ['price'],
  }),
  finalSchema
)

EskiMojo14 avatar Apr 10 '25 08:04 EskiMojo14

Yes, you are right. decode-formdata is too opinionated to provide an official schema or actions based on it. I will think about following your recommendation and provide a formData schema and a basic decodeFormData action that just converts the entries to a JS object without any special behaviour.

What is your use case for using v.pipe(v.formData(), v.decodeFormData())? Why not do the decoding before and pass the result to Valibot. I ask because I want to evaluate if we should add it, as there is always a downside when extending the API interface of the library.

fabian-hiller avatar Apr 20 '25 00:04 fabian-hiller

just preference really - i like having the transformation contained in the schema, rather than having to do it separately before feeding it in

similar to the json methods from #1137

EskiMojo14 avatar Apr 20 '25 00:04 EskiMojo14

Maybe it is a good idea to mention on what we are woking on in our v1.1 blog post so people can reach out if they are interested in this PR.

fabian-hiller avatar Apr 20 '25 00:04 fabian-hiller