JGuang

MaskInput

MaskInput · Mantine Core

Preview
npm install @mantine/core@9.7.1 @mantine/hooks@9.7.1

MaskInput

Install: npm install @mantine/core@9.7.1 @mantine/hooks@9.7.1

Version and compatibility

Pinned Mantine Core 9.7.1 requires React and React DOM ^19.2.0 and matching @mantine/hooks@9.7.1, from the installed npm package's peerDependencies. Do not force it into React 18 or another incompatible version. Explain upgrade impact and agree on a plan with the project owner; do not hide conflicts with --force/--legacy-peer-deps. The native Provider enables theme.respectReducedMotion and uses forceColorScheme for light/dark.

Use case

Constrain text input to a mask format.

Native props used by this example

These props are extracted from the local typechecked JSX and grouped by their owning native component. This is not an exhaustive prop list; see pinned source signatures and inheritance below.

Component propExplanation
MaskInput.disabledDisable user input/action; not equivalent to readOnly.
MaskInput.errorLocal error display; it does not run validation by itself.
MaskInput.readOnlyPrevent editing while preserving the read-only interaction.
MaskInput.maskInput mask syntax supported by the native component.
MaskInput.labelVisible label or component-specific label content.
MaskInput.placeholderInput hint, not a replacement for a label.

Interaction and state checks

Current scenarios: Default, Disabled, Invalid, Read only. Check actual behavior after selecting supported disabled/error/read-only scenarios; components without those native states do not receive invented universal props. Verify keyboard focus and exits, then connect changed values through the native callback signature.

Business integration boundary

A mask is presentation/input constraint, not proof that a phone/card value is valid or authorized.

Host setup

Install pinned @mantine/core and @mantine/hooks, import @mantine/core/styles.css at the entry and use MantineProvider. The example's theme/variant are JGuang-authored host props, not universal native component APIs; forceColorScheme synchronizes the app theme. Native implementation source is a reading reference: use npm exports rather than copying internal engines. This batch covers Core, not dates/charts/forms extension packages. Detailed upstream prose remains English.

Runnable usage

import { useState } from 'react';
import * as M from '@mantine/core';
import '@mantine/core/styles.css';


function ComponentPreview({ variant = 'Default' }: { variant?: string }) {
const disabled = variant === "Disabled";
const invalid = variant === "Invalid";
const readOnly = variant === "Read only";
return <M.MaskInput disabled={disabled} error={invalid ? "Check the format / 请检查格式" : undefined} readOnly={readOnly} mask="0000 0000" label="Masked input" placeholder="1234 5678" />;
}
export default function Example({ variant = 'Default', theme = 'light' }: { variant?: string; theme?: 'light' | 'dark' }) {
return <M.MantineProvider forceColorScheme={theme} theme={{ respectReducedMotion: true }}><ComponentPreview variant={variant} /></M.MantineProvider>;
}

Preview states

Default, Disabled, Invalid, Read only

The example uses the native Mantine API. For supported input demos, change the local variant to Disabled, Invalid or Read only; these are example labels, not new component props. Keep the documented data, controlled values, stores and compound children when adapting the example.

Usage

MaskInput is a wrapper around useMask hook. It supports all mask options and standard input props (label, description, error, etc.). The mask string defines the expected format, see mask pattern syntax.

Dynamic mask

Use the modify option to change the mask based on the current input value. This example switches between standard and American Express credit card formats:

Custom tokens

Override or extend the built-in token map with the tokens option:

Regex array format

For complex masks where built-in tokens are not enough, pass an array of string literals and RegExp objects:

Transform

Use the transform option to convert each character before validation. This example auto-uppercases input so the A token accepts lowercase letters:

Disabled state

Error state

Success state

Reset value

MaskInput is uncontrolled internally – setting value from a parent will not clear it. Use the resetRef prop to get a function that clears the input value imperatively:

With use-form

