Skip to content

[SUR-930] [Upload] No File Found placeholder should be replaced with file name#472

Open
jaieds wants to merge 2 commits into
stagingfrom
feat/file-picker
Open

[SUR-930] [Upload] No File Found placeholder should be replaced with file name#472
jaieds wants to merge 2 commits into
stagingfrom
feat/file-picker

Conversation

@jaieds

@jaieds jaieds commented Jul 7, 2026

Copy link
Copy Markdown
Contributor

Description

Closes brainstormforce/surerank#2200

Adds a new FilePicker component: a button-styled file input that visually matches Input type="file" but is built as a proper React control.

  • Renders a "Choose File" segment + filename preview segment ("No file chosen" placeholder when empty), proxying clicks/Enter/Space to a visually-hidden native <input type="file">.
  • Controlled value support: File | File[] | string | null — a previously saved filename string renders exactly like a fresh selection; picking a new file replaces it.
  • onChange( files: FileList | null ) — same callback convention as Input.
  • Opt-in clearable prop: shows a remove "X" (keyboard accessible) when a file is present; clears selection and fires onChange(null). Default suffix stays the static Upload icon, matching Input's current file rendering.
  • Sizes sm | md | lg, label, disabled, error, required, and native pass-through props (multiple, accept, name, id, aria attributes). Styling tokens copied verbatim from Input's file branch.
  • 10 Storybook stories covering empty, pre-filled string, controlled File, multiple, clearable, disabled, error, and each size.

Input type="file" now delegates its rendering to FilePicker, so existing consumers automatically get the filename preview and controlled value support with no code changes (visuals verified identical; a native file input's value cannot be set programmatically, so the previous architecture could not show a saved filename). The file-only class constants in input.tsx that became unused were removed. No new dependencies.

Note for reviewers: the file input's DOM changes from a styled native input to a button + visually-hidden native input. Form submission still works (the hidden input stays form-associated with name/required/accept); a controlled string value is display-only, same as any custom picker. Consumer CSS targeting ::file-selector-button would no longer apply.

Screenshots | Video with voice-over

Empty state renders Choose File No file chosen identically to Input type="file" (verified side-by-side in Storybook; computed styles at md are identical: 40px height, 10px 40px 10px 14px padding, 14px font, 6px radius).

Link to Figma (If applicable)

N/A — UI source of truth is the existing Input type="file" styling.

How has this been tested?

  • tsc -b, npm run build, and eslint all clean; vitest --project=storybook renders all 10 stories (10/10 pass).
  • Browser-verified in Storybook: mouse/Enter/Space all proxy to the hidden input (spy on input.click()); change events with DataTransfer files fire onChange with the FileList and update the preview (single + multiple); controlled string value is replaced by a new selection; clearable X works via mouse, Enter, and Space; disabled blocks focus and clicks; error sets aria-invalid + error outline.
  • Accessibility tree exposes exactly one interactive element (button named by the associated Label); hidden input is tabIndex=-1 + aria-hidden, so no double tab stop.
  • Computed-style comparison against Input type="file" at md: identical height, padding, font size, radius, background, and outline.

Checklist:

  • My code is tested
  • Screenshot added in PR
  • Figma design linked
  • My code follows accessibility standards
  • My code has proper inline documentation
  • I have resolved all lint issues
  • My templates are responsive
  • I've added conditional class names use cn()
  • I've followed theme color usage
  • I have used clear and relevant file paths

Button-styled file input mirroring Input type="file" styling, with
controlled value support (File, File[], or saved filename string),
keyboard-accessible hidden native input, and opt-in clearable action.
Comment thread src/components/file-picker/file-picker.stories.tsx
Comment thread src/components/file-picker/file-picker.stories.tsx
Comment thread src/components/file-picker/file-picker.stories.tsx
Comment thread src/components/file-picker/file-picker.tsx
Comment thread src/components/file-picker/file-picker.tsx
Comment thread src/components/file-picker/index.ts
Comment thread src/components/index.ts
@jaieds jaieds changed the title feat: add FilePicker component [SUR-930] [Upload] No File Found placeholder should be replaced with file name Jul 7, 2026
Input's file branch now renders FilePicker, so existing consumers get
controlled value support and the filename preview without code changes.
Removes the file-only class constants that became unused.
@jaieds jaieds requested review from imnavanath and ravindrakele July 7, 2026 16:44
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.

2 participants