FileUploadField v1.0
Framer Component
Framer Component Documentation

FileUploadField

Drag-and-drop file uploads for Framer with real cloud storage, native form integration, live progress tracking, and complete visual customisation — zero code required.

6
Upload Providers
37
File Type Toggles
18
Colour Controls
0
Lines of Code Needed
ComponentsFileUploadField

Overview #

FileUploadField is a production-ready Framer component that adds fully functional file upload capability to any Framer site or prototype. Drop it inside a Framer Form, pick a cloud storage provider, and files uploaded by your visitors are sent directly to your storage bucket — with the resulting URL automatically included in your form submission data.

How it works

When a visitor selects or drops a file, the component uploads it directly from their browser to your chosen storage provider — no backend server required. The file travels from the visitor's device straight to the bucket using a technique called direct upload.

Once the upload finishes, the file's public URL is placed into a hidden form field. When the visitor submits the form, this URL is included alongside all other field data.

💡

The component stores URLs, not file content. Framer's own database never receives the file — only the link to where it lives in your chosen storage provider.

Quick Start #

The fastest path to a working upload field using Cloudinary — the recommended provider for most projects. Free plan includes 25 GB storage and 25 GB bandwidth/month.

  1. Create a free Cloudinary account

    Go to cloudinary.com → click Sign up for free. No credit card needed. Verify your email.

  2. Copy your Cloud Name

    After login, your Dashboard shows your Cloud Name — a short string like dxyz12abc. Copy it (it's case-sensitive).

  3. Create an unsigned Upload Preset

    Go to Settings (gear icon) → UploadUpload PresetsAdd upload preset. Give it a name like framer_uploads. Set Signing Mode to Unsigned. Save.

    🚨

    The preset must be Unsigned. A signed preset requires a backend server to generate signatures — uploads will fail if you use one.

  4. Configure in Framer

    Select the component → set Provider to Cloudinary ⭐ → paste your Cloud Name and preset name into the respective fields.

  5. Publish and test

    Publish your site and upload a file. Within seconds it appears in Cloudinary's Media Library. The file row shows a green success state. Done!

All Features #

Drag & Drop
Drag files from your desktop onto the zone. An animated highlight and inner glow appear on hover.
Click to Browse
Clicking the zone or the Browse button opens the native OS file picker.
Real Upload Progress
A live progress bar shows actual bytes transferred — not a fake animation — powered by the XHR progress event.
Multiple Files
Enable the Multiple Files toggle. Each file gets its own row and independent progress tracking.
Client-side Validation
File size and type checks run before any upload begins — instant feedback without wasting bandwidth.
Error & Retry
Failed uploads show a contextual error and a Retry button. Files can be removed from the list at any time.
Native Form Integration
A hidden <input> automatically carries uploaded URLs into Framer's form submission payload.
Full Customisation
Every colour, font, icon, spacing, and label is in the Properties panel. No code required.
Gradient Support
Gradient colour values work for backgrounds and buttons. Contexts that can't support gradients fall back safely.
Upload-first Timing
Files upload immediately on selection. By submit time the URL is already in the hidden field — no delays.
Keyboard Accessible
The drop zone is focusable via Tab, activatable with Enter or Space, and screen-reader labelled.
Config Guard
Missing credentials disable and dim the component — preventing silent runtime failures in production.

Form Integration #

FileUploadField is designed to sit inside Framer's native Form component. The uploaded file URL travels with the rest of the form data automatically on submit.

The hidden field mechanism

The component renders a <input type="hidden" name="file_url"> element. As uploads complete, this input's value updates with the public URL(s). Framer serialises it on submit exactly like any other input field.

For multiple files, URLs are joined by commas: https://cdn.example.com/a.pdf,https://cdn.example.com/b.pdf.

Setting the field name

The Form Field Name property (default: file_url) controls the key used in your submission data. Change it to match whatever your form integration (Airtable, email template, Notion, etc.) expects.

Timing

Uploads start the moment a file is selected — not on form submit. On a normal connection, files finish well before the submit button is clicked. For large files on slow connections, the hidden field may be empty if the user submits before completion.

⚠️

To guarantee all uploads complete before form submission, you'd need custom code to disable the Submit button until every file row shows a success state. This is outside the component's built-in scope.

File Validation #

All validation runs in the browser before any upload begins. Users get instant feedback without wasting bandwidth on rejected files.

Size limit

The Max Size property (default: 10 MB) rejects any file exceeding the limit. The error appears below the drop zone and the upload never starts. Set to a high value like 500 to effectively disable the limit.

File type restriction

The Allowed Types group has a toggle for each of the 37 supported extensions. The rule is simple:

  • All toggles off — any file type is accepted
  • One or more toggles on — only those types are permitted

The hint text below the drop zone updates automatically to reflect active constraints, e.g. Max 10 MB · PDF, JPG, PNG.

💡

Validation is two-layered: the browser file picker is filtered via the accept attribute, and a JavaScript check runs again when files are dropped. This prevents bypassing via file rename.

Text & Labels #

Every visible string is editable from the Text group in the Properties panel. Each label also has a paired Font control for family, size, weight, line height, and letter spacing.

PropertyDefaultWhere It Appears
title"Drop files here or click to browse"Main heading in the idle drop zone.
description"Supports any file type"Sub-text below the title. Leave blank to hide.
releaseText"Release to upload"Replaces the title while a file is being dragged over the zone.
button"Browse Files"Label on the Browse button (only shown if Show Button is on).
helper""Caption rendered below the entire component. Good for extra instructions.
uploadingText"Uploading…"Status text in the file row while uploading.
successMessage"Uploaded successfully"Status text after a successful upload, shown next to the file size.
errorMessage"Upload failed. Please try again."Fallback status text if the upload fails with no specific server error.

Colors #

The Colors group provides 18 individual colour controls. Framer's colour picker supports solid colours, opacity, and CSS gradients.

💡

Gradient values work for background-type properties (button, drop zone background). They cannot be applied as border or SVG stroke colours — the component falls back safely to a solid colour in those cases.

Drop zone

PropertyDefaultControls
background#F9F9F9Drop zone fill, idle state.
activeBg#EEF4FFDrop zone fill while dragging a file over it.
borderColor#DDDDDDDrop zone border, idle.
activeBorderColor#4F6EF7Drop zone border while dragging.
titleColor#333333Title text.
releaseTextColor#4F6EF7"Release to upload" text during drag.
descriptionColor#888888Sub-text below the title.
accent#4F6EF7Browse button background; icon circle; uploading icon.
accentText#FFFFFFText on the Browse button.
muted#888888Drop zone icon colour (idle state).
hintColor#888888Constraints hint text.
helperColor#888888Helper caption below the component.

File rows

PropertyDefaultControls
successColor#16A34ARow tint, icon, and status text on success.
errorColor#DC2626Row tint, icon, and status text on failure. Also validation errors.
progressColor#4F6EF7Filled portion of the progress bar.
fileNameColor#222222File name text in each row.
rowUploadingBg#F8F8F8Row background while uploading.
rowUploadingBorder#E5E5E5Row border while uploading.

Border & Shape #

PropertyDefaultDescription
border.width1.5 pxBorder thickness. Set to 0 to remove it.
border.styleDashedBorder style: Solid, Dashed, or Dotted.
border.radius12 pxDrop zone corner radius (also applied, capped at 10 px, to file rows).
buttonRadius8 pxBrowse button corner radius, independent of the drop zone.

Icons #

Icons appear in three places and are each configured independently.

Drop zone icon

Toggle Drop Zone Icon on/off. When on, choose: Cloud (default), Arrow Up, Paperclip, Folder, Custom Image (any Framer asset), or None. The icon sits in an accent-coloured circle that pulses on drag-hover.

File row success icon

Toggle Row File Icon on/off. When on, choose Check, File, Custom Image, or None. While uploading, a pulsing file icon appears automatically.

Remove button icon

Choose Trash (default), X / Close, Custom Image, or None. Setting to None hides the remove button entirely — users won't be able to remove files once added.

Layout & Spacing #

PropertyDefaultControls
dropZonePaddingV32 pxTop and bottom padding inside the drop zone.
dropZonePaddingH24 pxLeft and right padding inside the drop zone.
dropZoneGap12 pxVertical gap between elements inside the drop zone (icon → title → description → button → hint).
rowPaddingV10 pxTop and bottom padding inside each file row.
rowPaddingH12 pxLeft and right padding inside each file row.
rowListGap6 pxGap between multiple file rows.

Width fills 100% of the container. Height is automatic and grows as files are added. In single-file mode, the drop zone hides after the first file is selected to keep the UI clean.

Upload Providers #

Six providers are available. All do the same job — receive a file and return a public URL — but differ in setup, pricing, and use-case fit.

Public
tmpfiles.org — no sign-up, files deleted after 1 hour.
Testing only
☁️
Cloudinary
Media CDN. Best free tier. Recommended for most projects.
Free tier
🗄️
Supabase
Open-source backend with built-in storage buckets.
Free tier
📁
Google Drive
Upload via Google Apps Script. Free within Drive quota.
Free
🔶
Cloudflare R2
S3-compatible, zero egress fees. Needs a Worker.
Needs Worker
📤
Uploadcare
Dedicated upload CDN. Single public key setup.
Free tier

⚡ Public — tmpfiles.org #

🚨

For testing only. Files are publicly accessible and deleted after 1 hour. Never use for real user data or production forms.

Zero configuration required. Select it from the Provider dropdown and uploads work immediately — no sign-up, no credentials. Use it to verify that drag-and-drop, the progress bar, and the file row UI all look correct before connecting a real provider.

☁️ Cloudinary #

Recommended for most projects. Direct browser uploads, no backend required. Free plan: 25 GB storage, 25 GB bandwidth/month.

Required credentials

cloudinaryCloudName
string
Your cloud identifier shown on the dashboard. Looks like dxyz12abc.
cloudinaryUploadPreset
string
Name of an unsigned upload preset created in Cloudinary's settings.

Setup guide

  1. Create a free account

    Sign up at cloudinary.com. No credit card. Verify email.

  2. Copy your Cloud Name

    Log in → Dashboard. Your Cloud Name appears prominently — e.g. dxyz12abc. Copy it exactly.

  3. Create an unsigned upload preset

    Settings (gear icon) → UploadUpload PresetsAdd upload preset. Name it (e.g. framer_uploads), set Signing Mode to Unsigned, optionally set a Folder. Save.

  4. Configure in Framer

    Set Provider to Cloudinary ⭐ → paste Cloud Name and preset name.

  5. Publish and test

    Upload a file. Check Cloudinary's Media Library — it should appear within seconds.

🗄️ Supabase #

Open-source backend with built-in Storage. Free plan: 1 GB storage. Files upload directly from the browser via the Storage REST API.

Required credentials

supabaseProjectUrl
string
Your project URL, e.g. https://abcdefgh.supabase.co. Found in Settings → API.
supabaseAnonKey
string
The public anon key — a long eyJ… string. Found in Settings → API.
supabaseBucketName
string
Storage bucket to upload into. Default: uploads.

Setup guide

  1. Create a Supabase project

    Go to supabase.com, sign up, create a new project. Wait ~1 minute for provisioning.

  2. Get your Project URL and Anon Key

    Go to Settings → API. Copy the Project URL and the anon public key (the long eyJ… string).

  3. Create a public storage bucket

    In the sidebar, click Storage → New Bucket. Name it uploads. Check Public Bucket so files are accessible by URL. Create it.

    ⚠️

    Without Public Bucket enabled, the upload URL will return a 403 error when accessed.

  4. Add an RLS policy for anonymous uploads

    Supabase Row Level Security blocks all writes by default. You must add a policy explicitly.

    Storage → click your bucket → Policies → New policy → For full customisation:

    • Policy name: Allow public uploads
    • Allowed operation: INSERT
    • Target roles: anon
    • USING clause: true

    Click Review → Save policy.

    🚨

    This is the step most people miss. If uploads return 403, this RLS policy is almost certainly the cause.

  5. Configure in Framer

    Set Provider to Supabase and fill in the three fields.

💡

The component prepends a timestamp to every filename (1713456789_document.pdf) to prevent collisions when users upload files with identical names.

📁 Google Drive #

Files upload to a Drive folder via a Google Apps Script Web App you deploy from your own Google account. Free within Drive's storage quota, but requires more setup steps.

Required credentials

gdriveWebAppUrl
string
The .../exec URL of your deployed Google Apps Script.
gdriveFileLinkType
enum
downloadable — direct download link. preview — Google Drive preview page.

Setup guide

  1. Create a new Google Apps Script

    Go to script.google.comNew project. Delete all existing code and paste:

    Apps Script (JavaScript)
    function doPost(e) {
      var params = e.queryString ? parseQuery(e.queryString) : {};
      var filename = params.filename || "upload_" + Date.now();
      var mimeType = params.mimeType || "application/octet-stream";
      var bytes    = JSON.parse(e.postData.contents);
      var blob     = Utilities.newBlob(bytes, mimeType, filename);
      // To upload to a specific folder, replace the next line with:
      // var folder = DriveApp.getFolderById("YOUR_FOLDER_ID");
      var folder   = DriveApp.getRootFolder();
      var file     = folder.createFile(blob);
      file.setSharing(DriveApp.Access.ANYONE_WITH_LINK, DriveApp.Permission.VIEW);
      return ContentService
        .createTextOutput(JSON.stringify({ success: true, fileId: file.getId() }))
        .setMimeType(ContentService.MimeType.JSON);
    }
    function parseQuery(q) {
      return q.split("&").reduce(function(o, p) {
        var kv = p.split("=");
        o[decodeURIComponent(kv[0])] = decodeURIComponent(kv[1] || "");
        return o;
      }, {});
    }
  2. (Optional) Target a specific folder

    Find your folder's ID from its Drive URL: drive.google.com/drive/folders/THIS_IS_THE_ID. Replace getRootFolder() with getFolderById("PASTE_ID").

  3. Deploy as a Web App

    Click Deploy → New deployment → Web app.

    • Execute as: Me
    • Who has access: Anyone ← required

    Authorise Drive access when prompted. Copy the /exec URL after deploying.

    ⚠️

    After editing the script, always create a new deployment (not update the existing one) for changes to take effect.

  4. Configure in Framer

    Set Provider to Google Drive, paste the /exec URL into Web App URL, and choose your File Link Type.

🔶 Cloudflare R2 #

S3-compatible object storage with zero egress fees. Great for video or large assets. Requires deploying a small Cloudflare Worker as the upload endpoint.

Required credentials

r2WorkerUrl
string
Worker base URL, no trailing slash. e.g. https://file-upload-worker.yourname.workers.dev

Setup guide

  1. Create a Cloudflare account and R2 bucket

    Sign up at cloudflare.com. Go to R2 Object Storage → Create bucket. Name it e.g. framer-uploads.

  2. Enable public access

    Open your bucket → Settings → Public Access → Allow Access. Note the public domain (e.g. pub-xxxx.r2.dev).

  3. Create a Worker

    Workers & Pages → Create application → Create Worker. Name it file-upload-worker. Replace the default code with:

    Cloudflare Worker (JavaScript)
    export default {
      async fetch(request, env) {
        if (request.method === "OPTIONS")
          return new Response(null, { headers: cors() });
        if (request.method !== "POST")
          return new Response("Method not allowed", { status: 405 });
    
        const form = await request.formData();
        const file = form.get("file");
        if (!file) return new Response("No file", { status: 400 });
    
        const key = `${Date.now()}_${file.name}`;
        await env.BUCKET.put(key, file.stream(), {
          httpMetadata: { contentType: file.type }
        });
        // Replace with your pub-xxxx.r2.dev domain:
        const url = `https://YOUR-BUCKET-PUBLIC-DOMAIN/${key}`;
        return new Response(JSON.stringify({ url }), {
          headers: { "Content-Type": "application/json", ...cors() }
        });
      }
    };
    function cors() {
      return {
        "Access-Control-Allow-Origin": "*",
        "Access-Control-Allow-Methods": "POST, OPTIONS",
        "Access-Control-Allow-Headers": "Content-Type"
      };
    }
  4. Bind the R2 bucket to the Worker

    In the Worker → Settings → Variables → R2 Bucket Bindings → Add binding. Set the variable name to exactly BUCKET, select your R2 bucket. Save and redeploy.

  5. Configure in Framer

    Set Provider to Cloudflare R2 and paste the Worker URL (no trailing slash) into Worker URL.

📤 Uploadcare #

Dedicated upload CDN. Free plan: 3 GB storage. Simplest setup of all paid providers — just one public key.

Required credentials

uploadcarePublicKey
string
Your project's public key from the Uploadcare dashboard. e.g. demopublickey.

Setup guide

  1. Create an account

    Sign up at uploadcare.com. Create a new project from your dashboard.

  2. Copy your Public Key

    Go to API Keys. Copy the Public Key (not the Secret Key — never put the secret in browser code).

  3. Configure in Framer

    Set Provider to Uploadcare and paste your public key. Done.

💡

Uploaded files are served from https://ucarecdn.com/FILE_UUID/. Append transformation parameters to resize or convert images on the fly, e.g. /-/scale_crop/400x400/.

All Properties #

Complete reference. All properties are optional — the component ships with defaults for everything.

Behaviour

multiple
boolean
Allow multiple uploads. Default: false. In single-file mode the drop zone hides after the first file.
maxFileSizeMB
number
Max file size in MB. Default: 10. Range: 0.1–500.
allowedTypes
object
Toggle individual extensions. All off = any type accepted.
fieldName
string
name attribute of the hidden form field. Default: file_url.
showProgressBar
boolean
Show the progress bar in each file row. Default: true.

Provider

uploadDestination
enum
public / cloudinary / supabase / gdrive / r2 / uploadcare
cloudinaryCloudName
string
Required for Cloudinary.
cloudinaryUploadPreset
string
Required for Cloudinary. Must be unsigned.
supabaseProjectUrl
string
Required for Supabase. Format: https://xxxx.supabase.co.
supabaseAnonKey
string
Required for Supabase. The long eyJ… anon key.
supabaseBucketName
string
Bucket name. Default: uploads.
gdriveWebAppUrl
string
Required for Google Drive. The Apps Script /exec URL.
gdriveFileLinkType
enum
downloadable or preview.
r2WorkerUrl
string
Required for R2. Worker base URL, no trailing slash.
uploadcarePublicKey
string
Required for Uploadcare.

Drop Zone & Icons

showDropZoneIcon
boolean
Show/hide the drop zone icon.
iconStyle
enum
cloud / arrow / paperclip / folder / custom / none
iconImage
image
Custom icon image. Used only when iconStyle is custom.
iconSize
number
Icon size in px. Default: 40. Range: 16–120.
showButton
boolean
Show/hide the Browse Files button.
buttonRadius
number
Browse button corner radius. Default: 8 px.
showRowFileIcon
boolean
Show/hide the icon at the left of each file row.
uploadedRowIconStyle
enum
check / file / custom / none. Success state icon.
uploadedRowIcon
image
Custom success icon. Used only when style is custom.
uploadedRowIconSize
number
Success icon size. Default: 16 px.
removeIconStyle
enum
trash / x / custom / none. none hides the remove button.
removeIconImage
image
Custom remove icon. Used only when style is custom.
removeIconSize
number
Remove icon size. Default: 16 px.

Spacing

dropZonePaddingV
number
Drop zone top/bottom padding. Default: 32 px.
dropZonePaddingH
number
Drop zone left/right padding. Default: 24 px.
dropZoneGap
number
Gap between elements in the drop zone. Default: 12 px.
rowPaddingV
number
File row top/bottom padding. Default: 10 px.
rowPaddingH
number
File row left/right padding. Default: 12 px.
rowListGap
number
Gap between file rows. Default: 6 px.

Supported File Types #

37 extensions, each individually toggleable. All off = any type accepted.

ExtMIME TypeCategory
7zapplication/x-7z-compressedArchive
aacaudio/aacAudio
avivideo/x-msvideoVideo
avifimage/avifImage
csvtext/csvData
docapplication/mswordDocument
docxapplication/vnd.openxmlformats-officedocument.wordprocessingml.documentDocument
flacaudio/flacAudio
gifimage/gifImage
gzapplication/gzipArchive
heicimage/heicImage
htmltext/htmlWeb
jpgimage/jpegImage
jsonapplication/jsonData
mkvvideo/x-matroskaVideo
movvideo/quicktimeVideo
mp3audio/mpegAudio
mp4video/mp4Video
oggaudio/oggAudio
pdfapplication/pdfDocument
pngimage/pngImage
pptapplication/vnd.ms-powerpointDocument
pptxapplication/vnd.openxmlformats-officedocument.presentationml.presentationDocument
rarapplication/vnd.rarArchive
svgimage/svg+xmlImage
tarapplication/x-tarArchive
txttext/plainText
wavaudio/wavAudio
webmvideo/webmVideo
webpimage/webpImage
xlsapplication/vnd.ms-excelData
xlsxapplication/vnd.openxmlformats-officedocument.spreadsheetml.sheetData
xmlapplication/xmlData
zipapplication/zipArchive

Troubleshooting #

Drop zone is greyed out and unclickable

Missing provider credentials detected. Check that all required fields for your chosen provider are filled in the Properties panel.

Upload fails — "Network error" or HTTP 403

Almost always a CORS issue. Provider-specific fixes:

  • Cloudinary — upload preset must be Unsigned.
  • Supabase — add an RLS INSERT policy for the anon role on the bucket.
  • Cloudflare R2 Worker — ensure the Worker returns Access-Control-Allow-Origin: * and handles OPTIONS preflight.
  • Google Drive — Web App must be deployed with access set to Anyone.

File URL missing from form submission

Either the form was submitted before the upload finished (wait for the green success state), or the Form Field Name property doesn't match the key your integration expects.

File picker doesn't open on click

Expected behaviour in Framer's canvas preview — browsers block file picker triggers in sandboxed iframes. Test on the published live site URL.

Type validation accepts files it shouldn't

If all type toggles are off, any file is accepted. To restrict types, turn at least one toggle on — only enabled types will be permitted.

Google Drive link returns 403

Your Google Workspace organisation may have external link sharing disabled. Try a personal Gmail account or ask your admin to allow external sharing.

Supabase URL returns 400 or 404

The bucket is likely not set to public. Go to Supabase Storage → your bucket → Settings → enable Public Bucket.

How to split multiple URLs in automations

Multiple URLs are comma-separated: https://cdn.../a.pdf,https://cdn.../b.pdf. In Zapier or Make, use a "Split text" step with , as the delimiter. In code: value.split(",").

For any issue not listed here, open the browser developer console (F12 → Console) and look for specific error messages. HTTP status codes like 400, 401, 403, or 413 each point to a specific configuration step that the error text will describe.

FileUploadField · Framer Component April 2026