FileInput

FileInput (파일 입력)

FileInput 컴포넌트는 사용자로부터 파일을 입력받는 컴포넌트예요. Input과 Input.Wrapper 컴포넌트의 기능과 모든 input 요소 props를 지원해요.

출처: 문서

본문

FileInput 컴포넌트는 Input과 Input.Wrapper 컴포넌트의 기능과 모든 input 요소 props를 지원해요. FileInput 문서는 컴포넌트가 지원하는 모든 기능을 담고 있지 않아요. 사용 가능한 모든 기능은 Input 문서를 참고해요.

import { FileInput } from '@mantine/core';

function Demo() {
  return (
    <FileInput
      label="Input label"
      description="Input description"
      placeholder="Input placeholder"
    />
  );
}

로딩 상태 (Loading state)

loading prop을 설정하면 로딩 인디케이터를 표시해요. 기본적으로 로더는 input 오른쪽에 표시돼요. loadingPosition prop을 'left'나 'right'로 바꿔 위치를 조절할 수 있어요. API 호출, 검색, 검증 같은 비동기 작업에 유용해요.

import { FileInput } from '@mantine/core';

function Demo() {
  return <FileInput placeholder="Upload file" loading />;
}

제어 사용 (Controlled)

multiple이 false일 때:

import { useState } from 'react';
import { FileInput } from '@mantine/core';

function Demo() {
  const [value, setValue] = useState<File | null>(null);
  return <FileInput value={value} onChange={setValue} />;
}

multiple이 true일 때:

import { useState } from 'react';
import { FileInput } from '@mantine/core';

function Demo() {
  const [value, setValue] = useState<File[]>([]);
  return <FileInput multiple value={value} onChange={setValue} />;
}

비제어 사용 (Uncontrolled)

FileInput은 네이티브 input[type="file"]처럼 비제어 폼에서도 사용할 수 있어요. 폼 제출 시 FormData 객체에 파일 입력 값을 포함하려면 name 속성을 설정해요. 비제어 폼에서 초기 값을 제어하려면 defaultValue prop을 사용해요.

FormData와 함께 비제어 FileInput을 사용하는 예시:

import { FileInput } from '@mantine/core';

function Demo() {
  return (
    <form
      onSubmit={(event) => {
        event.preventDefault();
        const formData = new FormData(event.currentTarget);
        const files = formData.getAll('file');
        console.log('File input value:', files);
      }}
    >
      <FileInput label="Upload your file" name="file" />
      <button type="submit">Submit</button>
    </form>
  );
}

여러 파일 (Multiple)

multiple을 설정하면 사용자가 두 개 이상의 파일을 선택할 수 있어요.

import { FileInput } from '@mantine/core';

function Demo() {
  return <FileInput label="Upload files" placeholder="Upload files" multiple />;
}

Accept

accept prop으로 특정 mime 타입으로 파일 선택을 제한할 수 있어요.

import { FileInput } from '@mantine/core';

function Demo() {
  return (
    <FileInput accept="image/png,image/jpeg" label="Upload files" placeholder="Upload files" />
  );
}

지우기 가능 (Clearable)

clearable prop을 설정하면 파일이 선택되었을 때 input 오른쪽 섹션에 지우기 버튼이 표시돼요. 커스텀 right section을 정의하면 지우기 버튼이 렌더링되지 않는다는 점을 참고해요.

import { FileInput } from '@mantine/core';

function Demo() {
  return <FileInput clearable label="Upload files" placeholder="Upload files" />;
}

지우기 섹션 모드 (Clear section mode)

clearSectionMode prop은 지우기 버튼과 rightSection이 어떻게 렌더링되는지 결정해요.

  • 'both'(기본) – 지우기 버튼과 rightSection을 모두 렌더링해요
  • 'rightSection' – 사용자가 제공한 rightSection만 렌더링하고 지우기 버튼은 무시해요
  • 'clear' – 지우기 버튼만 렌더링하고 rightSection은 무시해요
import { CaretDownIcon } from '@phosphor-icons/react';
import { FileInput, Stack } from '@mantine/core';

function Demo() {
  return (
    <Stack>
      <FileInput
        label="clearSectionMode='both' (default)"
        placeholder="Pick file"
        clearable
        rightSection={<CaretDownIcon size={16} />}
        clearSectionMode="both"
      />

      <FileInput
        label="clearSectionMode='rightSection'"
        placeholder="Pick file"
        clearable
        rightSection={<CaretDownIcon size={16} />}
        clearSectionMode="rightSection"
      />

      <FileInput
        label="clearSectionMode='clear'"
        placeholder="Pick file"
        clearable
        rightSection={<CaretDownIcon size={16} />}
        clearSectionMode="clear"
      />
    </Stack>
  );
}

커스텀 값 컴포넌트

valueComponent prop으로 선택된 파일이 어떻게 표시되는지 커스터마이즈할 수 있어요.

import { FileInput, FileInputProps, Pill } from '@mantine/core';

