Skip to content

Import

import { useFieldProps } from '@dnb/eufemia/extensions/forms'
// Use useFieldProps

Description

The useFieldProps hook standardize handling of the value flow for a single consumer component representing one data point. It holds error state, hides it while the field is in focus, connects to surrounding DataContext (if present) and other things that all field or value components needs to do. By implementing custom field or value components and passing the received properties through useFieldProps, all these features work the same way as other field or value components, and you only need to implement the specific unique features of that component.

How to use

import { useFieldProps } from '@dnb/eufemia/extensions/forms'
const MyFieldComponent = (props) => {
const { value, ...rest } = useFieldProps(props)
return <Input value={value} {...rest} />
}
render(<MyFieldComponent path="/dataSelector" />)

Advanced usage:

import { Form, useFieldProps } from '@dnb/eufemia/extensions/forms'
const MyFieldComponent = (props) => {
const translations = Form.useTranslation().MyField
const errorMessages = React.useMemo(() => {
return {
// My default error messages
'Field.errorRequired': translations.myErrorMessage,
'MyCustom.message': translations.myCustomErrorMessage,
...props.errorMessages,
}
}, [props.errorMessages])
const preparedProps = {
errorMessages,
// Your component props
...props,
}
const {
// Return Parameters:
value,
handleChange,
handleFocus,
handleBlur,
htmlAttributes,
// Component Properties
...rest
} = useFieldProps(preparedProps)
return (
<Input
value={value}
onChange={handleChange}
onFocus={handleFocus}
onBlur={handleBlur}
{...htmlAttributes}
{...rest}
/>
)
}

Internal Properties

All properties are optional and can be used as needed. These properties can be provided as part of your component properties.

  • value the input value (string).
  • emptyValue defines what value is considered to be empty. Defaults to undefined. But an empty string is also validated when required is true.
  • path the JSON pointer that defines the entry name/key in the data structure.
  • itemPath similar to path, but is used when run inside the Iterate context.

Validation

  • required if true, it will call validateRequired for validation.
  • schema or pattern for JSON schema validation powered by ajv.
  • onChangeValidator your custom validation function. It will run on every keystroke. Can be an async function. Use it together with debounceAsync.
  • onBlurValidator your custom validation function. It will run on a handleBlur() call. Use it over onChangeValidator for validations with side-effects. Can be an async function.
  • validateRequired does allow you to provide a custom logic for how the required property should validate. See example down below.
  • validateInitially in order to show an error without a change and blur event. Used for rare cases.
  • validateUnchanged in order to validate without a change and blur event. Used for rare cases.
  • validateContinuously in order to validate without a focus event beforehand. Used for rare cases.

Validators

  • exportValidators object with your validators you want to export. More info down below.

For more advanced use cases, you can export your custom Field validators with exportValidators. They are then available (as validators in object of the second validator parameter) to be used in the validator.

When an array is returned from the validator, it will be used to only call these validators (in the order they are returned). If no array is returned, the internal validator will be called in addition.

const MyField = (props) => {
const myInternalValidator = useCallback(() => {
if (value === 'fail now') {
return new Error('Internal validation error')
}
}, [])
return (
<Field.String exportValidators={{ myInternalValidator }} {...props} />
)
}
const myValidator = (value, { validators: { myInternalValidator } }) => {
if (value === 'fail') {
return new Error('My error')
}
return [myInternalValidator] // optional
}
render(<MyField onBlurValidator={myValidator} />)

Error

  • error like new Error() or new FormError() that includes a message to display. More info down below.
  • errorMessages object with your custom messages or translation keys, such as 'Field.errorRequired'. More info down below.

Return Parameters

