File Dropzone
공통 컴포넌트사용자 화면과 관리자 화면 모두에서 쓰입니다.
끌어다 놓거나 눌러서 첨부파일을 고르는 영역입니다.
파일을 끌어다 놓거나 눌러서 선택하는 첨부파일 영역입니다. 고른 파일을 목록으로 보여 주고(이미지는 미리보기), 형식·크기·개수를 검사하고, 개별 삭제를 지원합니다. 서버로 올리는 일은 하지 않고, 고른 파일 목록만 부모에게 알려 줍니다.
Preview
아무 파일이나 끌어다 놓아 보세요. (허용: 이미지와 PDF, 파일당 5MB, 최대 4개)
파일을 끌어다 놓거나 눌러서 선택하세요
image/*,.pdf · 파일당 최대 5MB · 최대 4개
tsx
const [files, setFiles] = useState<File[]>([]);
<FileDropzone
value={files}
onChange={setFiles}
accept="image/*,.pdf"
maxSizeMB={5}
maxFiles={4}
/>What users can do
- 끌어다 놓기: 영역 위로 파일을 끌면 테두리가 파랗게 바뀌고 "여기에 놓으세요"가 나옵니다.
- 눌러서 선택: 영역을 누르거나 키보드로
Enter/Space를 누르면 파일 선택 창이 열립니다. - 목록 확인: 파일 이름과 크기가 보이고, 이미지는 작은 미리보기가 함께 나옵니다.
- 삭제: 각 파일의 ✕로 하나씩 뺍니다.
Validation
조건에 맞지 않는 파일은 목록에 들어가지 않고, 이유가 빨간 글씨로 나옵니다. 맞는 파일은 그대로 추가됩니다.
| 조건 | 메시지 |
|---|---|
| 형식이 accept와 다름 | 파일이름: 허용되지 않는 형식입니다. |
| maxSizeMB 초과 | 파일이름: 5MB를 넘습니다. |
| maxFiles 초과 | 파일은 최대 4개까지 올릴 수 있습니다. |
브라우저의 검사는 편의일 뿐입니다. 파일 이름이나 형식은 조작할 수 있으므로, 서버가 파일의 실제 내용(형식), 크기, 개수를 다시 검사하고 안전한 이름으로 저장해야 합니다.
Single file (image)
multiple={false}이면 파일을 하나만 받고, 새 파일을 고르면 기존 파일이 교체됩니다. 프로필 사진 같은 곳에 알맞습니다.
프로필 이미지를 끌어다 놓으세요
image/* · 파일당 최대 2MB
tsx
<FileDropzone
value={image}
onChange={setImage}
multiple={false}
accept="image/*"
maxSizeMB={2}
label="프로필 이미지를 끌어다 놓으세요"
/>Upload to your server
올리는 부분은 서비스가 만듭니다. 킷의 api 클라이언트를 쓰면 로그인 토큰이 자동으로 붙습니다.
tsx
import { api } from "@/meerkit";
async function upload(files: File[]) {
const form = new FormData();
files.forEach((f) => form.append("files", f));
await api.post("/uploads", form); // Content-Type은 브라우저가 알아서 설정
}- 올린 뒤 서버가 돌려준 주소를
User.avatar_url같은 필드에 저장하면UserAvatar가 바로 보여 줍니다. - 큰 파일은 진행률 표시와 업로드 취소를 서비스에서 추가하세요.
- 서버는 저장 전에 형식·크기 검사, 파일 이름 정리, (필요하면) 바이러스 검사를 합니다.
Accept rules
| 값 | 뜻 |
|---|---|
image/* | 모든 이미지 |
image/png | PNG만 |
.pdf | 확장자가 .pdf인 파일 |
image/*,.pdf | 쉼표로 여러 규칙을 함께 허용 |
Props
| Prop | Type | 설명 |
|---|---|---|
value필수 | File[] | 현재 고른 파일 목록. |
onChange필수 | (files: File[]) => void | 파일이 추가·삭제될 때 새 목록을 전달합니다. |
accept | string | 허용 형식. input의 accept와 같은 문법. |
multiple | boolean | false면 한 개만 받고 교체합니다. 기본 true. |
maxFiles | number | multiple일 때 최대 개수. 기본 5. |
maxSizeMB | number | 파일 하나의 최대 크기(MB). 기본 10. |
label | string | 영역 안의 안내 문구. |
hint | string | 작은 보조 문구. 없으면 형식·크기·개수를 자동으로 보여 줍니다. |
disabled | boolean | 잠금. |
Accessibility
- 영역은
role="button"이며Tab으로 포커스가 가고Enter/Space로 열립니다. 마우스가 없어도 쓸 수 있습니다. - 삭제 버튼에는
aria-label="파일이름 삭제"가 있고, 오류는role="alert"로 읽힙니다. - 같은 파일을 지웠다가 다시 고를 수 있습니다.
첨부가 필요한 폼(문의, 게시글 등)에서는 이 컴포넌트를 폼 안에 넣고, 제출할 때 files를 FormData에 담아 보내면 됩니다.