const ValueComponent: FileInputProps['valueComponent'] = ({ value }) => {
  if (value === null) {
    return null;
  }

  if (Array.isArray(value)) {
    return (
      <Pill.Group>
        {value.map((file, index) => (
          <Pill key={index}>{file.name}</Pill>
        ))}
      </Pill.Group>
    );
  }

  return <Pill>{value.name}</Pill>;
};

function Demo() {
  return (
    <FileInput
      label="Upload files"
      placeholder="Upload files"
      multiple
      valueComponent={ValueComponent}
    />
  );
}

오류 상태 (Error state)

error prop으로 오류 메시지를 표시할 수 있어요.

import { FileInput } from '@mantine/core';

function Demo() {
  return (
    <>
      <FileInput label="Boolean error" placeholder="Boolean error" error />
      <FileInput
        mt="md"
        label="With error message"
        placeholder="With error message"
        error="Invalid name"
      />
    </>
  );
}

성공 상태 (Success state)

success prop으로 성공 메시지를 표시할 수 있어요.

import { FileInput } from '@mantine/core';

function Demo() {
  return <FileInput label="Upload file" success="File is valid" />;
}

비활성 상태 (Disabled state)

import { FileInput } from '@mantine/core';

function Demo() {
  return <FileInput disabled label="Disabled input" placeholder="Disabled input" />;
}

왼쪽·오른쪽 섹션 (Left and right sections)

FileInput은 leftSection과 rightSection prop을 지원해요. 이 섹션들은 input wrapper 안에 절대 위치(absolute positioning)로 렌더링돼요. 아이콘이나 다른 요소를 표시하는 데 사용할 수 있어요.

섹션 스타일과 콘텐츠를 제어하는 props:

  • rightSection / leftSection – input의 해당 쪽에 렌더링할 React 노드
  • rightSectionWidth/leftSectionWidth – right section의 너비와 input 해당 쪽의 패딩을 제어해요. 기본적으로 컴포넌트 size prop으로 제어돼요.
  • rightSectionPointerEvents/leftSectionPointerEvents – 섹션의 pointer-events 속성을 제어해요. 상호작용하지 않는 요소를 렌더링하려면 none으로 설정해 클릭이 input을 통과하게 해요.
import { FileInput } from '@mantine/core';
import { FileTextIcon } from '@phosphor-icons/react';

function Demo() {
  const icon = <FileTextIcon size={18} />;

  return (
    <>
      <FileInput
        leftSection={icon}
        label="Attach your CV"
        placeholder="Your CV"
        leftSectionPointerEvents="none"
      />
      <FileInput
        rightSection={icon}
        label="Attach your CV"
        placeholder="Your CV"
        rightSectionPointerEvents="none"
        mt="md"
      />
    </>
  );
}

Styles API

FileInput은 Styles API를 지원해요. classNames prop으로 내부 요소에 스타일을 추가할 수 있어요.

주요 선택자는 다음과 같아요.

  • wrapper – Input의 루트 요소
  • input – input 요소
  • section – 왼쪽·오른쪽 섹션
  • bottomSection – input border 아래쪽에 렌더링되는 하단 섹션 요소
  • root – 루트 요소
  • label – 라벨 요소
  • required – 라벨 안에 렌더링되는 필수 별표 요소
  • description – 설명 요소
  • error – 오류 요소
  • success – 성공 요소
  • placeholder – 플레이스홀더 텍스트

요소 ref 가져오기

import { useRef } from 'react';
import { FileInput } from '@mantine/core';

function Demo() {
  const ref = useRef<HTMLButtonElement>(null);
  return <FileInput ref={ref} />;
}

접근성 (Accessibility)

FileInput을 label prop 없이 사용하면 스크린 리더가 제대로 인지하지 못해요.

import { FileInput } from '@mantine/core';

// Inaccessible input – screen reader will not announce it properly
function Demo() {
  return <FileInput />;
}

aria-label을 설정하면 input을 접근 가능하게 만들 수 있어요. 이 경우 라벨은 보이지 않지만 스크린 리더가 읽어줘요.

import { FileInput } from '@mantine/core';

// Accessible input – it has aria-label
function Demo() {
  return <FileInput aria-label="My input" />;
}

label prop이 설정되면 input은 접근 가능하며 aria-label을 설정할 필요가 없어요.

import { FileInput } from '@mantine/core';

// Accessible input – it has associated label element
function Demo() {
  return <FileInput label="My input" />;
}

FileInputProps 타입

FileInputProps 타입은 단일 타입 인자를 받는 제네릭 인터페이스예요. 인자는 multiple 값이에요.

import type { FileInputProps } from '@mantine/core';

type SingleInputProps = FileInputProps<false>;
type MultipleInputProps = FileInputProps<true>;

더 알아보기 (Learn more)

  • Input — 입력 컴포넌트 기반 문서
  • FileButton — 파일 선택 버튼 컴포넌트
  • Pill — 파일 이름 표시용 pill 컴포넌트