Please check the build logs for more information.
See Builds for ideas on how to fix a failed build, or Metadata for how to configure docs.rs builds.
If you believe this is docs.rs' fault, open an issue.
Ridstack-Form
Type-safe form handling for Dioxus.
Quickstart
use *;
use *;
use Error;
// reusable component
Status
Let's Deep Dive
Architecture
Check architecture.svg in the repo.
Field Value
For a field to work, the value of that field must apply FieldValue trait.
Every FieldValue needs to point a primitve field value which is basically String, u8, u16, bool, etc.
The primitive field value is required for the components to get data of the field.
Interconversion btw field and primitive field value is needed.
By default FieldValue and PrimitiveFieldValue is applied for most of rust built-in types.
You can also apply PrimitiveFieldValue on your own struct or enum. Then create components
accessing it as field data.
There's also a macro named FieldValue which builds FieldValue trait for wrapper-like structs.
It is helpful to auto build FieldValue if the underlying data implements PrimitiveFieldValue.
Reusable Components
Ridstack form is made on the principle of reusable components. It means you've to make components
or parts of your form only once and you can use it as many times as you want (like Tanstack Form).
You can make a component work only on a particular type of field. (Its based on the PrimitiveFieldValue type).
An example is here:
use *;
use *;
Here in the form generics, it's specified that only those types whose PrimitiveFieldValue is of String type.
In this way the type-safety of reusable components is maintained.
For your reference, I'm putting how to make a good components system in a separate dir (components dir) inside the repo's example dir.
If you want raw errors (errors in String form), you can use the use_raw_field_errors hook, which will directly return the
error of highest priority, maintained by Ord and PartialOrd (0 is the hightest, 1 next, ...) in form of String.
Note: This is directly copied from my project and thus many packages are unspecified.
Note: Ensure that use_raw_field_errors should be used inside Field component or its children as it may give a context error.
Manual Setup
- Create your data struct.
- Create error details for the fields for the form. it should handle this infallible error returned from string. and these derive traits are also required. You can also use many different types of error. Basically these errors will be used for validation which will be done by you only.
- Create a struct for storing your fields. Use Store macro on it.
- Create form state. Its advised (and mandatory also),
to use Store on the
TestFieldStateandFormState.
-
Let's start applying traits.
FormSubmitInputreturns the original data you've created.
GetFieldRegistryreturns the field_registry
- Here's the important part. Each field of the form needs an accessor
which is mostly (there are other patterns also) an empty struct with some derive impls.
Then we apply the
FieldStateProvidertaking this accessor as generic over theFieldRegistry. We could've returned and made theTestFieldStatetheFieldStateProviderbut the API doesn't allow us and also it may break granular reactivity provided by the store.
;- Now, we apply calculate can submit because it can't be auto-checked whether the fields are ready to be submitted or not.
- We will apply some traits required for Form management.
The first is
GetFormStatewhich makes us return the form state. The second isInitFormwhich returns a hook used to initialize the form
- We need to manually check which field validators to be run on submit. For this we apply
ValidateOnSubmittrait.
-
Create some components shown above. We mostly don't directly write component as we don't get type safety in the arguments of the closure.
-
Now the final piece. That's using this form. To get started, use the
use_form_providerhook and pass your form type (hereTestForm) in the turbofish operator. -
Then use the
Formcomponent to provide states to the child. This is the power that if you use modals or steppers, the form and field states will be preserved due to direct entry to the stores. -
Then use the
Fieldcomponent to access the fields. Use the accessor structs to ensure that theFieldcomponent points to the specified field. You can use thevalidatorsandasync_validatorsprop to set sync and async validators respectively. You can also use thevalidate_onprop to make sure that validators run before submit, on blur, on input or all.Note:
FormandFieldcomponents need heavy generics of the Form struct (hereTestForm). It is a better practice to already put the generics in a separate component and use that instead. Here's the last part.
] validators: FieldValue, FieldError, >, async_validators: FieldValue, FieldError, >, ) where TField: Clone + PartialEq + 'static, TestForm: , // reusable component
Some other patterns:
Note: This section will be updated slowly
- If you're building form manually, you can create an enum instead of accessor structs
if many fields of your struct are of same type. Then use match case in
FieldStateProvidertrait, to provide field states. But its better to let the macro do the work. - If you're building form manually, then you've to use the
use_form_providerfn to pass context down the tree. This opens an interesting view that if you're creating, for example someone's profile through form and want them to show a preview of what it may look, you can directly access the whole form throughuse_formfn outside theFormor html form component.
FAQs
- Was this library built with AI?
The answer is no. I don't use AI for some of my personal limitations. But some references through AI has been definitely taken especially the async validation debounces and updates, rest is purely built by me.
- Why do I need this library?
Imagine you've a data-struct. You've got a dioxus server-fn taking that data as input. Now, don't you think if you get a form having the required fields building you that data with all the state managements and validations built right for your data so that you can instantly call your server-fn on its submission, won't that be very nice?
Ridstack-form makes this possible.
You take a data-struct, apply GenForm macro, skip the fields you don't want in your form
by doing nothing on them, and add errors and optional accessor names on the fields you want in your
form and you get all the preparations instantly. Now in part of your app, you just instantiate your form
and in the on_submit function, you get the data ready to be put in your server fn.
- Why was this library built?
Honestly, I found no suitable form library in dioxus meeting my requirements. The form libraries in dioxus ecosystem is bit primitive and time consuming to build. This library gets you instantly started (Although, there are some quirks still there), and expand accordingly. Besides its completely built with dioxus stores thus enabling granular reactivity.
- Why is there no tests?
First of all, I'm lazy. And since I'm still a student, I've many things to do. I take some of my time daily to complete this.
And secondly, most of the logic is directly inside the Field component as it's a giant fn.
I could find any suitable way to test all of that. But the current app I'm building, I'm using it
there. If any problems arise, I'll make my best effort to solve the problem.
Or else, if you really want tests, just make a pr.
- Is this library very verbose?
Yes, setting up a form is very tedious.
But you don't have to worry as a giant macro is there to help you. It'll apply all the traits by itself. You only have apply the FieldValue trait on your field data.