2.0.0-rc1 • Published 3 years ago

amiable-forms v2.0.0-rc1

Weekly downloads
7
License
MIT
Repository
github
Last release
3 years ago

amiable-forms

A library for creating forms in React using hooks. This project requires no dependencies other than React as a peer dependency and is written from the ground up with hooks in mind. It is easy to integrate into any form UI. To achieve this, no renderable form or field component are provided or required. Instead hooks are used to transform any component needed into a form. If desired, this allows forms to be created even without the use of standard browser form elements.

  • built using React Hooks
  • independent field handling
  • highly compatible, easy to integrate
  • efficient, fields only render when needed

Installation

amiable-forms requires React 16.8.3 or later.

npm install --save amiable-forms

Getting Started

First wrap the form components with the <AmiableForm> component provided by amiable-forms. This will not add any visual components or inject any props. Its purpose is only to provide a context for the hooks to use.

Field components can be defined with the useField hook. This can be done many different ways, a very simplistic version is shown in the example below.

The last hook that will most likely be required is the useSubmit hook which provides an onSubmit method.

const Input = props => {
  const { value, onChange } = useField({ name: props.name })
  return <input {...props} value={value} onChange={onChange} />
}

const SubmitButton = () => {
  const { onSubmit } = useSubmit()
  return <button onClick={onSubmit}>Login</button>
}

const process = values => console.log('Submit', values)

const LoginForm = () => (
  <AmiableForm process={process}>
    <Input name="username" placeholder="username" />
    <Input name="password" placeholder="password" type="password" />
    <SubmitButton />
  </AmiableForm>
)

To see a more complete example of a form built with amiable-forms use this codesandbox link: Simple Example Form
// TODO: update example to use 1.1.4

Documentation

AmiableForm

The AmiableForm component is used to provide a React context and is not a visual component. This shouldn't be confused with any visual UI Form components that might be required for your specific form setup. The AmiableForm component must be wrapped around the entire form for any of the amiable-forms hooks and helper components to function. This allows form state to be shared without needing explicit prop passing.

<AmiableForm
  process={() => {}}
  processInvalid={() => {}}
  validate={() => {}}
  transform={() => {}}
  initialValues={{}}>
  ...
</AmiableForm>
Prop NameTypeDescription
processfunction(values, ...args)function called when a valid form is submittedrequired
processInvalidfunction(values, formMeta, fields)function called when an invalid form is submitted
validatefunction(values)return error string
transformfunction({ current, next })return transformed state
initialValuesplain objectthe initial values to set to the form

useField

The useField hook is used to define a field component. amiable-form doesn't provide a Field component and instead provides this hook. This is a design choice to increase compatibility to various form layouts making its integration a more amiable task.

The useField hook will only cause renders when the value for that field changes.

const YourField = () => {
  const { value, onChange } = useField({ name: 'field1' })
  return <input value={value} onChange={onChange} />
}
Input Key NameTypeDescription
namestringThe name of the field and key in the values object. The name can use a path following the same convention as lodash's set and get functions.required
validators[function(), ...]An array of validation function
parsefunction()
formatfunction()
parseWhenFocusedboolean
customdunno

The useField hook returns many variables to accommodate a variety of situations.

Return NameTypeDescription
valueanythe current value of the field
submittedbooleanif the form has attempted to be submitted
setValuefunction()sets the value of the field
setVisitedfunction()marks the field as visited
setFocusedfunction()marks the field as focused
onChangefunction(ev)helper handler, calls setValue
onBlurfunction(ev)helper handler, calls setVisited()
errorstringcontains error messages from the validator functions
validbooleansignals if the field is valid or invalid
touchedbooleansignals if the field's value has ever changed
visitedbooleansignals if a user has clicked through a field
dirtybooleansignals if the value of the field differs from the initial state
cleanValueanythe initial value of the field(?)

Field Validators

Field level validation is accomplished by providing an array of validation functions to the useField hook under the validators input key. The current field value is passed to each validation function when invoked and the validator will either return undefined for a pass condition or a string containing the error message. The error message from the first failing validator will be set to the error key return value of the useField hook.

Validator Function Exmaples

const required = value => value ? undefined : 'required'

const numeric = value => (!value || /^\\d+$/i.test(value)) ? undefined : 'invalid'

Field Parse and Format

The parse and format functions can be used when the value shown to the user in the form differs from what needs to be saved in the data. For example, date fields might want to display a format of MM/DD/YYYY to the user but store the value as YYYY-MM-DD. The parse function is used to read the information in the field and convert it into the form data format. format is used to convert the form data value into a value to be shown to the user. The parse function can also be used as a way to normalize the user input. By default, the value will be parsed when entered, but can be turned off by setting parseWhenFocused to false.

Validator Function Exmaples

const parse = value => (value && value.toUpperCase()) || undefined

const format = value => (value || '').toLowerCase()

useForm

The useForm hook is the base amiable-forms hook and provides access to the entire state of the form. All of the other hooks are built using useForm. By default, useForm will cause the component it is in to render on every change. To avoid unnecessary renders, the shouldUpdate function needs to be passed into it as an argument.

const never = () => false
const { setValues } = useForm({ shouldUpdate: never })
Input Key NameTypeDescription
shouldUpdatefunction({ previous, current })is given the current and previous form state and returns true if the component should render or false if not
Return NameTypeCategoryDescription
setValuefunction()actions
setValuesfunction()actions
setFieldfunction()actions
setMetaValuefunction()actions
removeFieldfunction()actions
resetfunction()actions
clearfunction()actions
valuesobjectstate
fieldsobjectstate
metaobjectstate
cleanValuesobjectstate
submitfunction()submission
onSubmitfunction()submission
registerfunction()registration
deregisterfunction()registration

Field Meta

NameTypeDescription
errorstring
validboolean
touchedboolean
visitedboolean
dirtyboolean
registeredboolean
focusedboolean

Form Meta

NameTypeDescription
touchedboolean
submittedboolean
visitedboolean
validboolean
dirtyboolean
errorstring

Helper Utilties

useFieldValue

useArrayField

useRepeated

useFieldCustomMeta

Debug

Solutions to Common Problems

  • conditional sections based on form state
  • setting form state (or submitting) from external source
  • sending additional arguments to the process function
  • complex fields
  • destructive parse (parseWhenFocused)
2.0.0-rc1

3 years ago

1.3.6

3 years ago

1.3.5

4 years ago

1.3.4

4 years ago

1.3.3

4 years ago

1.3.2

4 years ago

1.3.1

4 years ago

1.3.0

4 years ago

1.2.0

4 years ago

1.1.5

4 years ago

1.1.4

4 years ago

1.1.3

4 years ago

1.1.2

4 years ago

1.1.1

4 years ago

1.1.0

4 years ago

1.0.0

4 years ago

0.3.7

5 years ago

0.3.6

5 years ago

0.3.5

5 years ago

0.3.4

5 years ago

0.3.3

5 years ago

0.3.2

5 years ago

0.3.1

5 years ago

0.3.0

5 years ago

0.2.1

5 years ago

0.2.0

5 years ago

0.1.3

5 years ago

0.1.2

5 years ago

0.1.1

5 years ago

0.1.0

5 years ago