Gathering detailed insights and metrics for react-ux-form
Gathering detailed insights and metrics for react-ux-form
Gathering detailed insights and metrics for react-ux-form
Gathering detailed insights and metrics for react-ux-form
devextreme-react
DevExtreme React UI and Visualization Components
@swan-io/use-form
A simple, fast and opinionated form library for React & React Native focusing on UX.
react-browser-form
<div align="center"> <a href="https://deniskabana.github.io/react-browser-form/introduction" title="React Browser Form - Form management in React made simple for browsers."> <img src="https://raw.githubusercontent.com/deniskabana/react-browser-form/
craft-ux
`craft-ux` is a dynamic form-building library that provides components to create and manage form workflows efficiently. Built for React and powered by Redux, `craft-ux` allows you to build highly customizable and scalable forms, ideal for use cases in fin
A simple, fast, and opinionated form library for React & React Native focusing on UX.
npm install react-ux-form
Typescript
Module System
Node Version
NPM Version
TypeScript (97.49%)
HTML (1.9%)
JavaScript (0.61%)
Total Downloads
0
Last Day
0
Last Week
0
Last Month
0
Last Year
0
MIT License
210 Stars
261 Commits
7 Forks
7 Watchers
3 Branches
93 Contributors
Updated on Jul 08, 2025
Latest Version
1.5.0
Package Id
react-ux-form@1.5.0
Unpacked Size
108.04 kB
Size
30.67 kB
File Count
8
NPM Version
8.19.2
Node Version
18.12.1
Published on
Aug 08, 2023
Cumulative downloads
Total Downloads
Last Day
0%
NaN
Compared to previous day
Last Week
0%
NaN
Compared to previous week
Last Month
0%
NaN
Compared to previous month
Last Year
0%
NaN
Compared to previous year
1
1
A simple, fast, and opinionated form library for React & React Native focusing on UX.
👉 Take a look at the demo website.
1$ npm install --save react-ux-form 2# --- or --- 3$ yarn add react-ux-form
Why another React form library 🤔?
Because, as silly as it seems, we couldn't find any existing library which fits our existing needs:
The key of good UX is simple: validation should be executed in continue, feedback should be provided when it makes sense.
Let's say we want to display a valid state icon (✔) when the input value is a valid credit card number but don't want to display an error until the user blurs the field (and lets the value in an invalid state).
How do we easily achieve such magic? With the onSuccessOrBlur
strategy 🧙♂️
1const {} = useForm({ 2 cardNumber: { initialValue: "", strategy: "onSuccessOrBlur" }, 3});
Of course, onSuccessOrBlur
will not fit perfectly every use-case!
That's precisely why every field config could declare its own strategy
:
Strategy | When feedback will be available? |
---|---|
onChange | On first change (as the user types or update the value) |
onSuccess | On first validation success |
onBlur | On first field blur |
onSuccessOrBlur | On first validation success or first field blur (default) |
onSubmit | On form submit |
valid
or should display an error
message), the field switches to what we call "talkative" state. After that, feedback will be updated on each value change until this field or the form is reset.⚠️ The API is described using TypeScript pseudocode.
These types are not exported by the library / are not even always valid.
useForm
takes one argument (a map of your fields configs) and returns a set of helpers (functions, components, and values) to manage your form state.
1import { useForm } from "react-ux-form";
2
3const {
4 formStatus,
5 Field,
6 FieldsListener,
7 getFieldState,
8 setFieldValue,
9 setFieldError,
10 focusField,
11 resetField,
12 sanitizeField,
13 validateField,
14 listenFields,
15 resetForm,
16 submitForm,
17} = useForm({
18 // Keys are used as fields names
19 fieldName: {
20 initialValue: "",
21 // Properties below are optional (those are the default values)
22 strategy: "onSuccessOrBlur",
23 debounceInterval: 0,
24 equalityFn: (value1, value2) => Object.is(value1, value2),
25 sanitize: (value) => value,
26 validate: (value, { focusField, getFieldState }) => {},
27 },
28});
1type fieldConfig = { 2 // The initial field value. It could be anything (string, number, boolean…) 3 initialValue: Value; 4 5 // The chosen strategy. See "validation strategies" paragraph 6 strategy: Strategy; 7 8 // An amount of time (in ms) to wait before triggering validation 9 debounceInterval: number; 10 11 // When performing async validation, it might happen that the value has changed between the start and the end of its execution 12 // That's why we compare the two values: to ensure that the feedback given to the user is correct 13 equalityFn: (value1: Value, value2: Value) => boolean; 14 15 // Will be run on value before validation and submission. Useful from trimming whitespaces 16 sanitize: (value: Value) => Value; 17 18 // Used to perform field validation. It could return an error message (or nothing) 19 // It also handle async: simply return a Promise that resolves with an error message (or nothing) 20 validate: (value: Value) => ErrorMessage | void | Promise<ErrorMessage | void>; 21};
1type formStatus = 2 | "untouched" // no field has been updated 3 | "editing" 4 | "submitting" 5 | "submitted";
<Field />
A component that exposes everything you need locally as a children
render prop.
1<Field name="fieldName"> 2 { 3 (props: { 4 // A ref to pass to your element (only required for focus handling) 5 ref: MutableRefObject; 6 // The field value 7 value: Value; 8 // Is the field validating? (only happen on async operations) 9 validating: boolean; 10 // Is the field valid? 11 valid: boolean; 12 // The field is invalid: here its error message. 13 error?: ErrorMessage; 14 // The onBlur handler (required for onBlur and onSuccessOrBlur strategies) 15 onBlur: () => void; 16 // The onChange handler (required) 17 onChange: (value: Value) => void; 18 // Focus the next field (uses the field config declaration order in useForm) 19 focusNextField: () => void; 20 }) => /* … */ 21 } 22</Field>
<FieldsListener />
A component that listens for fields states changes. It's useful when a part of your component needs to react to fields updates without triggering a full re-render.
1<FieldsListener names={["firstName", "lastName"]}> 2 { 3 (states: Record<"firstName" | "lastName", { 4 // The field value 5 value: Value; 6 // Is the field validating? (only happen on async operations) 7 validating: boolean; 8 // Is the field valid? 9 valid: boolean; 10 // The field is invalid: here its error message. 11 error?: ErrorMessage; 12 }>) => /* … */ 13 } 14</FieldsListener>
By setting sanitize: true
, you will enforce sanitization.
1type getFieldState = ( 2 name: FieldName, 3 options?: { 4 sanitize?: boolean; 5 }, 6) => { 7 value: Value; 8 validating: boolean; 9 valid: boolean; 10 error?: ErrorMessage; 11};
By setting validate: true
, you will enforce validation. It has no effect if the field is already talkative.
1type setFieldValue = ( 2 name: FieldName, 3 value: Value, 4 options?: { 5 validate?: boolean; 6 }, 7) => void;
Will make the field talkative.
1type setFieldError = (name: FieldName, error?: ErrorMessage) => void;
Will only work if you forward the Field
provided ref
to your input.
1type focusField = (name: FieldName) => void;
Hide user feedback (the field is not talkative anymore). If feedbackOnly
is not set to true
, value will also be resetted to initialValue
.
1type resetField = ( 2 name: FieldName, 3 options?: { 4 feedbackOnly?: boolean; 5 }, 6) => void;
Sanitize the field value.
1type sanitizeField = (name: FieldName) => void;
Once you manually call validation, the field automatically switches to talkative state.
1type validateField = (name: FieldName) => Promise<ErrorMessage | void>;
A function that listen for fields states changes. Useful when you want to apply side effects on values change.
1React.useEffect(() => { 2 const removeListener = listenFields( 3 ["firstName", "lastName"], 4 (states: Record<"firstName" | "lastName", { 5 // The field value 6 value: Value; 7 // Is the field validating? (only happen on async operations) 8 validating: boolean; 9 // Is the field valid? 10 valid: boolean; 11 // The field is invalid: here its error message. 12 error?: ErrorMessage; 13 }>) => /* … */ 14 ); 15 16 return () => { 17 removeListener(); 18 } 19}, []);
Hide user feedback for all fields (they are not talkative anymore). If feedbackOnly
is not set to true
, values will also be resetted to their corresponding initialValue
and formStatus
will be resetted to untouched
.
1type resetForm = (options?: { feedbackOnly?: boolean }) => void;
Submit your form. Each callback could return a Promise
to keep formStatus
in submitting
state.
1type submitForm = ( 2 onSuccess: (values: Partial<Values>) => Promise<unknown> | void, 3 onFailure?: (errors: Partial<ErrorMessages>) => Promise<unknown> | void, 4 options?: { 5 // by default, it will try to focus the first errored field (which is a good practice) 6 avoidFocusOnError?: boolean; 7 }, 8) => void;
As it's a very common case to use several validation functions per field, we export a combineValidators
helper function that allows you to chain sync and async validation functions: it will run them sequentially until an error is returned.
1import { combineValidators, useForm } from "react-ux-form";
2
3const validateRequired = (value: string) => {
4 if (!value) {
5 return "required";
6 }
7};
8
9const validateEmail = (email: string) => {
10 if (!/.+@.+\..{2,}/.test(email)) {
11 return "invalid email";
12 }
13};
14
15const MyAwesomeForm = () => {
16 const { Field, submitForm } = useForm({
17 emailAddress: {
18 initialValue: "",
19 // will run each validation function until an error is returned
20 validate: combineValidators(
21 isEmailRequired && validateRequired, // validation checks could be applied conditionally
22 validateEmail,
23 ),
24 },
25 });
26
27 // …
28};
Very often, we want to execute validation only if a value is not empty. By wrapping any validator (or combined validators) with toOptionalValidator
, you can bypass the validation in such cases.
1import { toOptionalValidator, Validator } from "react-ux-form"; 2 3// This validator will error if the string length is < 3 (even if it's an empty string) 4const validator: Validator<string> = (value) => { 5 if (value.length < 3) { 6 return "Must be at least 3 characters"; 7 } 8}; 9 10// This validator will error if value is not empty string and if the string length is < 3 11const optionalValidator = toOptionalValidator(validator);
This function also accept a second param (required for non-string validators) to specify what is an empty value.
1import { toOptionalValidator, Validator } from "react-ux-form"; 2 3const validator: Validator<number> = (value) => { 4 if (value < 10) { 5 return "Must pick at least 10 items"; 6 } 7}; 8 9// This validator will also accept a value of 0, as we consider it "empty" 10const optionalValidator = toOptionalValidator(validator, (value) => value === 0);
As some of your fields might be unmounted on submit, the submitForm
method could not guarantee that every field value is defined and valid. We export hasDefinedKeys
helper function that allows you to test if some object keys are defined.
1import { hasDefinedKeys, useForm } from "react-ux-form"; 2 3const MyAwesomeForm = () => { 4 const { Field, submitForm } = useForm({ 5 firstName: { initialValue: "" }, 6 lastName: { initialValue: "" }, 7 }); 8 9 const handleSubmit = () => { 10 submitForm((values) => { 11 if (hasDefinedKeys(values, ["firstName", "lastName"])) { 12 // values.firstName and values.lastName are defined (the fields are mounted) 13 } 14 }); 15 }; 16 17 // … 18};
1import { useForm } from "react-ux-form"; 2 3const MyAwesomeForm = () => { 4 const { Field, submitForm } = useForm({ 5 firstName: { 6 initialValue: "", 7 strategy: "onSuccessOrBlur", 8 sanitize: (value) => value.trim(), // we trim value before validation and submission 9 validate: (value) => { 10 if (value === "") { 11 return "First name is required"; 12 } 13 }, 14 }, 15 }); 16 17 return ( 18 <form 19 onSubmit={(event: React.FormEvent) => { 20 event.preventDefault(); 21 22 submitForm( 23 (values) => console.log("values", values), // all fields are valid 24 (errors) => console.log("errors", errors), // at least one field is invalid 25 ); 26 }} 27 > 28 <Field name="firstName"> 29 {({ error, onBlur, onChange, valid, value }) => ( 30 <> 31 <label htmlFor="firstName">First name</label> 32 33 <input 34 id="firstName" 35 onBlur={onBlur} 36 value={value} 37 onChange={({ target }) => { 38 onChange(target.value); 39 }} 40 /> 41 42 {valid && <span>Valid</span>} 43 {error && <span>Invalid</span>} 44 </> 45 )} 46 </Field> 47 48 <button type="submit">Submit</button> 49 </form> 50 ); 51};
A full set of examples is available on the demo website or in the /website
directory project. Just clone the repository, install its dependencies and start it!
No vulnerabilities found.
No security vulnerabilities found.