jaredpalmer / formik

Build forms in React, without the tears 😭
https://formik.org
Apache License 2.0
33.9k stars 2.79k forks source link

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

Open tsiq-jeremy opened 5 years ago

tsiq-jeremy commented 5 years ago

🚀 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.

jaredpalmer commented 5 years ago

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

jaredpalmer commented 5 years ago

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>.

tsiq-jeremy commented 5 years ago

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.

lambert-velir commented 5 years ago

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

Andreyco commented 5 years ago

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

cc @lambert-velir

lambert-velir commented 5 years ago

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.

gtournie commented 5 years ago

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

seanf commented 5 years ago

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;
}
hnordt commented 5 years ago

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>
  );
}
onderonur commented 4 years ago

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 :)

nitedani commented 3 years ago
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>
johnrom commented 3 years ago

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

github-actions[bot] commented 3 years ago

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

VladBrok commented 1 year ago

@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

ZvozdaB commented 6 months ago

@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