milliform

GitHub
A super basic React form library!

About:

milliform is a super basic React form library that doesn't impose any constraints on rendering of your form.

milliform provides a useForm React hook that provides all the utilities you'll need to manage the state of your form.

Installation:

milliform can be installed using your favorite package manager (e.g. yarn, pnpm, or npm):

yarn add milliform

Or it can be imported from a CDN like unpkg or esm.sh:

import {useForm, Fields} from 'https://esm.sh/milliform@latest'

Usage:

First let's start with a basic example using plain old inputs to build a login form:

SimpleLoginExample.tsx
1'use client'
2import { useForm, Fields } from 'milliform'
3import { FormEvent } from 'react'
4
5let fields: Fields = {
6 email: {
7 validate(email) {
8 if (!email || !email.includes('@')) {
9 return 'No valid email provided!'
10 }
11 },
12 },
13 password: {
14 validate(pass) {
15 if (!pass) {
16 return 'No valid password provided!'
17 }
18 },
19 },
20}
21
22export default function Form() {
23 let {
24 values: { email, password },
25 setters: { setEmail, setPassword },
26 errors,
27 validate,
28 reset,
29 } = useForm<['email', 'password']>(fields)
30
31 function handleSubmit(e: FormEvent<HTMLFormElement>) {
32 e.preventDefault()
33 let errors = validate()
34 if (errors) {
35 return
36 }
37 // Submit values...
38 reset()
39 }
40
41 return (
42 <form onSubmit={handleSubmit}>
43 <label>
44 Email:
45 <input
46 type="email"
47 name="email"
48 value={email}
49 autoComplete="off"
50 onChange={(e) => {
51 setEmail(e.target.value)
52 }}
53 />
54 </label>
55 {errors && errors.email ? (
56 <div>
57 {errors.email}
58 </div>
59 ) : null}
60 <label>
61 Password:
62 <input
63 type="password"
64 name="password"
65 value={password}
66 autoComplete="new-password"
67 onChange={(e) => {
68 setPassword(e.target.value)
69 }}
70 />
71 </label>
72 {errors && errors.password ? (
73 <div>
74 {errors.password}
75 </div>
76 ) : null}
77 <button
78 type="submit"
79 >
80 Submit
81 </button>
82 </form>
83 )
84}
85

In this example, we're passing the values down to the input elements, wrapping the onChange handlers to extract the value from the event and pass it to the setters. Additionally, we conditionally render an error banner below each input if there are errors in the field.

Within the form's onSubmit handler, we call validate to validate all the fields, if the fields are valid then we continue on to submit the form fields. In this example, we're only resetting the form by calling reset.

In Depth:

To get started with milliform, you'll define the fields that are within the form:

1import type {Fields} from 'milliform';
2
3let fields: Fields = {
4 // field name
5 amount: {
6 // defining a validator function
7 // this is called with the value for the field when `validate` is called
8 validate(value) {
9 // the function must either return a string (indicating an error/invalid value)
10 // or undefined indicating that the value is valid
11 if (Number(amount) < 50) {
12 return 'Invalid amount selected!'
13 }
14 }
15 }
16}

You can then call useForm with the defined fields and get back the following values:

1import {useForm, Fields} from 'milliform'
2
3let fields: Fields = {
4 // field name
5 amount: {
6 // defining a validator function
7 // this is called with the value for the field when `validate` is called
8 validate(value) {
9 // the function must either return a string (indicating an error/invalid value)
10 // or undefined indicating that the value is valid
11 if (Number(amount) < 50) {
12 return 'Invalid amount selected!'
13 }
14 }
15 }
16}
17
18function Form() {
19 let {
20 values: {amount},
21 setters: {setAmount},
22 errors,
23 validate,
24 reset
25 } = useForm(fields)
26
27 // ... render the form ...
28}