useMask
useMask (입력 마스킹)
useMask 훅은 전화번호, 신용카드 번호, 날짜 같은 입력을 마스킹해요. 빌트인 토큰과 커스텀 토큰, 동적 마스크, 정규식 배열 형식을 지원해요.
출처: 문서
본문
useMask 훅을 사용해 입력 필드에 마스킹을 적용할 수 있어요. 반환값의 ref를 입력 요소에 전달하고, value와 rawValue로 표시 값과 원시 값을 각각 읽을 수 있어요.
import { TextInput, Text } from '@mantine/core';
import { useMask } from '@mantine/hooks';
function Demo() {
const { ref, value, rawValue } = useMask({ mask: '(999) 999-9999' });
return (
<>
<TextInput label="Phone number" ref={ref} />
<Text>Masked value: {value}</Text>
<Text>Raw value: {rawValue}</Text>
</>
);
}
isComplete, slotChar 그리고 transform
isComplete로 필요한 마스크 슬롯이 모두 채워졌는지 확인할 수 있어요. 예를 들어 제출 버튼을 제어할 때 사용해요. slotChar 옵션은 각 슬롯의 위치 힌트를 보여주는 여러 문자로 된 문자열을 받아요. transform 옵션은 검증 전에 각 문자를 변환해요. 다음 예시에서는 입력을 자동으로 대문자로 만들므로 A 토큰([A-Z])이 소문자도 받아들여요.
import { Button, Group, Text, TextInput } from '@mantine/core';
import { useMask } from '@mantine/hooks';
function Demo() {
const { ref, isComplete, rawValue } = useMask({
mask: 'AAA-9999',
slotChar: 'XXX-0000',
transform: (char) => char.toUpperCase(),
});
return (
<>
<TextInput label="Promo code" ref={ref} />
<Text>Raw value: {rawValue}</Text>
<Button disabled={!isComplete}>Apply code</Button>
</>
);
}
동적 마스크 (Dynamic mask)
modify 옵션으로 현재 입력 값에 따라 마스크를 변경할 수 있어요. 이 예시는 표준 신용카드 형식과 American Express 형식을 전환해요.
import { TextInput, Text } from '@mantine/core';
import { useMask } from '@mantine/hooks';
function Demo() {
const { ref, rawValue } = useMask({
mask: '9999 9999 9999 9999',
modify: (value) => {
const digits = value.replace(/\D/g, '');
if (digits.startsWith('34') || digits.startsWith('37')) {
return { mask: '9999 999999 99999' };
}
},
});
return (
<>
<TextInput label="Credit card number" ref={ref} />
<Text>Raw value: {rawValue}</Text>
<Text>Try starting with 34 or 37 for Amex format</Text>
</>
);
}
커스텀 토큰 (Custom tokens)
tokens 옵션으로 빌트인 토큰 맵을 재정의하거나 확장할 수 있어요.
import { TextInput, Text } from '@mantine/core';
import { useMask } from '@mantine/hooks';
function Demo() {
const { ref, rawValue } = useMask({
mask: '\\#hhhhhh',
tokens: { h: /[0-9a-fA-F]/ },
});
return (
<>
<TextInput label="Hex color" ref={ref} />
<Text>Raw value: {rawValue}</Text>
</>
);
}
이스케이프 (Escaping)
토큰 문자 앞에 \를 붙여 리터럴로 처리할 수 있어요. 이 예시에서 A는 보통 대문자 토큰이지만 \A는 리터럴 문자가 돼요.
import { TextInput, Text } from '@mantine/core';
import { useMask } from '@mantine/hooks';
function Demo() {
const { ref, rawValue } = useMask({
mask: '\\A-9999',
});
return (
<>
<TextInput label="Product code" ref={ref} />
<Text>Raw value: {rawValue}</Text>
</>
);
}
정규식 배열 형식 (Regex array format)
빌트인 토큰으로 충분하지 않은 복잡한 마스크에는 문자열 리터럴과 RegExp 객체의 배열을 전달해요. 이 예시는 첫 번째 자릿수를 0-2로, 분의 십의 자리를 0-5로 제한하는 시간 입력을 만들어요.
import { TextInput, Text } from '@mantine/core';
import { useMask } from '@mantine/hooks';
function Demo() {
const { ref, rawValue } = useMask({
mask: [/[0-2]/, /\d/, ':', /[0-5]/, /\d/],
});
return (
<>
<TextInput label="Time (HH:MM)" ref={ref} />
<Text>Raw value: {rawValue}</Text>
</>
);
}
초기화 (Reset)
훅이 반환하는 reset 함수를 사용해 입력 값을 프로그래밍 방식으로 지울 수 있어요.
import { Button, Group, Text, TextInput } from '@mantine/core';
import { useMask } from '@mantine/hooks';
function Demo() {
const { ref, value, rawValue, reset } = useMask({
mask: '(999) 999-9999',
});
return (
<>
<TextInput label="Phone number" ref={ref} />
<Text>Masked: {value}</Text>
<Text>Raw: {rawValue}</Text>
<Button onClick={reset}>Reset</Button>
</>
);
}
마스크 패턴 문법 (Mask pattern syntax)
마스크 문자열은 기대하는 형식을 정의해요. 각 문자는 토큰(편집 가능한 슬롯) 또는 리터럴(자동으로 삽입되는 고정 문자)이에요.
빌트인 토큰 (Built-in tokens)
9— 숫자 한 자리 ([0-9])a— 알파벳 한 자 ([A-Za-z])A— 대문자 한 자 ([A-Z])*— 영숫자 한 자 ([A-Za-z0-9])#— 숫자 또는 부호 ([-+0-9])
선택적 세그먼트 (Optional segments)
마지막 필수 문자 뒤에 ?를 붙이면 나머지 슬롯을 선택적으로 표시해요.
useMask({ mask: '(999) 999-9999? x9999' }) // Extension is optional
유틸리티 함수 (Utility functions)
다음 순수 함수들이 훅과 함께 내보내져요.
formatMask(raw, options)— 원시 값 문자열에 마스크 적용unformatMask(masked, options)— 마스킹된 값에서 모든 마스크 리터럴 제거isMaskComplete(masked, options)— 모든 필수 슬롯이 채워졌는지 확인generatePattern(mode, options)— HTMLpattern속성용 정규식 문자열 생성
import { formatMask, unformatMask, isMaskComplete } from '@mantine/hooks';
const options = { mask: '(999) 999-9999' };
formatMask('1234567890', options); // "(123) 456-7890"
unformatMask('(123) 456-7890', options); // "1234567890"
isMaskComplete('(123) 456-7890', options); // true
정의 (Definition)
interface UseMaskOptions {
// 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 on each keystroke, can return overrides for mask, tokens, or slotChar
modify?: (value: string) => Partial<Pick<UseMaskOptions, 'mask' | 'tokens' | 'slotChar'>> | undefined;
// Transform each character before validation and insertion
transform?: (char: string) => string;
// Character displayed in unfilled slots, "_" by default
slotChar?: string | null;
// Show mask pattern even when the field is empty and unfocused
alwaysShowMask?: boolean;
// Show mask placeholder on focus, true by default
showMaskOnFocus?: boolean;
// Clear value on blur when mask is incomplete, false by default
autoClear?: boolean;
// Sets aria-invalid on the input
invalid?: 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;
}
interface UseMaskReturnValue {
// Ref callback to attach to the input element
ref: React.RefCallback;
// Current masked display value
value: string;
// Current raw unmasked value
rawValue: string;
// Whether all required mask slots are filled
isComplete: boolean;
// Clear the input value and reset state
reset: () => void;
}
function useMask(options: UseMaskOptions): UseMaskReturnValue;
Exported types
UseMaskOptions와 UseMaskReturnValue 타입은 @mantine/hooks 패키지에서 내보내져요.
import type { UseMaskOptions, UseMaskReturnValue } from '@mantine/hooks';
더 알아보기 (Learn more)
- useLongPress — 길게 누르기
- useMediaQuery — 미디어 쿼리