JSPM

  • ESM via JSPM
  • ES Module Entrypoint
  • Export Map
  • Keywords
  • License
  • Repository URL
  • TypeScript Types
  • README
  • Created
  • Published
  • Downloads 68
  • Score
    100M100P100Q51567F
  • License MIT

A customizable form field components built with TypeScript

Package Exports

  • form-input-fields
  • form-input-fields/dist/index.es.js
  • form-input-fields/dist/index.js

This package does not declare an exports field, so the exports above have been automatically detected and optimized by JSPM instead. If any package subpath is missing, it is recommended to post an issue to the original package (form-input-fields) to support the "exports" field. If that is not possible, create a JSPM override to customize the exports field for this package.

Readme

Form Fields Components

A collection of Material-UI form field components with Formik integration.

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

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

export const DATE_PICKER_DATE_FORMAT = {
  short: "DD/MM/YYYY",
};

DATE_PICKER_MONTH_YEAR_FORMAT

export const DATE_PICKER_MONTH_YEAR_FORMAT = {
  short: "MM/YYYY",
  long: "MMMM YYYY",
};

Importing Date Constants

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

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

<Field
  component={FormDateField}
  name="birthDate"
  label="Birth Date"
  format="DD/MM/YYYY"
/>

Date with Validation

<Field
  component={FormDateField}
  name="startDate"
  label="Start Date"
  minDate={dayjs()}
  disablePast={true}
  showDateFormat={true}
  helperText="Select a future date"
/>

Appointment Scheduler

<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

<Field
  component={FormDateField}
  name="createdDate"
  label="Created Date"
  format="DD/MM/YYYY HH:mm"
  readOnly={true}
/>

Custom Change Handler

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

<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}
/>

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

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

Plus all standard Material-UI TextField props and Formik FieldProps.

Examples

Phone Number

<Field
  component={FormMaskField}
  name="phone"
  label="Phone Number"
  mask="(999) 999-9999"
  placeholder="(555) 123-4567"
/>

Date Input

<Field
  component={FormMaskField}
  name="date"
  label="Date"
  mask="99/99/9999"
  placeholder="MM/DD/YYYY"
/>

Product Code (Uppercase)

<Field
  component={FormMaskField}
  name="productCode"
  label="Product Code"
  mask="AAA-999-AAA"
  toUpperCase={true}
  returnCleanValue={true}
/>

Credit Card

<Field
  component={FormMaskField}
  name="creditCard"
  label="Credit Card"
  mask="9999 9999 9999 9999"
  placeholder="1234 5678 9012 3456"
/>

Custom Change Handler

<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);
  }}
/>

Show Mask Pattern

<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

<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

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")}
                        />
                      </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="contained"
                      size="large"
                      disabled={isSubmitting}
                      sx={{ minWidth: 200 }}
                    >
                      {isSubmitting ? "Submitting..." : "Submit Form"}
                    </Button>
                  </Box>
                </Grid>
              </Grid>
            </Form>
          )}
        </Formik>
      </Container>
    </ThemeProvider>
  );
}

export default App;

App.css

#root {
  max-width: 1280px;
  margin: 0 auto;
  padding: 2rem;
  text-align: center;
}

.logo {
  height: 6em;
  padding: 1.5em;
  will-change: filter;
  transition: filter 300ms;
}

.logo:hover {
  filter: drop-shadow(0 0 2em #646cffaa);
}

.logo.react:hover {
  filter: drop-shadow(0 0 2em #61dafbaa);
}

@keyframes logo-spin {
  from {
    transform: rotate(0deg);
  }
  to {
    transform: rotate(360deg);
  }
}

@media (prefers-reduced-motion: no-preference) {
  a:nth-of-type(2) .logo {
    animation: logo-spin infinite 20s linear;
  }
}

.card {
  padding: 2em;
}

.read-the-docs {
  color: #888;
}

Key Features Demonstrated

This example application showcases:

  1. Complete Form Integration: Full Formik integration with validation and error handling
  2. Multiple Mask Types: Phone numbers, dates, credit cards, license plates, hex colors, and custom codes
  3. Advanced Features:
    • Uppercase conversion (toUpperCase)
    • Clean value return (returnCleanValue)
    • Custom placeholder characters (placeholderChar)
    • Pattern display (showMaskPattern)
    • Placeholder display (showPlaceholder)
  4. Custom Event Handling: onChange handlers that provide masked, clean, and raw values
  5. Material-UI Integration: Consistent styling with Material-UI theme and components
  6. Real-time Validation: Form validation with error display
  7. Live Value Display: Real-time display of current form values
  8. Responsive Layout: Grid-based responsive layout

Running the Example

To run this example:

  1. Install dependencies: npm install
  2. Start the development server: npm run dev
  3. Open your browser and navigate to the local development URL
  4. Interact with the form fields to see the masking in action
  5. Open browser console to see custom onChange event data

The example demonstrates how FormMaskField seamlessly integrates with existing Material-UI and Formik workflows while providing powerful input masking capabilities.

Support

If you like my work, you can support me here:

Buy Me a book