You can handle the date inputs in Formik forms using a date picker library called @mui/x-date-pickers, integrate it seamlessly with Formik’s state management, and add validation using the Yup library.
Here is the step-by-step guide to implement a date picker with formik using an MUI library like @mui/x-date-pickers.
Step 1: Setup a React project
Create a new React project using the command below:
npm create vite@latest date-app -- --template react
Go inside the date-app folder and install the necessary dependencies:
cd date-app npm install
Step 2: Install MUI, Formik, and Yup
Let’s install Formik, Yup (for validation), MUI, and a date picker library like @mui/x-date-pickers to work with this project.
npm install formik yup @mui/material @emotion/react @emotion/styled
Step 3: Installing @mui/x-date-pickers and date-fns@2.x
We need to install a compatible version of date-fns with @mui/x-date-pickers. For instance, if we are using @mui/x-date-pickers version 5.x, then we need to have date-fns v2.x installed in our system.
npm install @mui/x-date-pickers@latest date-fns@2.x
Now, open the vite.config.js file inside the project’s root and add some configuration.
// vite.config.js import { defineConfig } from 'vite' import react from '@vitejs/plugin-react' export default defineConfig({ plugins: [react()], optimizeDeps: { include: ['date-fns'] }, resolve: { alias: { 'date-fns/format': 'date-fns/esm/format', 'date-fns/parse': 'date-fns/esm/parse', 'date-fns/_lib/format/longFormatters': 'date-fns/esm/_lib/format/longFormatters' } } })
By including date-fns in the optimizeDeps and setting up the correct aliases, we help the Vite resolve the dependencies correctly.
Step 4: Create a reusable DatePicker component
Create a new file called DatePickerField.jsx component inside the src folder and add the code below:
// src/DatePickerField.jsx import { useField, useFormikContext } from "formik"; import { DatePicker } from "@mui/x-date-pickers/DatePicker"; import { TextField } from "@mui/material"; // eslint-disable-next-line react/prop-types const DatePickerField = ({ name, ...otherProps }) => { const { setFieldValue } = useFormikContext(); const [field, meta] = useField(name); const handleChange = (value) => { setFieldValue(name, value); }; const configDatePicker = { ...field, ...otherProps, fullWidth: true, InputLabelProps: { shrink: true }, onChange: handleChange, }; if (meta && meta.touched && meta.error) { configDatePicker.error = true; configDatePicker.helperText = meta.error; } return ( <DatePicker {...configDatePicker} renderInput={(params) => <TextField {...params} />} /> ); }; export default DatePickerField;
Step 5: Define a validation schema
Inside the src folder, create a new validation schema file called “validationSchema.js” and add the code below:
// src/validationSchema.js import * as Yup from 'yup'; export const validationSchema = Yup.object().shape({ username: Yup.string().required('Username is required'), email: Yup.string().email('Invalid email').required('Email is required'), dateOfBirth: Yup.date() .nullable() .required('Date of Birth is required') .max(new Date(), 'Date of Birth cannot be in the future'), });
Step 6: Create the Formik form
Inside the src folder, create a new file called FormComponent.jsx and add the code below:
// src/FormComponent.jsx import { Formik, Form, Field } from "formik"; import { TextField, Box, Button, Typography } from "@mui/material"; import DatePickerField from "./DatePickerField"; import { styled } from "@mui/system"; import { validationSchema } from "./validationSchema"; const StyledTextField = styled(TextField)` margin: 16px 0; `; const FormContainer = styled(Box)` display: flex; flex-direction: column; align-items: center; padding: 32px; border: 1px solid #e0e0e0; border-radius: 8px; box-shadow: 0px 3px 6px rgba(0, 0, 0, 0.1); `; const FormComponent = () => { return ( <Formik initialValues={{ username: "", email: "", dateOfBirth: null, // Ensure dateOfBirth is null, not a string }} validationSchema={validationSchema} onSubmit={(values) => { alert(JSON.stringify(values, null, 2)); }} > {({ errors, touched }) => ( <Form> <FormContainer> <Typography variant="h5" component="h1" marginBottom="24px"> Sign Up </Typography> <Field name="username" as={StyledTextField} label="Username" error={touched.username && Boolean(errors.username)} helperText={touched.username && errors.username} fullWidth /> <Field name="email" as={StyledTextField} label="Email" error={touched.email && Boolean(errors.email)} helperText={touched.email && errors.email} fullWidth /> <DatePickerField name="dateOfBirth" label="Date of Birth" /> <Button type="submit" variant="contained" color="primary" fullWidth sx={{ marginTop: "16px" }} > Submit </Button> </FormContainer> </Form> )} </Formik> ); }; export default FormComponent;
Step 7: Integrate everything into the main application file
Modify the App.jsx file to include the FormComponent.jsx component.
// src/App.jsx import FormComponent from "./FormComponent"; import { LocalizationProvider } from "@mui/x-date-pickers/LocalizationProvider"; import { AdapterDateFns } from "@mui/x-date-pickers/AdapterDateFns"; import { Container } from "@mui/material"; const App = () => { return ( <LocalizationProvider dateAdapter={AdapterDateFns}> <Container maxWidth="sm"> <FormComponent /> </Container> </LocalizationProvider> ); }; export default App;
And our src/main.jsx file looks like this:
// src/main.jsx import React from 'react' import ReactDOM from 'react-dom/client' import App from './App.jsx' ReactDOM.createRoot(document.getElementById('root')).render( <React.StrictMode> <App /> </React.StrictMode>, )
Step 8: Run your project
You can run the React.js project using the command below:
npm run dev
If you click on the Date of Birth text box, it will open a datepicker like this:
If you submit the form with valid values, it will display an alert with form values like this:
Conclusion
We created a datepicker setup that ensures that the date picker and form components are reusable and modular, making them easy to maintain and extend.
The DatePickerField component encapsulates the date picker logic, while the FormComponent manages the form structure and validation.
That’s all!