Skip to content

Conversation

@LeticiaBN
Copy link

@LeticiaBN LeticiaBN commented Oct 14, 2025

🗂️ Add Folder Upload Support to dcc.Upload Component

This PR adds folder upload capability to the dcc.Upload component, addressing issue #3464. Users can now select and upload entire folders (including nested subfolders) via both click-to-select and drag-and-drop methods when multiple=True, significantly reducing user effort when uploading multiple files from various directories.

✨ Key Features

  • Drop-in improvement - Folder upload automatically enabled when multiple=True
  • No new props required - Backward compatible with existing code
  • Click-to-select folder support using webkitdirectory HTML attribute
  • Drag-and-drop folder support using FileSystem API (webkitGetAsEntry())
  • Recursive folder traversal automatically extracts all files from nested directories
  • Respects accept prop - Filters uploaded files by type (extensions, MIME types, wildcards)
  • Preserved folder hierarchy in filenames (e.g., folder/subfolder/file.txt)
  • Graceful degradation in browsers without folder support
  • Same output API as multiple file uploads
  • Comprehensive integration tests added

🌐 Browser Support

Browser Click-to-Select Drag-and-Drop
Chrome 86+
Edge 86+
Opera 72+
Safari ⚠️ Files only ⚠️ Files only
Firefox ⚠️ Files only ⚠️ Files only

Browsers without support automatically fall back to file-only mode

📝 Example Usage

Basic Folder Upload

import dash
from dash import dcc, html, Input, Output

app = dash.Dash(__name__)

app.layout = html.Div([
    dcc.Upload(
        id='upload-folder',
        children=html.Div(['Drag and Drop or Select Folder']),
        multiple=True,  # ⭐ Folder upload automatically enabled!
    ),
    html.Div(id='output')
])

@app.callback(
    Output('output', 'children'),
    Input('upload-folder', 'contents'),
    Input('upload-folder', 'filename')
)
def display_files(contents, filenames):
    if filenames:
        return html.Ul([html.Li(f) for f in filenames])
    return "No files uploaded"

if __name__ == '__main__':
    app.run_server(debug=True)

With File Type Filtering

dcc.Upload(
    id='upload-folder',
    children=html.Div(['Select Folder (images only)']),
    multiple=True,
    accept='image/*',  # ✅ Only image files from folders will be uploaded
)

🔧 Implementation Details

What Changed

React Components (Upload.react.js):

  • Added fileMatchesAccept() method to filter files based on accept prop
  • Implemented traverseFileTree() for recursive folder traversal with filtering
  • Added custom getDataTransferItems() handler for drag-and-drop folder support
  • Applied webkitdirectory, directory, and mozdirectory attributes when multiple=True

Python Wrapper:

  • Updated multiple prop documentation to mention folder upload capability
  • No API changes - existing code automatically benefits from folder support

Testing:

  • Added test_upfd001_folder_upload_with_multiple - verifies folder upload when multiple=True
  • Added test_upfd002_folder_upload_disabled_with_single - verifies no folder upload when multiple=False
  • Tests follow Dash testing best practices with explicit waits and descriptive assertions

Technical Details

This implementation uses webkitdirectory (HTML attribute) and webkitGetAsEntry() (FileSystem API) for the following reasons:

  • Compatibility with react-dropzone v4.1.2: The current Dash codebase uses react-dropzone v4.1.2, which integrates seamlessly with these APIs
  • Broad browser support: webkitdirectory and FileSystem API have been supported in Chrome/Edge since 2011
  • No breaking changes: Works with existing accept and multiple props
  • Progressive enhancement: Gracefully degrades to file-only mode in unsupported browsers

Addressing Reviewer Feedback

This PR addresses all reviewer feedback from the initial submission:

  1. Drop-in replacement: Removed useFsAccessApi prop in favor of automatic folder support with multiple=True
  2. Respects accept prop: Implemented full filtering for file extensions, MIME types, and wildcards
  3. Fixed failing tests: Replaced problematic tests with focused, reliable integration tests

Contributor Checklist

  • I have broken down my PR scope into the following TODO tasks
    • Implement click-to-select folder support with webkitdirectory when multiple=True
    • Implement drag-and-drop folder support with FileSystem API
    • Add recursive folder traversal logic
    • Add accept prop filtering for folder contents
    • Update component documentation
    • Add integration tests following Dash testing best practices
    • Address reviewer feedback
    • Fix linting issues
  • I have run the tests locally and they passed
  • I have added entry in the CHANGELOG.md

Closes #3464


@LeticiaBN LeticiaBN force-pushed the feat/add-folder-upload-support branch 2 times, most recently from 95c27bb to 08f7541 Compare October 14, 2025 12:30
- Add useFsAccessApi prop to enable folder selection
- Support both click-to-select and drag-and-drop folder uploads
- Recursively traverse folder structures using FileSystem API
- Preserve folder hierarchy in uploaded filenames
- Maintain backward compatibility (default: False)
- Add integration tests for folder upload functionality

Closes plotly#3464
@LeticiaBN LeticiaBN force-pushed the feat/add-folder-upload-support branch from 08f7541 to 7a25fa9 Compare October 14, 2025 12:55
@gvwilson gvwilson requested a review from KoolADE85 October 14, 2025 22:21
@gvwilson gvwilson added feature something new P2 considered for next cycle community community contribution labels Oct 14, 2025
@gvwilson
Copy link
Contributor

@T4rk1n @KoolADE85 what do you think?

@KoolADE85
Copy link
Contributor

Hey @LeticiaBN, thanks for submitting this PR! I think this a great feature to add to the component. I have a couple of thoughts on the approach:

  • Instead of adding a new useFsAccessApi prop, I think this could be a drop-in replacement/improvement for the existing multiple prop. So, any upload with multiple=True would automatically use this new code.
  • The implementation does not respect the accept prop, but I think it should. So that users can drop a folder and only the accepted file types within that folder would be transferred.
  • One of the submitted tests fails for me locally: test_upfd002_folder_upload_with_multiple_files. Is it also failing on your end?

…edback)

- Remove useFsAccessApi prop in favor of automatic folder support with multiple=True
- Implement accept prop filtering for folder uploads (extensions, MIME types, wildcards)
- Add custom getDataTransferItems handler for drag-and-drop folder support
- Add traverseFileTree method to recursively process folder contents
- Preserve folder hierarchy in uploaded file names
- Add webkitdirectory/directory/mozdirectory attributes when multiple=True
- Improve integration tests following Dash testing best practices
- Replace problematic test with focused, reliable tests

This is now a drop-in improvement - existing apps using multiple=True
automatically gain folder upload capability with no API changes required.
@LeticiaBN
Copy link
Author

@KoolADE85 Hey! Thanks for the feedback! I've addressed all your points:

  1. Removed useFsAccessApi prop - Folder upload now automatically works with multiple=True (drop-in improvement)

  2. Added accept prop filtering - Implemented fileMatchesAccept() method that filters folder contents by extensions, MIME types, and wildcards

  3. Fixed failing test

All tests pass locally. Let me know if you need any other changes! 🙂

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

community community contribution feature something new P2 considered for next cycle

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Feature Request] Allow dcc.Upload to Ingest a Folder

4 participants