Skip to content

fix(FileField): open the file dialog inside a link row - #2965

Merged
mfal merged 1 commit into
mainfrom
fix/file-field-click-in-link-row
Aug 28, 2026
Merged

fix(FileField): open the file dialog inside a link row#2965
mfal merged 1 commit into
mainfrom
fix/file-field-click-in-link-row

Conversation

@Lisa18289

Copy link
Copy Markdown
Member

Problem

A FileField (and FileDropZone, which renders one) opens no file dialog when it sits in a List row that has an href — including in a Modal rendered from that row. The button reacts, nothing happens, no error.

Reported from mStudio (coab-0x7e7/frontend/apps/mstudio#3835) for a certificate upload and two avatar uploads.

Cause

A row with href is a react-aria GridListItem link. react-aria attaches an onClick to such rows that kills the click's default action (useSelectableItem, linkBehavior defaults to "action" in useGridList) — and unlike its onPointerDown/onMouseDown siblings, it has no target or portal check.

FileInput opens the dialog with inputRef.current?.click() on its hidden <input type="file">. Opening the dialog is that click's default action, so the row handler cancels it.

Portalling does not help: Overlay moves the DOM node, but the content stays a React descendant of the row, and React dispatches along the React tree.

Fix

onClick={(event) => event.stopPropagation()} on the hidden input. That click is addressed to this input alone — everything outside can only misread it. Fixes every occurrence at once, however deep the field sits in rows and modals.

Test

FileField.browser.test.tsx renders the field in a GridListItem with href, clicks the trigger and asserts the input's click is not defaultPrevented. Red before the fix in both Firefox and WebKit, green after.

Closes #2964

Checklist

  • PR title is a Conventional Commit (fix: → base main)
  • pnpm lint clean (0 errors, prettier clean), pnpm affected:test green, full pnpm nx test:browser components green (72 files / 500 tests, Firefox + WebKit)
  • No generated code affected — FileInput is not @flr-generate, no prop, JSDoc or SCSS class change; git diff empty after build:remote-components and build:scss-types
  • No user-facing strings
  • No public API change, no visual change

A list row with an href is a react-aria GridListItem link, and react-aria
suppresses the default action of every click inside it — without a target or
portal check. Opening the file dialog *is* the default action of FileInput's
click on its hidden input, so the dialog stayed closed with no error. A modal
rendered from such a row is affected too: portalling moves the DOM node, not the
React tree React dispatches along.

The hidden input's click is addressed to that input alone, so it now stops
propagating.

Fixes #2964

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@Lisa18289
Lisa18289 requested a review from a team August 27, 2026 11:36
@Lisa18289 Lisa18289 self-assigned this Aug 27, 2026
@github-actions

Copy link
Copy Markdown
Contributor

Coverage Report for ./packages/components/

Status Category Percentage Covered / Total
🔵 Lines 76% 627 / 825
🔵 Statements 75.91% 643 / 847
🔵 Functions 77.95% 145 / 186
🔵 Branches 66.66% 298 / 447
File CoverageNo changed files found.
Generated in workflow #6353 for commit f0f2a45 by the Vitest Coverage Report Action

@github-actions

Copy link
Copy Markdown
Contributor

🚀 Preview Deployment

Preview environments are ready:

Type URL
docs pr-2965.docs.review.flow-components.de
storybook pr-2965.storybook.review.flow-components.de

Images:

  • docs: ghcr.io/mittwald/flow/docs:pr-2965
  • storybook: ghcr.io/mittwald/flow/storybook:pr-2965

@mfal
mfal merged commit b77a14c into main Aug 28, 2026
11 checks passed
@mfal
mfal deleted the fix/file-field-click-in-link-row branch August 28, 2026 06:49
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

FileField opens no file dialog inside a List row with href (hidden input's click gets preventDefault'ed)

2 participants