To use MaskInput with use-form, pass the initial value with defaultValue and write the raw (unmasked) value to the form state in onChangeRaw. In uncontrolled form mode, pass { forceUpdate: false } to form.setFieldValue so the input is not remounted on every keystroke:

Mask pattern syntax

Each character of the mask string is either a token (editable slot) or a literal (fixed character inserted automatically).

Built-in tokens

  • 9 – any single digit ([0-9])
  • a – any single letter ([A-Za-z])
  • A – any uppercase letter ([A-Z])
  • * – any alphanumeric character ([A-Za-z0-9])
  • # – digit or sign ([-+0-9])

Optional segments

Append ? after the last required character to mark remaining slots as optional:

<MaskInput mask="(999) 999-9999? x9999" /> // Extension is optional

Escaping

Prefix a token character with \ to treat it as a literal:

<MaskInput mask="\A999" /> // "A" is literal, not a token

Source-backed parameter reference

Implementation signatures and types are generated from the pinned local source. Optional props, native inherited types, union branches and never exclusions are preserved. A forwardRef implementation's ref is a React reference, not an additional business prop.

MaskInput(props)
export interface MaskInputProps
  extends
    BoxProps,
    __BaseInputProps,
    StylesApiProps<MaskInputFactory>,
    ElementProps<'input', 'size'> {
  /** Mask pattern string or array of string literals and RegExp objects */
  mask: string | Array<string | RegExp>;

  /** Override or extend the default token map */
  tokens?: Record<string, RegExp>;

  /** Called before masking on each keystroke, can return overrides for mask options */
  modify?: (
    value: string
  ) => Partial<Pick<MaskInputProps, 'mask' | 'tokens' | 'slotChar' | 'separate'>> | undefined;

  /** When true, raw and display values are decoupled */
  separate?: boolean;

  /** Character displayed in unfilled slots, `"_"` by default */
  slotChar?: string | null;

  /** Show mask pattern even when field is empty and unfocused */
  alwaysShowMask?: boolean;

  /** Show mask placeholder on focus, `true` by default */
  showMaskOnFocus?: boolean;

  /** Transform each character before validation and insertion */
  transform?: (char: string) => string;

  /** Clear value on blur when mask is incomplete, `false` by default */
  autoClear?: boolean;

  /** Called on every change with raw and masked values */
  onChangeRaw?: (rawValue: string, maskedValue: string) => void;

  /** Called when all required mask slots are filled */
  onComplete?: (maskedValue: string, rawValue: string) => void;

  /** Escape hatch for advanced cursor/value manipulation */
  beforeMaskedStateChange?: (states: {
    previousState: { value: string; selection: { start: number; end: number } | null };
    currentState: { value: string; selection: { start: number; end: number } | null };
    nextState: { value: string; selection: { start: number; end: number } | null };
  }) => { value: string; selection: { start: number; end: number } | null };

  /** Assigns a function that clears the input value to the given ref */
  resetRef?: React.RefObject<(() => void) | null>;
}

export type MaskInputFactory = Factory<{
  props: MaskInputProps;
  variant: InputVariant;
  ref: HTMLInputElement;
  stylesNames: __InputStylesNames;
}>;

export type Mod = Record<string, any> | string;

export type BoxMod = Mod | Mod[] | BoxMod[];

export interface BoxProps extends MantineStyleProps {
  /** Class added to the root element, if applicable */
  className?: string | undefined;

  /** Inline style added to root component element, can subscribe to theme defined on MantineProvider */
  style?: MantineStyleProp;

  /** CSS variables defined on root component element */
  __vars?: CssVarsProp;

  /** `size` property passed down the HTML element */
  __size?: string;

  /** Breakpoint above which the component is hidden with `display: none` */
  hiddenFrom?: MantineBreakpoint;

  /** Breakpoint below which the component is hidden with `display: none` */
  visibleFrom?: MantineBreakpoint;

  /** Determines whether component should be hidden in light color scheme with `display: none` */
  lightHidden?: boolean;

  /** Determines whether component should be hidden in dark color scheme with `display: none` */
  darkHidden?: boolean;

