FileUpload

Невизуальная обёртка над произвольным триггером — как правило, кнопкой. Клик по триггеру открывает системный диалог выбора файлов. Используйте, когда загрузка — вспомогательное действие в форме или toolbar, и не нужна отдельная зона перетаскивания.

Когда использовать

  • Кнопка «Загрузить файлы» рядом с другими полями формы.
  • Иконка-загрузка в toolbar.
  • Скрытый триггер, когда загрузка инициируется программно через клик на дочерний элемент.

Когда не подходит: если нужна явная зона drag-n-drop — используйте Dropzone или HiddenDropZone.

Анатомия

Upload mode

single — один файл за раз, повторный выбор заменяет предыдущий; multiple — батч-загрузка, файлы накапливаются.

Поле формы

FileUpload проксирует нативные атрибуты <input type="file"> на скрытый input — компонент работает как полноценное поле формы:

  • name, id, required, capture, form — стандартные атрибуты; id связывает input с <label htmlFor>.
  • innerRef — ссылка на нативный input (для интеграции с react-hook-form: ref из register(name)).
  • onChange — нативный onChange input, вызывается до валидации с исходным событием (точка интеграции с form-библиотеками).
  • disabled — деактивирует триггер и input.

Валидация

Ограничения accept (MIME-тип, шаблон image/* или расширение .pdf; строка или массив) и maxSize (байты) разбивают выбранные файлы на две группы:

  • принятые уходят в onFilesUpload(files);
  • отклонённые — в onFilesReject(rejections) с причиной maxSize или mime.

Размер проверяется раньше типа: превысивший лимит файл отклоняется с причиной maxSize.

Установка

pnpm add @cloud-ru/ds-dropzone
import { FileUpload } from '@cloud-ru/ds-dropzone'

Примеры использования

Кнопка-триггер

Кнопка-триггерFileUpload оборачивает Button
tsx
import { Button } from '@cloud-ru/ds-button';
import { FileUpload } from '@cloud-ru/ds-dropzone';
import { useState } from 'react';

export function FileUploadBasic() {
  const [files, setFiles] = useState<File[]>([]);

  return (
    <div style={{ display: 'flex', gap: 12, flexWrap: 'wrap', alignItems: 'center' }}>
      <FileUpload onFilesUpload={setFiles}>
        <Button type='button' label='Загрузить файлы' />
      </FileUpload>
      {files.length > 0 && <span>Выбрано: {files.map(f => f.name).join(', ')}</span>}
    </div>
  );
}

Поле формы с валидацией

Поле формы с валидациейname/id/required, accept + maxSize, отказ через onFilesReject
tsx
import { Button } from '@cloud-ru/ds-button';
import { FileRejection, FileUpload } from '@cloud-ru/ds-dropzone';
import { useState } from 'react';

const MAX_SIZE = 5 * 1024 * 1024;

export function FileUploadFormField() {
  const [file, setFile] = useState<File | null>(null);
  const [error, setError] = useState<string | null>(null);

  const handleReject = (rejections: FileRejection[]) => {
    const [first] = rejections;
    setError(first?.reason === 'maxSize' ? 'Файл больше 5 МБ' : 'Недопустимый тип файла');
  };

  return (
    <div style={{ display: 'flex', gap: 12, flexWrap: 'wrap', alignItems: 'center' }}>
      <FileUpload
        name='resume'
        id='resume'
        required
        mode='single'
        accept={['.pdf', '.doc', '.docx']}
        maxSize={MAX_SIZE}
        onFilesReject={handleReject}
        onFilesUpload={files => {
          if (!files.length) return;
          setError(null);
          setFile(files[0]);
        }}
      >
        <Button type='button' label='Прикрепить резюме' />
      </FileUpload>
      {file && <span>{file.name}</span>}
      {error && <span>{error}</span>}
    </div>
  );
}

Props

Types

PropsFileUploadProps
PropTypeDefaultRequiredDescription
acceptAcceptInputnoРазрешённые типы файлов: MIME-тип (`image/png`), шаблон (`image/*`) или расширение (`.pdf`). Строка (через запятую, как нативный `accept`) или массив. Задаёт нативный `accept` и валидацию.
childrenReactElement<any, string | JSXElementConstructor<any>>yesТриггер открытия диалога выбора файлов (кнопка / лейбл). Клонируется, к нему добавляется `onClick`.
data-test-idstringno
disabledbooleanfalsenoДеактивирует триггер и input.
innerRefRef<HTMLInputElement>noСсылка на нативный `<input type="file">` — для интеграции с формами (react-hook-form `ref`).
maxSizenumbernoМаксимальный размер одного файла в байтах. Превысившие уходят в `onFilesReject`.
mode"multiple" | "single"multiplenoРежим выбора файлов
onChangeChangeEventHandler<HTMLInputElement>noНативный `onChange` скрытого input. Вызывается до валидации с исходным событием — точка интеграции с react-hook-form и другими form-библиотеками.
onFilesReject((rejections: FileRejection[]) => void)noКолбек с отклонёнными файлами и причиной отказа (`maxSize` / `mime`). Вызывается только когда задан `maxSize` и/или `accept` и есть отклонённые файлы.
onFilesUpload(files: File[]) => voidyesКолбек с принятыми файлами (прошедшими проверку `maxSize` и `accept`).

Unions

Types

FileUploadProps

Unions

Storybook

Figma