Skip to content

πŸ‘» collection of atoms, utility functions and hooks to easily create forms with jotai and react

License

Notifications You must be signed in to change notification settings

omnidan/jotai-advanced-forms

Jotai Advanced Forms

πŸ“‹ collection of atoms, utility functions and hooks to easily create forms with jotai and react

🀝 Code of Conduct: Kept πŸ§ͺ Coverage πŸ“ License: MIT πŸ“¦ npm version πŸ’ͺ TypeScript: Strict

Documentation

The docs can be found at https://omnidan.github.io/jotai-advanced-forms/

Usage

npm i jotai-advanced-forms

In a directory co-located with the component/page that uses the form, place a state.ts file, with the following contents:

import { createForm } from "jotai-advanced-forms";

const { formFieldAtom, useForm } = createForm();
export { useForm };

// required field
export const firstNameAtom = formFieldAtom<string, "required">({
  initialState: "",
  validate: (value) => {
    if (value.length === 0) return "required";
  },
});

// optional field
export const lastNameAtom = formFieldAtom<string, undefined>({
  initialState: "",
});

Then, it is advisable to create custom input components that can deal with the props that this library provides:

import type { UseFormFieldProps } from "jotai-advanced-forms";

export function StringInput({
  value,
  onChange,
  onBlur,
  ref,
  hasError,
  errorCode,
  errorText,
}: UseFormFieldProps<string>) {
  return (
    <div>
      <input
        value={value}
        onChange={(e) => onChange(e.target.value)}
        onBlur={onBlur}
        ref={ref}
      />
      {hasError && (
        <p>
          {errorText} ({errorCode})
        </p>
      )}
    </div>
  );
}

Now, in a React component that contains the form, you can do the following:

import { useFormField } from "jotai-advanced-forms";
import { firstNameAtom, lastNameAtom, useForm } from "./state.js";
import { StringInput } from "./StringInput.js";

export function NameInputForm() {
  const firstNameField = useFormField({
    atom: firstNameAtom,
    errors: {
      // if you do not specify this, it will cause a type error, forcing you to handle error messages!
      required: "First name is required!",
    },
  });

  const lastNameField = useFormField({
    atom: lastNameAtom,
  });

  const { submitForm, resetForm, isSubmitting } = useForm({
    onValid: () => alert("success!"),
  });

  function handleSubmit(e) {
    e.preventDefault();
    submitForm();
  }

  return (
    <form onSubmit={handleSubmit}>
      <StringInput {...firstNameField} />
      <StringInput {...lastNameField} />
      <input type="submit" value="Submit" disabled={isSubmitting} />
      <button type="button" onClick={resetForm}>
        Reset Form
      </button>
    </form>
  );
}

Resetting Form Fields

You can reset the entire form or individual fields:

import { useAtom } from "jotai";
import { useResetAtom } from "jotai/utils";

// Reset the entire form
const { resetForm } = useForm({
  onValid: () => alert("success!"),
});

resetForm(); // Resets all fields to their initial values

// Reset an individual field
const emailField = formFieldAtom({ initialState: "" });
const resetEmail = useResetAtom(emailField);

resetEmail(); // Resets only the email field

Development

See .github/CONTRIBUTING.md, then .github/DEVELOPMENT.md. Thanks! πŸ’–

πŸ’ This package was templated with create-typescript-app using the create engine.

About

πŸ‘» collection of atoms, utility functions and hooks to easily create forms with jotai and react

Resources

License

Code of conduct

Contributing

Security policy

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Contributors 2

  •  
  •