It returns all of the given component properties, in addition to these:

  • value the output value.
  • id creates a memorized id.
  • dataContext the internal shared data context.
  • error the error object, in case an error is invoked. Will skip returning the error object, if the hook is used in a nested FieldBlock.
  • hasError will return true in case of an error, even if the hook is nested in a FieldBlock.
  • htmlAttributes object that include needed HTML (e.g. aria-_ or data-_) attributes, ready to be spread on form elements. It includes in addition internal aria attributes such as aria-invalid, aria-required and aria-describedby.
  • isChanged returns true if the value has changed with e.g. handleChange.
  • setHasFocus accepts a boolean as value. When called, it will update the internal logic - for event handling and validation. Will re-render the React Hook and its outer component.
  • onFocus event handler to assign to a form element.
  • onBlur event handler to assign to a form element.
  • onChange event handler to assign to a form element. When an async function is used, it will set the fieldState to pending. The corresponding FieldBlock will show an indicator on the field label.

Custom validateRequired

const validateRequired = (value, { emptyValue, required, isChanged }) => {
if (required && value === emptyValue) {
return new FormError('Field.errorRequired')
}
}
const { error, hasError } = useFieldProps({
value: undefined,
required: true,
validateInitially: true,
validateRequired,
errorMessages: {
'Field.errorRequired': 'Show this when "required" fails.',
},
})

Validation order

During validation, the different APIs do have a prioritization order and will stop processing further when they match:

  1. required property
  2. schema property (including pattern)
  3. onChangeValidator property
  4. onBlurValidator property

Error handling

Validation and error-handling are tightly coupled together. When a validation fails, you may use the error-object to handle and show the failures/statuses:

render(
<Field.String
label="Label"
error={new Error('This is what is wrong...')}
/>,
)

But when you handle errors via useFieldProps, you may rather provide an object with messages, which will be used to display the error:

const { error, hasError } = useFieldProps({
required: true,
errorMessages: {
'Field.errorRequired': 'Show this when "required" fails!',
},
...componentProps,
})

To re-use existing errorMessages, you can use the FormError constructor as well:

import { FormError } from '@dnb/eufemia/extensions/forms'
// Will show the message from the errorMessages
new FormError('Field.errorRequired')

In order to invoke an error without a change and blur event, you can use validateInitially:

const { error, hasError } = useFieldProps({
value: undefined,
required: true,
validateInitially: true,
errorMessages: {
'Field.errorRequired': 'Show this when "required" fails!',
},
})

Event handlers

  • handleFocus() to call the onFocus event.

  • handleBlur() to call the onBlur event.

  • handleChange(value) to call the onChange event. Will update/change the internal value and re-render the React Hook, so will the outer component too.

handleChange(value, (additionalArgs = null))

When additionalArgs is provided, it will be passed to the onChange, onFocus or onBlur events as the second argument. It will be merged with the internal additionalArgs, which includes props (including all of the given properties), getValueByPath and getSourceValue.

  • updateValue(value) to update/change the internal value, without calling any events.

  • forceUpdate() to re-render the React Hook along with the outer component.

Value transformers

The transformers are hooks to transform the value on different stages.

They should return a transformed value: (value) => value

  • toInput transforms the value before it is returned. This applies whether the original source of the value is the value property or the data context.

  • fromInput transforms the value given by handleChange before it is used in the further process flow. Use it to destruct the value from the original event object.

  • toEvent transforms the internal value before it gets returned by even callbacks such as onChange, onFocus and onBlur. The second parameter returns the event type: onChange, onFocus, onBlur or onBlurValidator.

  • fromExternal transforms the provided value property before any other operations are performed.

  • transformValue transforms the value given by handleChange after fromInput and before updateValue and toEvent. The second parameter returns the current value.

  • provideAdditionalArgs provide a function that can be called by the field to provide additional parameters, so events (onFocus, onBlur and onChange) and transformers (transformOut) get an additional parameter when transforming the value.

In addition there are field value transformers which should be used outside of the field component (by the field consumer):

  • transformIn transforms the value before it's displayed in the field (e.g. input).

  • transformOut transforms the value before it gets forwarded to the form data object or returned as the onChange value parameter.