  /** Element modifiers transformed into `data-` attributes, for example, `{ 'data-size': 'xl' }`, falsy values are removed */
  mod?: BoxMod;
}

export type ElementProps<
  ElementType extends React.ElementType,
  PropsToOmit extends string = never,
> = Omit<React.ComponentProps<ElementType>, 'style' | PropsToOmit>;

export interface CSSProperties extends React.CSSProperties {
  [key: string]: any;
}

type MantineStyle = CSSProperties | ((theme: MantineTheme) => CSSProperties);

export type MantineStyleProp = MantineStyle | MantineStyle[] | MantineStyleProp[] | undefined;

export type CssVariable = `--${string}`;

export type CssVariables<Variable extends string = CssVariable> = Partial<Record<Variable, string>>;

export type CssVars<Variable extends string = CssVariable> =
  | CssVariables<Variable>
  | ((theme: MantineTheme) => CssVariables<Variable>)
  | CssVars<Variable>[];

export type CssVarsProp<Variable extends string = CssVariable> =
  | CssVars<Variable>
  | CssVars<Variable>[];

type WrapperProps = React.ComponentProps<'div'> & DataAttributes;

export interface __BaseInputProps extends __InputWrapperProps, __InputProps {
  /** Props passed down to the root element */
  wrapperProps?: WrapperProps;
}

export type __InputStylesNames = InputStylesNames | InputWrapperStylesNames;

export type InputStylesNames = 'input' | 'wrapper' | 'section' | 'bottomSection';

export type InputVariant = 'default' | 'filled' | 'unstyled';

export interface __InputProps {
  /** Content section displayed on the left side of the input */
  leftSection?: React.ReactNode;

  /** Left section width, used to set `width` of the section and input `padding-left`, by default equals to the input height */
  leftSectionWidth?: React.CSSProperties['width'];

  /** Props passed down to the `leftSection` element */
  leftSectionProps?: React.ComponentProps<'div'>;

  /** Sets `pointer-events` styles on the `leftSection` element. Use `'all'` when section contains interactive elements (buttons, links). @default 'none' */
  leftSectionPointerEvents?: React.CSSProperties['pointerEvents'];

  /** Content section displayed on the right side of the input */
  rightSection?: React.ReactNode;

  /** Right section width, used to set `width` of the section and input `padding-right`, by default equals to the input height */
  rightSectionWidth?: React.CSSProperties['width'];

  /** Props passed down to the `rightSection` element */
  rightSectionProps?: React.ComponentProps<'div'>;

  /** Sets `pointer-events` styles on the `rightSection` element. Use `'all'` when section contains interactive elements (buttons, links). @default 'none' */
  rightSectionPointerEvents?: React.CSSProperties['pointerEvents'];

  /** Sets `required` attribute on the `input` element */
  required?: boolean;

  /** Key of `theme.radius` or any valid CSS value to set `border-radius`, numbers are converted to rem @default theme.defaultRadius */
  radius?: MantineRadius;

  /** Sets `disabled` attribute on the `input` element */
  disabled?: boolean;

  /** Controls input `height`, horizontal `padding`, and `font-size` @default 'sm' */
  size?: MantineSize | (string & {});

  /** Determines whether the input should have `cursor: pointer` style. Use when input acts as a button-like trigger (e.g., `component="button"` for Select/DatePicker). @default false */
  pointer?: boolean;

  /** Determines whether the input should have red border and red text color when the `error` prop is set @default true */
  withErrorStyles?: boolean;

  /** Determines whether the input should have green border when the `success` prop is set @default true */
  withSuccessStyles?: boolean;

  /** HTML `size` attribute for the input element (number of visible characters) */
  inputSize?: string;

  /** Section to be displayed when the input is `__clearable` and `rightSection` is not defined */
  __clearSection?: React.ReactNode;

  /** Determines whether the `__clearSection` should be displayed if it is passed to the component, has no effect if `rightSection` is defined */
  __clearable?: boolean;

