Dropzone

Native file selection and drag-and-drop with optional Active Storage direct uploads.

Source
app/components/nitro_kit/dropzone.rb
API
NitroKit::Dropzone.new(id:, name:, direct_upload:, multiple:, accept:, max_files:, max_bytes:)

Upload modes

Both modes retain a labelled native file input and ordinary multipart form submission.

Active Storage direct upload

Selection starts a direct upload, writes signed blob IDs, and keeps the form unavailable until uploads settle.

Viewport640 px · sm
Rubytest/dummy/app/components/gallery/components/dropzone_page.rb
form_with(
  scope: :upload,
  url: gallery_upload_submissions_path,
  builder: NitroKit::FormBuilder,
  id: "gallery-dropzone-direct-form",
  data: { turbo: false }
) do |form|
  form.dropzone(
    :files,
    id: "gallery-dropzone-direct",
    title: "Upload supporting evidence",
    description: "Up to two text or PNG files, each no larger than 2 MB.",
    multiple: true,
    accept: "text/plain,image/png",
    max_files: 2,
    max_bytes: 2 * 1024 * 1024,
    required: true
  )
  form.submit("Save direct upload", id: "gallery-dropzone-direct-submit")
end

Ordinary multipart upload

With direct upload disabled, dropped and selected files stay on the native input for the normal form request.

Viewport640 px · sm
Rubytest/dummy/app/components/gallery/components/dropzone_page.rb
form_with(
  scope: :upload,
  url: gallery_upload_submissions_path,
  builder: NitroKit::FormBuilder,
  id: "gallery-dropzone-multipart-form",
  data: { turbo: false }
) do |form|
  form.dropzone(
    :files,
    id: "gallery-dropzone-multipart",
    title: "Add source files",
    description: "Choose up to three text or PNG files.",
    direct_upload: false,
    multiple: true,
    accept: "text/plain,image/png",
    max_files: 3,
    max_bytes: 1024 * 1024
  )
  form.submit("Submit files", id: "gallery-dropzone-multipart-submit")
end

Shared form uploads

Each Dropzone keeps the shared form unavailable only while its own upload is active.

Viewport640 px · sm
Rubytest/dummy/app/components/gallery/components/dropzone_page.rb
form_with(
  scope: :upload,
  url: gallery_upload_submissions_path,
  builder: NitroKit::FormBuilder,
  id: "gallery-dropzone-shared-form",
  data: { turbo: false }
) do |form|
  form.dropzone(
    :primary_file,
    id: "gallery-dropzone-shared-primary",
    title: "Upload primary evidence",
    accept: "text/plain"
  )
  form.dropzone(
    :secondary_file,
    id: "gallery-dropzone-shared-secondary",
    title: "Upload secondary evidence",
    accept: "text/plain"
  )
  form.submit("Save both uploads", id: "gallery-dropzone-shared-submit")
  form.button(
    "Unavailable action",
    id: "gallery-dropzone-shared-disabled-submit",
    type: :submit,
    disabled: true
  )
end

Availability and constraints

Required, multiple, disabled, type, count, and byte limits are explicit Ruby options and native attributes.

Constraint states

Required single file
Disabled
Viewport640 px · sm
Rubytest/dummy/app/components/gallery/components/dropzone_page.rb
sample("Required single file", slug: "required-single") do
  render NitroKit::Dropzone.new(
    id: "gallery-dropzone-required",
    name: "evidence[file]",
    title: "Choose one PDF",
    description: "The browser keeps this requirement without JavaScript.",
    direct_upload: false,
    accept: "application/pdf",
    max_bytes: 512 * 1024,
    required: true
  )
end

sample("Disabled", slug: "disabled") do
  render NitroKit::Dropzone.new(
    id: "gallery-dropzone-disabled",
    name: "archive[file]",
    title: "Archived upload",
    description: "Uploads are unavailable while this record is archived.",
    disabled: true
  )
end