form-input-fields
Version:
A customizable form field components built with TypeScript
1,698 lines (1,434 loc) • 53 kB
Markdown
# Form Fields Components
A collection of Material-UI form field components with Formik integration.
More control in the progress of development.
## Installation
### Prerequisites
Before installing the form-fields package, make sure you have the following peer dependencies installed in your project:
- React 16.8.0 or later
- React DOM 16.8.0 or later
- Material-UI (MUI) 5.0.0 or later
- Formik 2.0.0 or later
- @mui/x-date-pickers 6.0.0 or later
- dayjs 1.11.0 or later
### Using npm
```bash
npm install form-fields @mui/material @emotion/react @emotion/styled formik @mui/x-date-pickers dayjs
```
### Using yarn
```bash
yarn add @your-org/form-fields @mui/material @emotion/react @emotion/styled formik @mui/x-date-pickers dayjs
```
### Using pnpm
```bash
pnpm add form-input-fields @mui/material @emotion/react @emotion/styled formik @mui/x-date-pickers dayjs
```
### Peer Dependencies
Make sure your project includes these peer dependencies:
```json
{
"devDependencies": {
"react": "^16.8.0 || ^17.0.0 || ^18.0.0",
"react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0",
"@mui/material": "^5.0.0",
"@emotion/react": "^11.0.0",
"@emotion/styled": "^11.0.0",
"formik": "^2.0.0",
"@mui/x-date-pickers": "^6.0.0",
"dayjs": "^1.11.0"
}
}
```
### TypeScript
This package includes TypeScript type definitions. No additional type packages are needed.
### Browser Support
The form fields support all modern browsers including:
- Chrome (latest 2 versions)
- Firefox (latest 2 versions)
- Safari (latest 2 versions)
- Edge (latest 2 versions)
For Internet Explorer 11 support, you'll need to include polyfills. See [Browser Support](#browser-support) for more details.
### Next Steps
After installation, you can import and use the components in your application:
```tsx
import { FormTextField, FormDateField, FormMaskField, FormSwitch } from 'form-input-fields';
```
### Troubleshooting
If you encounter any issues during installation, try the following:
1. Clear your package manager's cache:
```bash
npm cache clean --force
# or
yarn cache clean
# or
pnpm store prune
```
2. Delete `node_modules` and `package-lock.json` (or `yarn.lock`/`pnpm-lock.yaml`)
3. Reinstall dependencies:
```bash
npm install
# or
yarn install
# or
pnpm install
```
If you're still experiencing issues, please reach me at vladimir.vorobiev@gmail.com with details about your environment and the error message you're seeing.
## Table of Contents
- [FormTextField](#formtextfield)
- [Features](#features)
- [Basic Usage](#basic-usage)
- [Props](#props)
- [Examples](#examples)
- [Basic Text Input](#basic-text-input)
- [Text Field with Formik](#text-field-with-formik)
- [Custom Validation](#custom-validation)
- [FormDropDownField](#formdropdownfield)
- [Features](#features-4)
- [Basic Usage](#basic-usage-4)
- [Props](#props-4)
- [Examples](#examples-4)
- [Basic Dropdown](#basic-dropdown)
- [Dropdown with Default Selection](#dropdown-with-default-selection)
- [Required Dropdown with Validation](#required-dropdown-with-validation)
- [FormDateField](#formdatefield)
- [Features](#features)
- [Available Date Formats](#available-date-formats)
- [Importing Date Constants](#importing-date-constants)
- [Usage with Formik](#usage-with-formik)
- [Props](#props)
- [Examples](#examples)
- [Basic Date Input](#basic-date-input)
- [Date with Validation](#date-with-validation)
- [Appointment Scheduler](#appointment-scheduler)
- [Read-Only Date Display](#read-only-date-display)
- [Custom Change Handler](#custom-change-handler)
- [FormMaskField](#formmaskfield)
- [Features](#features-1)
- [Installation](#installation)
- [Basic Usage](#basic-usage)
- [Available Masks](#available-masks)
- [Props](#props-1)
- [Examples](#examples-1)
- [Phone Number](#phone-number)
- [Date Input](#date-input)
- [Product Code (Uppercase)](#product-code-uppercase)
- [Credit Card](#credit-card)
- [Custom Change Handler](#custom-change-handler-1)
- [Show Mask Pattern](#show-mask-pattern)
- [Show Placeholder](#show-placeholder)
- [Custom Mask with Validation](#custom-mask-with-validation)
- [FormCheckboxField](#formcheckboxfield)
- [Features](#features-2)
- [Basic Usage](#basic-usage-1)
- [Props](#props-2)
- [Examples](#examples-2)
- [Basic Checkbox](#basic-checkbox)
- [Checkbox with Formik](#checkbox-with-formik)
- [Custom Styled Checkbox](#custom-styled-checkbox)
- [FormSwitch](#formswitch)
- [Features](#features-5)
- [Basic Usage](#basic-usage-5)
- [Props](#props-5)
- [Examples](#examples-5)
- [Basic Switch](#basic-switch)
- [Switch with Formik](#switch-with-formik)
- [Custom Styled Switch](#custom-styled-switch)
- [FormDateTextField](#formdatetextfield)
- [Features](#features-3)
- [Available Date Formats](#available-date-formats-1)
- [Basic Usage](#basic-usage-3)
- [Props](#props-3)
- [Examples](#examples-3)
- [Basic Date Text Input](#basic-date-text-input)
- [Date Text Field with Formik](#date-text-field-with-formik)
- [Custom Date Format](#custom-date-format)
- [History](#history)
---
## FormTextField
A versatile text input field component that integrates Material-UI's TextField with Formik form handling.
### Features
- **Seamless Formik Integration**: Automatically handles form state, validation, and error messages
- **Material-UI Styling**: Consistent look and feel with Material Design
- **TypeScript Support**: Fully typed component with proper type definitions
- **Flexible Props**: Supports all standard TextField props from Material-UI
- **Error Handling**: Built-in error state management with Formik
- **Responsive Design**: Works well across different screen sizes
### Basic Usage
```tsx
import { Formik, Field } from 'formik';
import { FormTextField } from 'form-fields';
<Formik
initialValues={{ username: '' }}
onSubmit={(values) => console.log(values)}
>
<Field
component={FormTextField}
name="username"
label="Username"
placeholder="Enter your username"
/>
</Formik>
```
### Props
The FormTextField component accepts all props from `FormTextFieldProps`, `FieldProps` (Formik), and Material-UI's `TextFieldProps`.
#### FormTextFieldProps Interface
| Prop | Type | Default | Description |
|------------|------------|---------|-----------------------------------------------|
| `onChange` | `function` | - | Custom change handler that overrides Formik's |
| `onBlur` | `function` | - | Custom blur handler that overrides Formik's |
| `variant` | `'standard' | 'outlined' | 'filled'` | 'standard' | The variant of the MUI TextField. |
#### Common Props (from FieldProps & TextFieldProps)
| Prop | Type | Required | Description |
|--------------|------------------|----------|-----------------------------------------------|
| `name` | `string` | Yes | Field name in Formik values |
| `label` | `string` | No | Field label |
| `helperText` | `string` | No | Custom helper text |
| `error` | `boolean` | No | Error state (auto-managed by Formik) |
| `disabled` | `boolean` | No | Disabled state |
| `required` | `boolean` | No | Required field indicator |
| `type` | `string` | 'text' | Input type (text, email, password, etc.) |
| Other | `TextFieldProps` | No | All Material-UI TextField props are supported |
### Examples
#### Basic Text Input
```tsx
<Field
component={FormTextField}
name="username"
label="Username"
placeholder="Enter your username"
fullWidth
margin="normal"
variant="outlined" // <-- Example with outlined variant
/>
```
#### Text Field with Formik
```tsx
<Formik
initialValues={{ email: '' }}
validate={values => {
const errors = {};
if (!values.email) {
errors.email = 'Required';
} else if (!/^[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,}$/i.test(values.email)) {
errors.email = 'Invalid email address';
}
return errors;
}}
onSubmit={(values) => console.log(values)}
>
{({ errors, touched }) => (
<Field
component={FormTextField}
name="email"
label="Email"
type="email"
error={touched.email && Boolean(errors.email)}
helperText={touched.email && errors.email}
required
/>
)}
</Formik>
```
#### Custom Validation
```tsx
<Field
component={FormTextField}
name="password"
label="Password"
type="password"
inputProps={{
minLength: 8,
pattern: "(?=.*\d)(?=.*[a-z])(?=.*[A-Z]).{8,}"
}}
helperText="Must contain at least 8 characters, including uppercase, lowercase, and numbers"
required
/>
```
---
## FormDropDownField
A customizable dropdown/select component that integrates Material-UI's Select with Formik form handling.
### Features
- **Seamless Formik Integration**: Automatically handles form state, validation, and error messages
- **Material-UI Styling**: Consistent look and feel with Material Design
- **TypeScript Support**: Fully typed component with proper type definitions
- **Flexible Data Binding**: Works with array of objects with `id` and `description` properties
- **Optional Default Selection**: Add a default "Select" option with customizable text
- **Form Validation**: Built-in error state management with Formik
- **Responsive Design**: Works well across different screen sizes
### Basic Usage
```tsx
import { Formik, Field } from 'formik';
import { FormDropDownField } from 'form-input-fields';
const items = [
{ id: '1', description: 'Option 1' },
{ id: '2', description: 'Option 2' },
{ id: '3', description: 'Option 3' },
];
<Formik
initialValues={{ category: '' }}
onSubmit={(values) => console.log(values)}
>
<Field
component={FormDropDownField}
name="category"
label="Category"
items={items}
addInputSelect={true}
/>
</Formik>
```
### Props
The FormDropDownField component accepts all props from `FormDropDownFieldProps`, `FieldProps` (Formik), and Material-UI's `TextFieldProps` (with some exceptions).
#### FormDropDownFieldProps Interface
| Prop | Type | Default | Description |
|------|------|---------|-------------|
| `items` | `Array<{ id: string | number; description: string }>` | `[]` | Array of items to display in the dropdown |
| `addInputSelect` | `boolean` | `false` | Whether to show a default "Select" option as the first item |
| `selectText` | `string` | `'Select'` | Text to display for the default "Select" option |
| `required` | `boolean` | `false` | Whether the field is required |
| `disabled` | `boolean` | `false` | Whether the field is disabled |
| `className` | `string` | - | Custom class name for the root element |
| `helperText` | `string` | - | Helper text to display below the field |
| `error` | `boolean` | - | Error state of the field (overrides Formik error state) |
| `onChange` | `(value: any) => void` | - | Custom change handler |
| `onBlur` | `(event: React.FocusEvent<HTMLInputElement>) => void` | - | Custom blur handler |
| `variant` | `'standard' | 'outlined' | 'filled'` | 'standard' | The variant of the MUI TextField. |
### Examples
#### Basic Dropdown
```tsx
const items = [
{ id: 'us', description: 'United States' },
{ id: 'ca', description: 'Canada' },
{ id: 'uk', description: 'United Kingdom' },
];
<Field
component={FormDropDownField}
name="country"
label="Country"
items={items}
fullWidth
variant="outlined" // <-- Example with outlined variant
/>
```
#### Dropdown with Default Selection
```tsx
<Field
component={FormDropDownField}
name="category"
label="Category"
items={categories}
addInputSelect={true}
selectText="Select a category"
helperText="Please select a category from the list"
/>
```
#### Required Dropdown with Validation
```tsx
<Formik
initialValues={{ department: '' }}
validationSchema={Yup.object({
department: Yup.string().required('Department is required'),
})}
onSubmit={(values) => console.log(values)}
>
{({ errors, touched }) => (
<Form>
<Field
component={FormDropDownField}
name="department"
label="Department"
items={departments}
addInputSelect={true}
required
error={touched.department && Boolean(errors.department)}
helperText={touched.department && errors.department}
/>
<Button type="submit" variant="contained" color="primary">
Submit
</Button>
</Form>
)}
</Formik>
```
---
## FormDateField
A date input field component with Material-UI and Formik integration, powered by MUI X Date Pickers.
### Features
- **Material-UI Integration**: Consistent styling with other form components
- **Formik Integration**: Seamless form state management with error handling
- **Day.js Support**: Lightweight date library for date manipulation
- **Custom Date Formatting**: Flexible date display formats
- **Date Validation**: Built-in min/max date validation
- **Read-Only Support**: Can be configured as read-only
- **TypeScript Support**: Full type safety with exported interfaces
- **Helper Text Display**: Show date format or custom helper text
- **Today Button**: Optional today button in date picker
### Available Date Formats
The component uses predefined date format constants from `date.ts`:
#### FORM_DATE_FORMAT
```typescript
export const FORM_DATE_FORMAT = {
short: "YYYY-MM-DD",
long: "MM/DD/YYYY hh:mm A",
custom: "DD MMMM YYYY hh:mm A",
};
```
#### DATE_PICKER_DATE_FORMAT
```typescript
export const DATE_PICKER_DATE_FORMAT = {
short: "DD/MM/YYYY",
};
```
#### DATE_PICKER_MONTH_YEAR_FORMAT
```typescript
export const DATE_PICKER_MONTH_YEAR_FORMAT = {
short: "MM/YYYY",
long: "MMMM YYYY",
};
```
### Importing Date Constants
```tsx
import {
FORM_DATE_FORMAT,
DATE_PICKER_DATE_FORMAT,
DATE_PICKER_MONTH_YEAR_FORMAT
} from "form-input-mask-field/date";
// Use predefined formats
<Field
component={FormDateField}
name="birthDate"
format={FORM_DATE_FORMAT.short} // 'YYYY-MM-DD'
/>
// Or use custom format
<Field
component={FormDateField}
name="eventDate"
format="DD/MM/YYYY HH:mm" // Custom format
/>
```
### Usage with Formik
```tsx
import { Formik, Field } from "formik";
import { FormDateField, FormDateFieldProps } from "form-input-mask-field";
import { FORM_DATE_FORMAT } from "form-input-mask-field/date";
import dayjs from "dayjs";
<Formik
initialValues={{ birthDate: null, appointmentDate: null }}
onSubmit={(values) => console.log(values)}
>
{/* Basic usage */}
<Field
component={FormDateField}
name="birthDate"
label="Birth Date"
format={FORM_DATE_FORMAT.short}
/>
{/* Advanced usage with validation */}
<Field
component={FormDateField}
name="appointmentDate"
label="Appointment Date"
format="DD/MM/YYYY"
minDate={dayjs()}
disablePast={true}
showTodayButton={true}
showDateFormat={true}
onChange={(value, context) => {
console.log("Selected date:", value);
console.log("Formatted value:", context.formattedValue);
}}
/>
</Formik>;
```
### Props
The FormDateField component accepts all props from `FormDateFieldProps`, `FieldProps`, and `TextFieldProps`.
#### FormDateFieldProps Interface
| Prop | Type | Default | Description |
| ----------------- | ---------- | ------------------------ | --------------------------------------------- |
| `format` | `string` | `FORM_DATE_FORMAT.short` | Date format string using dayjs format tokens |
| `minDate` | `Dayjs` | - | Minimum selectable date |
| `maxDate` | `Dayjs` | - | Maximum selectable date |
| `disablePast` | `boolean` | `false` | Disable past dates |
| `disableFuture` | `boolean` | `false` | Disable future dates |
| `showTodayButton` | `boolean` | `false` | Show today button in the picker |
| `readOnly` | `boolean` | `false` | Make the field read-only |
| `showDateFormat` | `boolean` | `false` | Show the date format as helper text |
| `onChange` | `function` | - | Custom change handler with additional context |
#### Common Props (from FieldProps & TextFieldProps)
| Prop | Type | Required | Description |
| ------------ | ---------------- | -------- | --------------------------------------------- |
| `name` | `string` | Yes | Field name in Formik values |
| `label` | `string` | No | Field label |
| `helperText` | `string` | No | Custom helper text |
| `error` | `boolean` | No | Error state |
| `disabled` | `boolean` | No | Disabled state |
| Other | `TextFieldProps` | No | All Material-UI TextField props are supported |
### Examples
#### Basic Date Input
```tsx
<Field
component={FormDateField}
name="birthDate"
label="Birth Date"
format="DD/MM/YYYY"
/>
```
#### Date with Validation
```tsx
<Field
component={FormDateField}
name="startDate"
label="Start Date"
minDate={dayjs()}
disablePast={true}
showDateFormat={true}
helperText="Select a future date"
/>
```
#### Appointment Scheduler
```tsx
<Field
component={FormDateField}
name="appointmentDate"
label="Appointment Date"
format="DD MMMM YYYY"
minDate={dayjs().add(1, "day")}
maxDate={dayjs().add(3, "month")}
showTodayButton={true}
showDateFormat={true}
/>
```
#### Read-Only Date Display
```tsx
<Field
component={FormDateField}
name="createdDate"
label="Created Date"
format="DD/MM/YYYY HH:mm"
readOnly={true}
/>
```
#### Custom Change Handler
```tsx
<Field
component={FormDateField}
name="eventDate"
label="Event Date"
format="YYYY-MM-DD"
onChange={(value, context) => {
console.log("Selected date:", value);
console.log("Formatted value:", context.formattedValue);
console.log("Validation error:", context.validationError);
// Custom logic here
if (value && value.day() === 0) {
alert("Events cannot be scheduled on Sundays");
}
}}
/>
```
#### Date Range (Start/End Dates)
```tsx
<Field
component={FormDateField}
name="startDate"
label="Start Date"
format="DD/MM/YYYY"
maxDate={values.endDate ? dayjs(values.endDate) : undefined}
/>
<Field
component={FormDateField}
name="endDate"
label="End Date"
format="DD/MM/YYYY"
minDate={values.startDate ? dayjs(values.startDate) : undefined}
/>
```
## FormCheckboxField
A customizable checkbox component with Material-UI and Formik integration, providing consistent styling and behavior across your application.
### Features
- **Material-UI Integration**: Consistent styling with Material-UI's design system
- **Formik Integration**: Seamless form state management with error handling
- **Custom Styling**: Easy customization through Material-UI's styling system
- **TypeScript Support**: Full type safety with exported interfaces
- **Accessibility**: Built with accessibility in mind, following WAI-ARIA guidelines
- **Responsive Design**: Works well on all screen sizes
### Basic Usage
```tsx
import { Formik, Field } from 'formik';
import { FormCheckboxField } from 'form-input-mask-field';
// Basic usage
<FormCheckboxField
id="terms"
label="I agree to the terms and conditions"
checked={false}
onChange={(e) => console.log('Checked:', e.target.checked)}
/>
// With Formik
<Formik
initialValues={{ termsAccepted: false }}
onSubmit={(values) => console.log(values)}
>
{({ values }) => (
<Field
name="termsAccepted"
component={({ field, form }) => (
<FormCheckboxField
{...field}
label="I agree to the terms and conditions"
checked={field.value}
onChange={(e) => {
form.setFieldValue(field.name, e.target.checked);
}}
/>
)}
/>
)}
</Formik>
```
### Props
The FormCheckboxField component accepts all props from `FormCheckboxFieldProps` and Material-UI's `CheckboxProps`.
#### FormCheckboxFieldProps Interface
| Prop | Type | Default | Description |
| -------------- | --------- | ------- | ------------------------------------------------ |
| `id` | `string` | - | Unique identifier for the checkbox |
| `label` | `string` | - | Label text displayed next to the checkbox |
| `checked` | `boolean` | `false` | Whether the checkbox is checked |
| `onChange` | `function`| - | Callback when checkbox state changes |
| `disabled` | `boolean` | `false` | Disable the checkbox |
| `required` | `boolean` | `false` | Mark the field as required |
| `color` | `string` | 'primary'| Color of the checkbox when checked |
| `size` | `string` | 'medium'| Size of the checkbox ('small' or 'medium') |
| `labelPlacement`| `string` | 'end' | Position of the label ('end', 'start', 'top', 'bottom') |
### Examples
#### Basic Checkbox
```tsx
<FormCheckboxField
id="notifications"
label="Enable email notifications"
checked={notificationsEnabled}
onChange={(e) => setNotificationsEnabled(e.target.checked)}
color="secondary"
/>
```
#### Checkbox with Formik
```tsx
<Formik
initialValues={{
termsAccepted: false,
newsletter: true,
notifications: false
}}
onSubmit={(values) => console.log('Form values:', values)}
>
{({ values }) => (
<Form>
<Field
name="termsAccepted"
component={({ field, form }) => (
<FormCheckboxField
{...field}
label="I agree to the terms and conditions"
checked={field.value}
onChange={(e) => form.setFieldValue(field.name, e.target.checked)}
required
/>
)}
/>
<Field
name="newsletter"
component={({ field, form }) => (
<FormCheckboxField
{...field}
label="Subscribe to newsletter"
checked={field.value}
onChange={(e) => form.setFieldValue(field.name, e.target.checked)}
color="secondary"
/>
)}
/>
<Button type="submit" variant="contained" color="primary">
Submit
</Button>
</Form>
)}
</Formik>
```
#### Custom Styled Checkbox
```tsx
import { makeStyles } from '@mui/styles';
const useStyles = makeStyles((theme) => ({
root: {
margin: theme.spacing(1),
},
labelRoot: {
color: theme.palette.primary.main,
fontWeight: 500,
},
}));
function CustomCheckbox() {
const classes = useStyles();
return (
<FormCheckboxField
id="custom-checkbox"
label="Custom Styled Checkbox"
checked={false}
onChange={() => {}}
classes={{
root: classes.root,
label: classes.labelRoot,
}}
color="primary"
/>
);
}
```
## FormSwitch
A customizable switch component with Material-UI and Formik integration, providing consistent styling and behavior for boolean inputs across your application.
### Features
- **Material-UI Integration**: Consistent styling with Material-UI's design system
- **Formik Integration**: Seamless form state management with error handling
- **Flexible Label Placement**: Support for different label positions
- **TypeScript Support**: Full type safety with exported interfaces
- **Accessibility**: Built with accessibility in mind, following WAI-ARIA guidelines
- **Error Handling**: Built-in error state management with Formik
- **Responsive Design**: Works well on all screen sizes
### Basic Usage
```tsx
import { Formik, Field } from 'formik';
import { FormSwitch } from 'form-input-fields';
// Basic usage
<FormSwitch
label="Enable Notifications"
checked={notificationsEnabled}
onChange={(e, checked) => setNotificationsEnabled(checked)}
/>
// With Formik
<Formik
initialValues={{ notifications: false }}
onSubmit={(values) => console.log(values)}
>
<Field
component={FormSwitch}
name="notifications"
label="Enable Notifications"
helperText="Receive email notifications"
/>
</Formik>
```
### Props
The FormSwitch component accepts all props from `FormSwitchProps`, `FieldProps` (Formik), and Material-UI's `SwitchProps`.
#### FormSwitchProps Interface
| Prop | Type | Default | Description |
| ---------------- | ---------- | ------- | ------------------------------------------------ |
| `label` | `string` | - | Label text displayed next to the switch |
| `labelPlacement` | `string` | 'end' | Position of label ('top', 'start', 'bottom', 'end') |
| `color` | `string` | 'primary'| Switch color ('primary', 'secondary', 'error', 'info', 'success', 'warning', 'default') |
| `size` | `string` | 'medium'| Switch size ('small' or 'medium') |
| `disabled` | `boolean` | `false` | Disable the switch |
| `required` | `boolean` | `false` | Mark the field as required |
| `onChange` | `function` | - | Custom change handler with context data |
| `onBlur` | `function` | - | Custom blur handler |
| `helperText` | `string` | - | Helper text to display below the switch |
| `error` | `boolean` | `false` | Error state of the switch |
| `className` | `string` | - | Custom class name for the root element |
#### Common Props (from FieldProps & SwitchProps)
| Prop | Type | Required | Description |
|--------------|------------------|----------|-----------------------------------------------|
| `name` | `string` | Yes | Field name in Formik values |
| `label` | `string` | No | Field label |
| `helperText` | `string` | No | Custom helper text |
| `error` | `boolean` | No | Error state (auto-managed by Formik) |
| `disabled` | `boolean` | No | Disabled state |
| `required` | `boolean` | No | Required field indicator |
| Other | `SwitchProps` | No | All Material-UI Switch props are supported |
### Examples
#### Basic Switch
```tsx
<FormSwitch
label="Enable Dark Mode"
checked={darkModeEnabled}
onChange={(e, checked) => setDarkModeEnabled(checked)}
color="secondary"
size="small"
/>
```
#### Switch with Formik
```tsx
<Formik
initialValues={{
notifications: false,
darkMode: true,
autoSave: false
}}
onSubmit={(values) => console.log('Form values:', values)}
>
<Form>
<Field
component={FormSwitch}
name="notifications"
label="Enable Notifications"
helperText="Receive email notifications"
color="primary"
/>
<Field
component={FormSwitch}
name="darkMode"
label="Dark Mode"
helperText="Use dark theme"
color="secondary"
labelPlacement="start"
/>
<Field
component={FormSwitch}
name="autoSave"
label="Auto Save"
helperText="Automatically save changes"
color="success"
size="small"
/>
<Button type="submit" variant="contained" color="primary">
Save Settings
</Button>
</Form>
</Formik>
```
#### Custom Styled Switch
```tsx
<FormSwitch
label="Custom Styled Switch"
checked={false}
onChange={(e, checked) => console.log('Switch toggled:', checked)}
className="custom-switch-class"
color="warning"
labelPlacement="top"
helperText="This is a custom styled switch"
/>
```
#### Switch with Custom Change Handler
```tsx
<Field
component={FormSwitch}
name="advancedMode"
label="Advanced Mode"
onChange={(e, checked, context) => {
console.log('Field name:', context.fieldName);
console.log('Formik value:', context.formikValue);
// Custom logic here
}}
helperText="Enable advanced features"
/>
```
#### Switch with Validation
```tsx
<Formik
initialValues={{ termsAccepted: false }}
validate={(values) => {
const errors = {};
if (!values.termsAccepted) {
errors.termsAccepted = 'You must accept the terms to continue';
}
return errors;
}}
onSubmit={(values) => console.log(values)}
>
<Form>
<Field
component={FormSwitch}
name="termsAccepted"
label="I accept the terms and conditions"
helperText="Please read and accept the terms"
required
/>
<Button type="submit" variant="contained" color="primary">
Continue
</Button>
</Form>
</Formik>
```
## FormDateTextField
A versatile date input field component that provides a text-based date picker with Formik integration and Material-UI styling.
### Features
- **Formik Integration**: Seamlessly works with Formik for form state management
- **Material-UI Styling**: Consistent look and feel with Material Design
- **Flexible Date Formatting**: Supports custom date formats using day.js
- **TypeScript Support**: Fully typed component with proper type definitions
- **Responsive Design**: Works well across different screen sizes
- **Accessibility**: Built with accessibility in mind
### Available Date Formats
The component uses predefined date format constants from `date.ts`:
#### FORM_DATE_FORMAT
```typescript
export const FORM_DATE_FORMAT = {
short: "YYYY-MM-DD",
long: "MM/DD/YYYY hh:mm A",
custom: "DD MMMM YYYY hh:mm A"
};
```
#### DATE_PICKER_DATE_FORMAT
```typescript
export const DATE_PICKER_DATE_FORMAT = {
short: "DD/MM/YYYY"
};
```
#### DATE_PICKER_MONTH_YEAR_FORMAT
```typescript
export const DATE_PICKER_MONTH_YEAR_FORMAT = {
short: "MM/YYYY",
long: "MMMM YYYY"
};
```
### Basic Usage
```tsx
import { Formik, Field } from 'formik';
import { FormDateTextField } from 'form-fields';
<Formik
initialValues={{ eventDate: '' }}
onSubmit={(values) => console.log(values)}
>
<Field
component={FormDateTextField}
name="eventDate"
label="Event Date"
format="MM/DD/YYYY"
/>
</Formik>
```
### Props
The FormDateTextField component accepts all props from `FormDateTextFieldProps`, `FieldProps` (Formik), and Material-UI's `TextFieldProps` (with some exclusions).
#### FormDateTextFieldProps Interface
| Prop | Type | Default | Description |
|------|------|---------|-------------|
| `format` | `string` | `FORM_DATE_FORMAT.long` | Date format string using day.js tokens |
| `required` | `boolean` | `false` | Whether the field is required |
| `disabled` | `boolean` | `false` | Whether the field is disabled |
| `className` | `string` | - | Custom class name for the root element |
| `helperText` | `string` | - | Helper text to display below the field |
| `error` | `boolean` | - | Error state of the field |
| `onChange` | `(value: Dayjs \| null) => void` | - | Custom change handler |
| `onBlur` | `(event: React.FocusEvent<HTMLInputElement>) => void` | - | Custom blur handler |
#### Common Props (from FieldProps & TextFieldProps)
| Prop | Type | Required | Description |
|------|------|----------|-------------|
| `name` | `string` | Yes | Field name in Formik values |
| `label` | `string` | No | Label for the input field |
| `placeholder` | `string` | No | Placeholder text |
| `fullWidth` | `boolean` | No | If true, the input will take up the full width of its container |
| `margin` | `'none' \| 'dense' \| 'normal'` | No | If 'dense' or 'normal', will adjust vertical spacing |
| `size` | `'small' \| 'medium'` | No | The size of the text field |
### Examples
#### Basic Date Text Input
```tsx
<FormDateTextField
name="birthDate"
label="Birth Date"
format="YYYY-MM-DD"
helperText="Enter your date of birth"
required
/>
```
#### Date Text Field with Formik
```tsx
import { Formik, Form, Field } from 'formik';
import { FormDateTextField, FormTextField } from 'form-fields';
import { Button } from '@mui/material';
const EventForm = () => (
<Formik
initialValues={{
eventName: '',
eventDate: '',
}}
onSubmit={(values) => {
console.log('Form submitted:', values);
}}
>
{({ isSubmitting }) => (
<Form>
<Field
name="eventName"
label="Event Name"
component={FormTextField}
fullWidth
margin="normal"
/>
<Field
component={FormDateTextField}
name="eventDate"
label="Event Date"
format="MM/DD/YYYY"
required
helperText="Select the event date"
margin="normal"
/>
<Button
type="submit"
variant="contained"
color="primary"
disabled={isSubmitting}
>
Submit
</Button>
</Form>
)}
</Formik>
);
```
#### Custom Date Format
```tsx
<FormDateTextField
name="appointmentTime"
label="Appointment Time"
format="dddd, MMMM D, YYYY h:mm A"
helperText="Example: Monday, January 1, 2023 2:30 PM"
required
/>
```
#### Disabled State
```tsx
<FormDateTextField
name="purchaseDate"
label="Purchase Date"
value="2023-05-15"
disabled
helperText="This field cannot be modified"
/>
```
#### With Error State
```tsx
<FormDateTextField
name="expiryDate"
label="Expiry Date"
error={!!errors.expiryDate && touched.expiryDate}
helperText={touched.expiryDate && errors.expiryDate}
format="MM/DD/YYYY"
required
/>
```
## FormMaskField
A flexible form field component with advanced text masking capabilities.
### Features
- **Material-UI Integration**: Consistent styling with other form components
- **Formik Integration**: Seamless form state management
- **Flexible Masking**: Pattern-based input masking with multiple character types
- **Uppercase Conversion**: Automatic text transformation
- **TypeScript Support**: Full type safety and IntelliSense
- **Clean Value Option**: Return masked or unmasked values to form state
### Usage with Formik
```tsx
import { Formik, Field } from "formik";
import { FormMaskField } from "form-input-mask-field";
<Formik
initialValues={{ phoneNumber: "", gameCode: "" }}
onSubmit={(values) => console.log(values)}
>
<Field
component={FormMaskField}
name="phoneNumber"
label="Phone Number"
mask="(999) 999-9999"
placeholder="Enter phone number"
/>
<Field
component={FormMaskField}
name="gameCode"
label="Game Code"
mask="AAAAA"
toUpperCase={true}
returnCleanValue={true}
/>
</Formik>;
```
### Mask Pattern Characters
| Character | Description | Example |
| --------- | ---------------------------- | ------------------------ |
| `9` | Digit (0-9) | `999-99-9999` for SSN |
| `A` | Letter (a-z, A-Z) | `AAA` for country code |
| `*` | Alphanumeric (a-z, A-Z, 0-9) | `***-***` for mixed code |
| `a` | Lowercase letter (a-z) | `aaa` for lowercase only |
| `Z` | Uppercase letter (A-Z) | `ZZZ` for uppercase only |
| `#` | Hexadecimal (0-9, A-F, a-f) | `######` for hex color |
| Any other | Literal character | `-`, `(`, `)`, `/`, etc. |
### Props
| Prop | Type | Default | Description |
| ------------------ | ---------- | ------- | -------------------------------------------------------------- |
| `mask` | `string` | - | Mask pattern using the characters above |
| `placeholderChar` | `string` | `'_'` | Character shown in placeholder for mask positions |
| `toUpperCase` | `boolean` | `false` | Convert input to uppercase automatically |
| `returnCleanValue` | `boolean` | `false` | Return unmasked value to Formik (true) or masked value (false) |
| `showMaskPattern` | `boolean` | `false` | Show the mask pattern as helper text below the input field |
| `showPlaceholder` | `boolean` | `false` | Show placeholder text with mask pattern in the input field |
| `onChange` | `function` | - | Custom change handler with masked, clean, and raw values |
| `variant` | `'standard' | 'outlined' | 'filled'` | 'standard' | The variant of the MUI TextField. |
Plus all standard Material-UI TextField props and Formik FieldProps.
### Examples
#### Phone Number
```tsx
<Field
component={FormMaskField}
name="phone"
label="Phone Number"
mask="(999) 999-9999"
placeholder="(555) 123-4567"
variant="outlined" // <-- Example with outlined variant
/>
```
#### Date Input
```tsx
<Field
component={FormMaskField}
name="date"
label="Date"
mask="99/99/9999"
placeholder="MM/DD/YYYY"
/>
```
#### Product Code (Uppercase)
```tsx
<Field
component={FormMaskField}
name="productCode"
label="Product Code"
mask="AAA-999-AAA"
toUpperCase={true}
returnCleanValue={true}
/>
```
#### Credit Card
```tsx
<Field
component={FormMaskField}
name="creditCard"
label="Credit Card"
mask="9999 9999 9999 9999"
placeholder="1234 5678 9012 3456"
/>
```
#### Custom Change Handler
```tsx
<Field
component={FormMaskField}
name="customField"
label="Custom Field"
mask="999-AAA"
onChange={(event) => {
console.log("Masked value:", event.target.value);
console.log("Clean value:", event.target.cleanValue);
console.log("Raw input:", event.target.rawValue);
}}
variant="outlined" // <-- Example with outlined variant
/>
```
#### Show Mask Pattern
```tsx
<Field
component={FormMaskField}
name="gameCode"
label="Game Code"
mask="AAA-999"
showMaskPattern={true}
toUpperCase={true}
/>
// This will show "Pattern: AAA-999" as helper text below the input
```
#### Show Placeholder
```tsx
<Field
component={FormMaskField}
name="phoneNumber"
label="Phone Number"
mask="(999) 999-9999"
showPlaceholder={true}
/>
// This will show "(___) ___-____" as placeholder text in the input field
```
## Complete Example Application
Here's a comprehensive example showing how to build a complete form application using FormMaskField with Material-UI and Formik:
### App.tsx
```tsx
import React from "react";
import { Formik, Form, Field, FormikHelpers, FormikErrors } from "formik";
import Container from "@mui/material/Container";
import Typography from "@mui/material/Typography";
import Box from "@mui/material/Box";
import Button from "@mui/material/Button";
import { Grid } from "@mui/material";
import Paper from "@mui/material/Paper";
import Alert from "@mui/material/Alert";
import { ThemeProvider, createTheme } from "@mui/material/styles";
import CssBaseline from "@mui/material/CssBaseline";
import { FormMaskField } from "form-input-mask-field";
import "./App.css";
interface FormValues {
phone: string;
date: string;
creditCard: string;
licensePlate: string;
hexColor: string;
customCode: string;
socialSecurity: string;
postalCode: string;
}
interface FormFieldEvent
extends Omit<React.ChangeEvent<HTMLInputElement>, "target"> {
target: HTMLInputElement & {
value: string;
cleanValue: string;
rawValue: string;
name: string;
};
}
// Create a Material-UI theme
const theme = createTheme({
palette: {
primary: {
main: "#1976d2",
},
secondary: {
main: "#dc004e",
},
},
});
// Validation schema
const validateForm = (values: FormValues): FormikErrors<FormValues> => {
const errors: Partial<FormValues> = {};
if (!values.phone) {
errors.phone = "Phone number is required";
} else if (values.phone.replace(/\D/g, "").length < 10) {
errors.phone = "Phone number must be 10 digits";
}
if (!values.date) {
errors.date = "Date is required";
}
if (!values.creditCard) {
errors.creditCard = "Credit card is required";
} else if (values.creditCard.replace(/\D/g, "").length < 16) {
errors.creditCard = "Credit card must be 16 digits";
}
if (!values.licensePlate) {
errors.licensePlate = "License plate is required";
}
return errors;
};
function App() {
const initialValues: FormValues = {
phone: "",
date: "",
creditCard: "",
licensePlate: "",
hexColor: "",
customCode: "",
socialSecurity: "",
postalCode: "",
};
const handleSubmit = (
values: FormValues,
{ setSubmitting }: FormikHelpers<FormValues>
) => {
console.log("Form Values:", values);
setTimeout(() => {
alert("Form submitted! Check console for values.");
setSubmitting(false);
}, 400);
};
const handleCustomChange =
(fieldName: keyof FormValues) => (event: FormFieldEvent) => {
console.log(`${fieldName} changed:`, {
masked: event.target.value,
clean: event.target.cleanValue,
raw: event.target.rawValue,
});
return event;
};
return (
<ThemeProvider theme={theme}>
<CssBaseline />
<Container maxWidth="lg" sx={{ py: 4 }}>
<Typography variant="h3" component="h1" gutterBottom align="center">
FormMaskField Demo
</Typography>
<Typography
variant="subtitle1"
align="center"
color="text.secondary"
paragraph
>
A comprehensive example showcasing the FormMaskField component with
various mask patterns and configurations
</Typography>
<Formik
initialValues={initialValues}
validate={validateForm}
onSubmit={handleSubmit}
>
{({ values, isSubmitting, errors, touched }) => (
<Form>
<Grid container spacing={3}>
{/* Basic Masks Section */}
<Grid>
<Paper elevation={2} sx={{ p: 3 }}>
<Typography variant="h5" gutterBottom>
Basic Input Masks
</Typography>
<Grid container spacing={2}>
<Grid>
<Field
name="phone"
component={FormMaskField}
label="Phone Number"
mask="(999) 999-9999"
showMaskPattern={true}
showPlaceholder={true}
helperText="US phone number format"
onChange={handleCustomChange("phone")}
variant="outlined" // <-- Example with outlined variant
/>
</Grid>
<Grid>
<Field
name="date"
component={FormMaskField}
label="Date"
mask="99/99/9999"
showMaskPattern={true}
showPlaceholder={true}
helperText="MM/DD/YYYY format"
/>
</Grid>
<Grid>
<Field
name="socialSecurity"
component={FormMaskField}
label="Social Security Number"
mask="999-99-9999"
showMaskPattern={true}
showPlaceholder={true}
returnCleanValue={true}
helperText="Clean value returned (no dashes)"
/>
</Grid>
<Grid>
<Field
name="postalCode"
component={FormMaskField}
label="ZIP Code"
mask="99999-9999"
showMaskPattern={true}
showPlaceholder={true}
helperText="US ZIP+4 format"
/>
</Grid>
</Grid>
</Paper>
</Grid>
{/* Advanced Masks Section */}
<Grid>
<Paper elevation={2} sx={{ p: 3 }}>
<Typography variant="h5" gutterBottom>
Advanced Input Masks
</Typography>
<Grid container spacing={2}>
<Grid>
<Field
name="creditCard"
component={FormMaskField}
label="Credit Card Number"
mask="9999-9999-9999-9999"
showMaskPattern={true}
showPlaceholder={true}
helperText="16-digit credit card number"
onChange={handleCustomChange("creditCard")}
/>
</Grid>
<Grid>
<Field
name="licensePlate"
component={FormMaskField}
label="License Plate"
mask="AAA-999"
toUpperCase={true}
showMaskPattern={true}
showPlaceholder={true}
helperText="3 letters + 3 numbers (auto uppercase)"
onChange={handleCustomChange("licensePlate")}
/>
</Grid>
<Grid>
<Field
name="hexColor"
component={FormMaskField}
label="Hex Color Code"
mask="#######"
toUpperCase={true}
showMaskPattern={true}
showPlaceholder={true}
placeholderChar="0"
helperText="6-digit hex color code"
/>
</Grid>
<Grid>
<Field
name="customCode"
component={FormMaskField}
label="Custom Code"
mask="**-999-AA"
toUpperCase={true}
returnCleanValue={true}
showMaskPattern={true}
showPlaceholder={true}
helperText="Alphanumeric + digits + letters"
onChange={handleCustomChange("customCode")}
/>
</Grid>
</Grid>
</Paper>
</Grid>
{/* Current Values Display */}
<Grid>
<Paper elevation={2} sx={{ p: 3 }}>
<Typography variant="h5" gutterBottom>
Current Form Values
</Typography>
<Box sx={{ mt: 2 }}>
<Typography
variant="body2"
component="pre"
sx={{
backgroundColor: "#f5f5f5",
p: 2,
borderRadius: 1,
overflow: "auto",
fontSize: "0.875rem",
}}
>
{JSON.stringify(values, null, 2)}
</Typography>
</Box>
</Paper>
</Grid>
{/* Form Errors Display */}
{Object.keys(errors).length > 0 &&
Object.keys(touched).length > 0 && (
<Grid>
<Alert severity="error">
<Typography variant="h6" gutterBottom>
Form Validation Errors:
</Typography>
<ul>
{Object.entries(errors).map(
([field, error]) =>
touched[field] && (
<li key={field}>
<strong>{field}:</strong> {error}
</li>
)
)}
</ul>
</Alert>
</Grid>
)}
{/* Submit Button */}
<Grid>
<Box
sx={{ display: "flex", justifyContent: "center", mt: 2 }}
>
<Button
type="submit"
variant