PasswordInput
PasswordInput
사용자로부터 비밀번호 데이터를 입력받는 컴포넌트예요. 비밀번호 표시/숨기기 토글 버튼을 제공해요.
출처: 문서
본문
사용법 (Usage)
PasswordInput 컴포넌트는 Input 및 Input.Wrapper 컴포넌트 기능과 모든 input 요소 prop을 지원해요. PasswordInput 문서에는 컴포넌트가 지원하는 모든 기능이 포함되지는 않아요. 사용 가능한 모든 기능은 Input 문서를 참고해요.
import { PasswordInput } from '@mantine/core';
function Demo() {
return <PasswordInput label="Password" placeholder="Your password" />;
}
variant, size, radius, label, description, error 등의 표준 Input prop을 지원해요.
로딩 상태 (Loading state)
loading prop을 설정하면 로딩 인디케이터가 표시돼요. 기본적으로 로더는 인풋 오른쪽에 표시돼요. loadingPosition prop을 'left' 또는 'right'로 바꿔 위치를 변경할 수 있어요. API 호출, 검색, 검증 같은 비동기 작업에 유용해요.
import { PasswordInput } from '@mantine/core';
function Demo() {
return <PasswordInput label="Password" loading />;
}
제어 방식 (Controlled)
import { useState } from 'react';
import { PasswordInput } from '@mantine/core';
function Demo() {
const [value, setValue] = useState('');
return <PasswordInput value={value} onChange={(event) => setValue(event.currentTarget.value)} />;
}
비제어 방식 (Uncontrolled)
PasswordInput은 네이티브 input[type="password"]와 같은 방식으로 비제어 폼에서 사용할 수 있어요. 폼 제출 시 FormData 객체에 비밀번호 인풋 값을 포함하려면 name 속성을 설정해요. 비제어 폼에서 초기 값을 제어하려면 defaultValue prop을 사용해요.
FormData와 함께 비제어 PasswordInput을 사용하는 예시:
import { PasswordInput } from '@mantine/core';
function Demo() {
return (
<form
onSubmit={(event) => {
event.preventDefault();
const formData = new FormData(event.currentTarget);
console.log('Password value:', formData.get('password'));
}}
>
<PasswordInput name="password" />
<button type="submit">Submit</button>
</form>
);
}
표시 상태 제어 (Controlled visibility toggle)
visible과 onVisibilityChange prop으로 표시 상태를 제어할 수 있어요. 예를 들어 두 인풋 사이의 표시 상태를 동기화하는 데 사용할 수 있어요.
import { useDisclosure } from '@mantine/hooks';
import { PasswordInput, Stack } from '@mantine/core';
function Demo() {
const [visible, { toggle }] = useDisclosure(false);
return (
<Stack>
<PasswordInput label="Password" visible={visible} onVisibilityChange={toggle} />
<PasswordInput label="Confirm password" visible={visible} onVisibilityChange={toggle} />
</Stack>
);
}
표시 토글 아이콘 변경 (Change visibility toggle icon)
표시 토글 아이콘을 변경하려면 reveal prop을 받는 React 컴포넌트를 visibilityToggleIcon에 전달해요.
import { PasswordInput } from '@mantine/core';
import { EyeIcon, EyeSlashIcon } from '@phosphor-icons/react';
const VisibilityToggleIcon = ({ reveal }: { reveal: boolean }) =>
reveal ? <EyeSlashIcon size={16} /> : <EyeIcon size={16} />;
function Demo() {
return <PasswordInput label="Password" visibilityToggleIcon={VisibilityToggleIcon} />;
}
강도 측정기 예시 (Strength meter example)
Progress와 Popover 컴포넌트로 만든 비밀번호 강도 측정기 예시예요.
import { useState } from 'react';
import { XIcon, CheckIcon } from '@phosphor-icons/react';
import { PasswordInput, Progress, Text, Popover, Box } from '@mantine/core';
function PasswordRequirement({ meets, label }: { meets: boolean; label: string }) {
return (
<Text color={meets ? 'teal' : 'red'} size="sm" mt={7}>
{meets ? <CheckIcon size={12} /> : <XIcon size={12} />} {label}
</Text>
);
}
const requirements = [
{ re: /[0-9]/, label: 'Includes number' },
{ re: /[a-z]/, label: 'Includes lowercase letter' },
{ re: /[A-Z]/, label: 'Includes uppercase letter' },
{ re: /[$&+,:;=?@#|'<>.^*()%!-]/, label: 'Includes special symbol' },
];
function getStrength(password: string) {
let multiplier = password.length > 5 ? 0 : 1;
requirements.forEach((requirement) => {
if (!requirement.re.test(password)) {
multiplier += 1;
}
});
return Math.max(100 - (100 / (requirements.length + 1)) * multiplier, 10);
}
function Demo() {
const [popoverOpened, setPopoverOpened] = useState(false);
const [value, setValue] = useState('');
const checks = requirements.map((requirement, index) => (
<PasswordRequirement key={index} label={requirement.label} meets={requirement.re.test(value)} />
));
const strength = getStrength(value);
const color = strength === 100 ? 'teal' : strength > 50 ? 'yellow' : 'red';
return (
<Popover opened={popoverOpened} position="bottom" width="target" transitionProps={{ transition: 'pop' }}>
<Popover.Target>
<div onFocusCapture={() => setPopoverOpened(true)} onBlurCapture={() => setPopoverOpened(false)}>
<PasswordInput value={value} onChange={(event) => setValue(event.currentTarget.value)} label="Your password *" withAsterisk />
</div>
</Popover.Target>
<Popover.Dropdown>
<Progress color={color} value={strength} size={5} mb="xs" />
<PasswordRequirement label="Has at least 6 characters" meets={value.length > 5} />
{checks}
</Popover.Dropdown>
</Popover>
);
}
표시 토글 없이 사용 (Usage without visibility toggle)
표시 토글 버튼이 필요 없다면 TextInput 컴포넌트를 사용해요.
import { TextInput } from '@mantine/core';
function Demo() {
return <TextInput type="password" />;
}
왼쪽·오른쪽 섹션 (Left and right sections)
PasswordInput은 leftSection과 rightSection prop을 지원해요. 이 섹션들은 인풋 래퍼 안에서 절대 위치로 렌더링돼요. 아이콘, 인풋 컨트롤 또는 다른 요소를 표시하는 데 사용할 수 있어요.
섹션 스타일과 콘텐츠를 제어하려면 다음 prop을 사용할 수 있어요.
rightSection/leftSection– 인풋의 해당 쪽에 렌더링할 React 노드rightSectionWidth/leftSectionWidth– 오른쪽 섹션의 너비와 인풋 해당 쪽의 패딩을 제어해요. 기본적으로 컴포넌트sizeprop에 의해 제어돼요.rightSectionPointerEvents/leftSectionPointerEvents– 섹션의pointer-events속성을 제어해요. 비대화형 요소를 렌더링하고 싶다면none으로 설정해 클릭이 인풋으로 통과하게 해요.
rightSection prop을 사용하면 표시 토글 버튼은 렌더링되지 않아요.
import { PasswordInput } from '@mantine/core';
import { LockIcon } from '@phosphor-icons/react';
function Demo() {
const icon = <LockIcon size={16} />;
return (
<>
<PasswordInput leftSection={icon} label="With left section" defaultValue="secret" />
<PasswordInput rightSection={icon} label="With right section" defaultValue="secret" mt="md" />
</>
);
}
오류 상태 (Error state)
import { PasswordInput } from '@mantine/core';
function Demo() {
return (
<>
<PasswordInput label="Boolean error" error defaultValue="secret" />
<PasswordInput label="With error message" error="Invalid name" defaultValue="secret" mt="md" />
</>
);
}
성공 상태 (Success state)
import { PasswordInput } from '@mantine/core';
function Demo() {
return <PasswordInput label="Password Input" error="Looks good!" defaultValue="secret" />;
}
비활성 (Disabled)
disabled prop이 설정되면 표시 토글 버튼이 숨겨져요.
import { PasswordInput } from '@mantine/core';
function Demo() {
return <PasswordInput label="Disabled password input" disabled defaultValue="secret" />;
}
Styles API
PasswordInput은 Styles API를 지원해요. classNames prop으로 컴포넌트의 내부 요소에 스타일을 추가할 수 있어요.
Styles API 셀렉터:
wrapper– Input의 루트 요소input– 인풋 요소section– 왼쪽·오른쪽 섹션bottomSection– 인풋 테두리 하단 안쪽에 렌더링되는 아래쪽 섹션 요소root– 루트 요소label– 라벨 요소required– 라벨 안에 렌더링되는 필수 별표 요소description– 설명 요소error– 오류 요소success– 성공 요소innerInput– 실제 인풋 요소visibilityToggle– 표시 토글 버튼
요소 ref 가져오기 (Get element ref)
import { useRef } from 'react';
import { PasswordInput } from '@mantine/core';
function Demo() {
const ref = useRef<HTMLInputElement>(null);
return <PasswordInput ref={ref} />;
}
접근성 (Accessibility)
label prop 없이 PasswordInput을 사용하면 스크린 리더가 제대로 알리지 못해요.
// Inaccessible input – screen reader will not announce it properly
import { PasswordInput } from '@mantine/core';
function Demo() { return <PasswordInput placeholder="Password" />; }
aria-label을 설정하면 인풋을 접근 가능하게 만들 수 있어요. 이 경우 라벨은 보이지 않지만 스크린 리더가 알려줘요.
// Accessible input – it has aria-label
import { PasswordInput } from '@mantine/core';
function Demo() { return <PasswordInput aria-label="Password" />; }
label prop이 설정되어 있으면 인풋은 접근 가능하며 aria-label을 설정할 필요가 없어요.
표시 토글 버튼의 aria-label을 설정하려면 visibilityToggleButtonProps prop을 사용해요.
import { PasswordInput } from '@mantine/core';
function Demo() {
return <PasswordInput visibilityToggleButtonProps={{ 'aria-label': 'Toggle password visibility' }} />;
}
표시 토글 포커스 (Visibility toggle focus)
기본적으로 표시 토글 버튼은 탭 순서에서 제외돼요 (tabindex="-1"). 이는 네이티브 브라우저의 비밀번호 표시 컨트롤을 모방하고 폼 흐름을 중단시키지 않아요. Tab을 누르면 토글 버튼이 아니라 다음 필드로 포커스가 이동해요. 토글은 마우스, 터치, 그리고 탭 순서가 아니라 요소별로 탐색하는 보조 기술로 계속 조작할 수 있어요.
사용자가 Tab으로 토글에 도달하길 기대한다면 visibilityToggleFocusable prop을 설정해요. 그러면 버튼이 tabindex="0"을 받고 Enter 또는 Space로 활성화할 수 있어요.
import { PasswordInput, Stack, TextInput } from '@mantine/core';
function Demo() {
return (
<Stack>
<TextInput label="Email" placeholder="Email" />
<PasswordInput label="Password" placeholder="Password" visibilityToggleFocusable />
<TextInput label="Nickname" placeholder="Nickname" />
</Stack>
);
}
애플리케이션의 모든 PasswordInput에 이 동작을 적용하려면 theme에서 prop을 설정해요.
import { createTheme, PasswordInput } from '@mantine/core';
const theme = createTheme({
components: {
PasswordInput: PasswordInput.extend({
defaultProps: {
visibilityToggleFocusable: true,
},
}),
},
});