formik icon indicating copy to clipboard operation
formik copied to clipboard

Add a way to add disabled prop to all Fields or inputs.

Open tsiq-jeremy opened this issue 6 years ago • 15 comments

🚀 Feature request

I want to be able to make all Fields/inputs in a form be disabled through the top level Form component. Our goal is that while submitting, we disable the form so the user can not change the fields during this time.

Current Behavior

Currently you would need to pass disabled prop to every input like this:

<Form>
  <Field id="a" name="a" type="text" disabled={isSubmitting}/>
  <Field id="b" name="b" type="text" disabled={isSubmitting}/>
</Form>

Desired Behavior

Instead it would be nice to pass the disabled prop just to the Form and have it be passed down to the Field's.

<Form disabled={isSubmitting}>
  <Field id="a" name="a" type="text"/>
  <Field id="b" name="b" type="text"/>
</Form>

Who does this impact? Who is this for?

This is helpful for anyone who has to regularly prevent users from filling out fields or wanting to toggle a form to be read only.

Additional context

Docs on the disabled attribute. https://developer.mozilla.org/en-US/docs/Mozilla/Tech/XUL/Attribute/disabled

I have not done research on how this works with other types of inputs such as checkboxes or select.

tsiq-jeremy avatar Jan 10 '19 18:01 tsiq-jeremy

AFAIK <form disabled> is invalid. This would be quite magical. Need to think about it more.

jaredpalmer avatar Feb 06 '19 19:02 jaredpalmer

This can be implemented in user land by building a custom <Form> and using the DOM. The tricky thing is that not all Fields are inputs and not all users use <Field>.

jaredpalmer avatar Feb 06 '19 19:02 jaredpalmer

For a project we built a custom <Form> component that under the hood uses react context to pass the disabled prop to all of the input components. As you mentioned, probably the trickiest parts is normalizing all of the input components so that they take the same disabled prop. For instance react-select takes as prop isDisabled so you would need a mapping that accounts for this.

tsiq-jeremy avatar Feb 07 '19 15:02 tsiq-jeremy

Could disabled={isSubmitting} be the default behavior of <Field>?

lambert-velir avatar May 08 '19 17:05 lambert-velir

The tricky thing is that not all Fields are inputs and not all users use <Field>.

cc @lambert-velir

Andreyco avatar May 08 '19 18:05 Andreyco

disabled is a valid attribute for all form elements, input, textarea, select, which is what the component prop of <Field> expects. https://jaredpalmer.com/formik/docs/api/field#component

If the user passes a custom React component, I would think they would either pass disabled through to the underlying input, etc, or handle it the same way.

lambert-velir avatar May 08 '19 18:05 lambert-velir

Why not using a fieldset at the top level? You can disabled all the fields inside doing just <fieldset disabled>

https://developer.mozilla.org/en-US/docs/Web/HTML/Element/fieldset#Attributes

gtournie avatar Jun 18 '19 01:06 gtournie

Thanks @gtournie. For anyone else using antd, the inputs won't look disabled, so you might need a bit of CSS, eg this quick hack:

fieldset:disabled input {
  background: #ddd;
  cursor: wait;
}

seanf avatar Jul 02 '19 03:07 seanf

Here's what I'm doing:

function FormInput(props) {
  return (
    <Field name={props.name}>
      {({ field, form })=> (
        <Input
          {...field}
          disabled={form.isSubmitting || props.disabled}
          error={
            form.touched[field.name]
              ? form.errors[field.name]
              : null
          }
        />
      )}
    </Field>
  );
}

hnordt avatar Jul 24 '19 02:07 hnordt

For material-ui form items, I have created a custom form component with an additional context. Form gets a isDisabled prop and passes it to the context. Each form item inside the form consumes this context and they can also use their own disabled prop. This may not be the perfect solution. But it is simple and maintainable :)

onderonur avatar Oct 21 '19 07:10 onderonur

const FormikDisabler = ({ disabled }: { disabled?: boolean }) => {
  const { setSubmitting } = useFormikContext();
  useEffect(() => {
    if (disabled) {
      setSubmitting(true);
    } else {
      setSubmitting(false);
    }
  }, [disabled, setSubmitting]);
  return null;
};

usage:

      <Formik ...>
        <Form>
          <FormikDisabler disabled />
           ...
        </Form>
      </Formik>

nitedani avatar Mar 25 '21 14:03 nitedani

I think a plugin api would be the right way to add functionality like this. #3109

johnrom avatar Mar 25 '21 15:03 johnrom

This issue is stale because it has been open 30 days with no activity. Remove stale label or comment or this will be closed in 60 days

github-actions[bot] avatar Sep 18 '21 00:09 github-actions[bot]

@gtournie thanks

Why not using a fieldset at the top level? You can disabled all the fields inside doing just <fieldset disabled>

https://developer.mozilla.org/en-US/docs/Web/HTML/Element/fieldset#Attributes

VladBrok avatar Jun 01 '23 05:06 VladBrok

@gtournie <fieldset disabled> might be a good solution but it doesn't work as expected with all MUI form components. Still waiting for a solution

ZvozdaB avatar Mar 15 '24 10:03 ZvozdaB