  /** Determines how the clear button and rightSection are rendered @default 'both' */
  __clearSectionMode?: ClearSectionMode;

  /** Right section displayed when both `__clearSection` and `rightSection` are not defined */
  __defaultRightSection?: React.ReactNode;

  /** Displays loading indicator in the left or right section @default false */
  loading?: boolean;

  /** Position of the loading indicator @default 'right' */
  loadingPosition?: 'left' | 'right';

  /** Content section displayed at the bottom of the input, inside the border */
  __bottomSection?: React.ReactNode;

  /** Props passed down to the `__bottomSection` element */
  __bottomSectionProps?: React.ComponentProps<'div'>;
}

export type InputWrapperStylesNames =
  | 'root'
  | InputLabelStylesNames
  | InputDescriptionStylesNames
  | InputErrorStylesNames
  | InputSuccessStylesNames;

export interface __InputWrapperProps {
  /** Contents of `Input.Label` component. If not set, label is not displayed. */
  label?: React.ReactNode;

  /** Contents of `Input.Description` component. If not set, description is not displayed. */
  description?: React.ReactNode;

  /** Contents of `Input.Error` component. If not set, error is not displayed. */
  error?: React.ReactNode;

  /** Contents of `Input.Success` component. If not set, success is not displayed. */
  success?: React.ReactNode;

  /** Adds required attribute to the input and a red asterisk on the right side of label @default false */
  required?: boolean;

  /** If set, the required asterisk is displayed next to the label. Overrides `required` prop. Does not add required attribute to the input. @default false */
  withAsterisk?: boolean;

  /** Props passed down to the `Input.Label` component */
  labelProps?: InputLabelProps & DataAttributes & PlaceholderPolymorphicProps;

  /** Props passed down to the `Input.Description` component */
  descriptionProps?: InputDescriptionProps & DataAttributes & PlaceholderPolymorphicProps;

  /** Props passed down to the `Input.Error` component */
  errorProps?: InputErrorProps & DataAttributes & PlaceholderPolymorphicProps;

  /** Props passed down to the `Input.Success` component */
  successProps?: InputSuccessProps & DataAttributes & PlaceholderPolymorphicProps;

  /** Render function to wrap the input element. Useful for adding tooltips, popovers, or other wrappers around the input. @default React.Fragment */
  inputContainer?: (children: React.ReactNode) => React.ReactNode;

  /** Controls order and visibility of wrapper elements. Only elements included in this array will be rendered. @default ['label', 'description', 'input', 'error'] */
  inputWrapperOrder?: ('label' | 'input' | 'description' | 'error')[];
}

Native and external types

External types remain defined by React or native dependencies, not manually expanded into guessed props. The installed version's TypeScript definitions are authoritative.

Factory<{
  props: MaskInputProps;
  variant: InputVariant;
  ref: HTMLInputElement;
  stylesNames: __InputStylesNames;
}>
MantineStyleProps
React.CSSProperties
MantineTheme
Partial<Record<Variable, string>>
Record<Variable, string>
Variable
MantineBreakpoint
Record<string, any>
React.ReactNode
InputLabelProps
DataAttributes
PlaceholderPolymorphicProps
InputDescriptionProps
InputErrorProps
InputSuccessProps
React.ComponentProps<'div'>
MantineRadius
MantineSize
ClearSectionMode
StylesApiProps<MaskInputFactory>
React.ElementType
Omit<React.ComponentProps<ElementType>, 'style' | PropsToOmit>
React.ComponentProps<ElementType>
ElementType
PropsToOmit
Array<string | RegExp>
RegExp
Record<string, RegExp>
Partial<Pick<MaskInputProps, 'mask' | 'tokens' | 'slotChar' | 'separate'>>
Pick<MaskInputProps, 'mask' | 'tokens' | 'slotChar' | 'separate'>
React.RefObject<(() => void) | null>
HTMLInputElement
InputLabelStylesNames
InputDescriptionStylesNames
InputErrorStylesNames
InputSuccessStylesNames