Cleiton Freitas
Cleiton Freitas

Reputation: 527

Problem autoFocus Autocomplete Material UI

I am not able to focus on the first element of my form which is an Autocomplete component of the Material UI.

When opening the modal, the focus is on the 'unit' element, as shown in the image below: It dont's work

I want the focus to be on the 'group' element, as shown below: It work

Here is the Sandbox link: https://codesandbox.io/s/awesome-bassi-zjp50?file=/src/MyForm.jsx:1422-1431

can anyone help me?

MyForm

import React from "react";
import { Formik, Form, Field } from "formik";
import * as Yup from "yup";
import { Grid } from "@material-ui/core";
import Input from "./components/Input";
import Autocomplete from "./components/Autocomplete";

const initialValues = {
  id: 0,
  group: {
    value: 0,
    label: ""
  },
  name: "",
  unit: {
    value: 0,
    label: ""
  }
};

const groupList = [
  {
    value: "1",
    label: "Seeds"
  },
  {
    value: "2",
    label: "Fertilizers"
  }
];

const unitList = [
  {
    value: "1",
    label: "kg"
  },
  {
    value: "2",
    label: "t"
  }
];

const validationSchema = Yup.object({
  group: Yup.object().shape({
    value: Yup.number().required().min(1).nullable()
  }),
  name: Yup.string().required().max(50),
  unit: Yup.object().shape({
    value: Yup.number().required().min(1).nullable()
  })
});

export default function MyForm() {
  function _onSubmit(fields, { props, setErrors, setSubmitting }) {
    console.log(fields);
  }

  return (
    <Formik
      enableReinitialize={true}
      initialValues={initialValues}
      validationSchema={validationSchema}
      onSubmit={_onSubmit}
    >
      {function Render({ errors, touched, isSubmitting, setFieldValue }) {
        return (
          <Form id="form">
            <Grid container direction="row">
              <Grid item xs={12}>
                <Field
                  name="group"
                  autoFocus
                  component={Autocomplete}
                  label="Group"
                  options={groupList}
                  disabled={isSubmitting}
                  textFieldProps={{
                    fullWidth: true,
                    margin: "dense",
                    variant: "outlined"
                  }}
                />
              </Grid>
              <Grid item xs={12}>
                <Field
                  name="name"
                  fullWidth
                  label="Name"
                  disabled={isSubmitting}
                  component={Input}
                />
              </Grid>
              <Grid item xs={12}>
                <Field
                  name="unit"
                  component={Autocomplete}
                  label="Unit"
                  options={unitList}
                  disabled={isSubmitting}
                  textFieldProps={{
                    fullWidth: true,
                    margin: "dense",
                    variant: "outlined"
                  }}
                />
              </Grid>
            </Grid>
          </Form>
        );
      }}
    </Formik>
  );
}

Popup Modal

import React from "react";
import {
  Dialog,
  DialogTitle,
  DialogContent,
  makeStyles,
  Typography,
  Divider,
  DialogActions,
  Button,
  Grid,
  Box
} from "@material-ui/core";

const useStyles = makeStyles((theme) => ({
  dialogWrapper: {
    padding: theme.spacing(2),
    position: "absolute",
    top: theme.spacing(5)
  },
  dialogTitle: {
    paddingRight: 0
  },
  button: {
    margin: theme.spacing(0.5),
    textTransform: "none"
  },
  buttonsContainer: {
    display: "flex",
    flex: "0 0 auto",
    justifyContent: "flex-end",
    width: "100%",
    height: "100%"
  },
  buttons: {
    display: "flex"
  },
  loadingIcon: {
    display: "flex",
    alignItems: "center",
    justifyContent: "center",
    marginRight: theme.spacing(1)
  }
}));

function Popup(props) {
  const classes = useStyles();
  const { title, children, openPopup, setOpenPopup, ...rest } = props;

  return (
    <Dialog
      {...rest}
      open={openPopup}
      maxWidth="sm"
      classes={{ paper: classes.dialogWrapper }}
    >
      <DialogTitle dividers="true" className={classes.dialogTitle}>
        <div style={{ display: "flex" }}>
          <Typography variant="h4" component="div" style={{ flexGrow: 1 }}>
            {title}
          </Typography>
        </div>
      </DialogTitle>
      <Divider />
      <DialogContent {...rest} direction="row">
        {children}
      </DialogContent>
      <DialogActions {...rest}>
        <Grid {...rest} container className={classes.buttonsContainer}>
          <Box {...rest} className={classes.buttons}>
            <Button
              className={classes.button}
              variant="contained"
              color="primary"
              type="submit"
              form="form"
              {...rest}
            >
              Save
            </Button>
            <Button
              className={classes.button}
              color="default"
              fullWidth
              onClick={() => {
                setOpenPopup(false);
              }}
              {...rest}
            >
              Cancel
            </Button>
          </Box>
        </Grid>
      </DialogActions>
    </Dialog>
  );
}

export default Popup;

Autocomplete

import React from "react";
import { FieldProps, getIn } from "formik";
import { TextField, CircularProgress } from "@material-ui/core";
import MuiAutocomplete, {
  createFilterOptions
} from "@material-ui/lab/Autocomplete";

const NewAutocomplete: React.FC<
  FieldProps & {
    label?: string,
    options: Array<{ label: string, value: number }>
  }
> = ({ textFieldProps, field, form, label, options, isLoading, ...props }) => {
  const filterOptions = createFilterOptions({
    matchFrom: "start",
    limit: 500
  });
  const errorText =
    getIn(form.touched, field.name) && getIn(form.errors, field.name);

  const valueInit = [
    {
      value: 0,
      label: ""
    }
  ];

  return (
    <MuiAutocomplete
      {...props}
      {...field}
      filterOptions={filterOptions}
      options={[...valueInit, ...options]}
      getOptionLabel={(option) => (option ? option.label : "")}
      getOptionSelected={(option, value) => option.value === value?.value}
      style={{ width: 300 }}
      loading={isLoading}
      value={field.value}
      onChange={(e, value) => {
        form.setFieldValue(field.name, value);
      }}
      renderInput={(props) => (
        <>
          <TextField
            {...props}
            {...textFieldProps}
            label={label}
            helperText={errorText?.value || errorText}
            error={!!errorText}
            autoFocus
            InputProps={{
              ...props.InputProps,
              endAdornment: (
                <React.Fragment>
                  {isLoading ? (
                    <CircularProgress color="primary" size={20} />
                  ) : null}
                  {props.InputProps.endAdornment}
                </React.Fragment>
              )
            }}
          />
        </>
      )}
    />
  );
};

export default NewAutocomplete;

Thanks for your help!

Upvotes: 6

Views: 8977

Answers (1)

v1s10n_4
v1s10n_4

Reputation: 697

You're actually setting autoFocus to true on TextField by default inside your NewAutocomplete definition (src/components/Autocomplete.jsx:50 in your sandbox).

Once that line removed, you can then add autoFocus: true to textFieldProps value of your first Field in MyForm component.

See codesandbox example

Upvotes: 4

Related Questions