Skip to content

feat(FileUpload): new component #4102

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking β€œSign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 78 commits into
base: v3
Choose a base branch
from
Open

Conversation

vachmara
Copy link
Contributor

@vachmara vachmara commented May 7, 2025 β€’

πŸ”— Linked issue

Resolves #1945

❓ Type of change

  • πŸ“– Documentation (updates to the documentation or readme)
  • 🐞 Bug fix (a non-breaking change that fixes an issue)
  • πŸ‘Œ Enhancement (improving an existing functionality)
  • ✨ New feature (a non-breaking change that adds functionality)
  • 🧹 Chore (updates to the build process or auxiliary tools and libraries)
  • ⚠️ Breaking change (fix or feature that would cause existing functionality to change)

πŸ“š Description

This PR introduces the FileUpload component, a long-requested feature by the Nuxt UI community (see #1945).

The FileUpload component provides a customizable and accessible file input that supports:

  • File selection via input or drag-and-drop
  • Multiple file selection
  • File preview (only for images if not display an icon)
  • Removal of selected files
  • Customization via slots

πŸ“ Checklist

  • I have linked an issue or discussion.
  • The component is available in the playground.
  • I have updated the documentation accordingly.
  • I have added tests to cover this component.

Copy link

pkg-pr-new bot commented May 7, 2025 β€’

npm i https://pkg.pr.new/@nuxt/ui@4102

commit: b9951d6

@vachmara
Copy link
Contributor Author

vachmara commented May 7, 2025

Would love to hear your feedback on this when you have a moment, @rdjanuar @benjamincanac, happy to iterate based on your suggestions!

@rdjanuar
Copy link
Contributor

rdjanuar commented May 7, 2025 β€’

Thank you for continuing this development @vachmara, actually i'm already done working on this feature but missing only style of component and forget to push it, you can take a look my implementation #2814. maybe on this week i can finish it @benjamincanac

@kaspernowak
Copy link

@vachmara Thank you for this! And also for mentioning it on #1945 which I follow :)

@rdjanuar good to hear that your implementation of this feature is near completion!
I took the time to compare the features in @vachmara's component with the features in #2814, and I feel like these features would be very useful implementations worth to consider:

  1. Image-preview management (essential IMO)
    • Automatically creates and revokes URL.createObjectURL thumbnails for image files.
    • Cleans up previews on file removal and component unmount.
  2. Form-field integration
    • Uses a useFormField composable to wire up blur/focus/change events and aria- attributes automatically.
  3. Themed size-variants & slots
    • size variants (xsβ†’xl) that adjust dimensions, padding, icon/avatar sizes.
    • Fully overridable slot props (ui.empty, ui.file, etc.) via tv() + appConfig.ui.fileUpload overrides.
  4. Custom loading state
    • loading boolean + loadingIcon prop so consumers can show a spinner while files upload.
  5. Built-in file-list UI
    • A <ul> of selected files with filename, size (in MB), avatar/icon preview, and β€œremove” button.
  6. Customizable icons
    • Separate uploadIcon, fileIcon and close icons exposed as props.

@vachmara
Copy link
Contributor Author

vachmara commented May 8, 2025

Hey @rdjanuar,

I noticed you've already done an excellent job on the logic. I honestly thought the feature was abandoned, and I should’ve checked in earlier, sorry about that. I’d be more than happy to help polish and push this component forward with you!

@kaspernowak, thanks for pointing out the main functionalities I implemented; spot on!

I’d also like to mention that the file type validation, which you handled nicely, was something I intentionally left out to maintain compatibility with FormField and Form, with the idea of using external validation libraries for that kind of logic. That said, I'm totally open to discussing the best approach here.

I think both of our implementations bring valuable logic, and it'd be great to merge the best of both. There’s still a bit of work to be done, proper testing (for Vue & Nuxt), improving some functionality (UI/UX, core logic like disabled etc..), and writing the proper documentation.

Don’t hesitate to share how you'd like to collaborate or areas you'd prefer me to focus on. Looking forward to working together!

@rdjanuar
Copy link
Contributor

Hi @vachmara ,

I think I’ll keep my file validation as the default since it already covers all aspects of file upload. Later, I might create a function to allow overriding it based on a given schema. For now, I’ll focus on finishing my work first, and then we can collaborate on it.

@benjamincanac
Copy link
Member

You're not making it easy guys haha

Can't we just keep one open and work together on it? I'd go for this one because it's most recent and follows the latest Nuxt UI components architecture pattern. You will both get the contribution anyway.

@rdjanuar
Copy link
Contributor

sounds good @benjamincanac

@vachmara vachmara marked this pull request as ready for review May 15, 2025 10:09
@vachmara
Copy link
Contributor Author

I’ve added tests and a minimal doc to get everyone started. If anything’s unclear or you’d like to see extra examples or features, just let me know, happy to iterate!

@larseberhardt larseberhardt mentioned this pull request May 19, 2025
8 tasks
@vachmara
Copy link
Contributor Author

vachmara commented Jun 6, 2025

Hey @benjamincanac,
The core functionality is in place, but I still need to fix a few issues and refactor parts of the code.
Feel free to share any feedback!

@caiotarifa
Copy link

Hi @vachmara,

Thanks so much for all the work on the FileUpload component so far, it’s looking fantastic! I’m really excited to get this merged and start using it. Are there any blockers or bugs I can help with?

@vachmara
Copy link
Contributor Author

vachmara commented Jul 1, 2025

Hey @caiotarifa,

Thanks for your message! Everything’s working well on my end.
I think we’re ready for review @benjamincanac

That said, feel free to try it out in the playground and share any feedback, especially on the design side. I’m sure there’s still room for improvement!

Also, we should discuss the documentation to make sure it’s clear and complete before merging.

@benjamincanac
Copy link
Member

@vachmara I've looked quickly and it seems pretty good (will review more deeply in the afternoon). Is it possible with this version to make it look like a Button like:
CleanShot 2025-07-08 at 13 01 37@2x
Maybe an example in the docs would be enough instead of a whole variant to achieve this? πŸ€”

@vachmara
Copy link
Contributor Author

vachmara commented Jul 8, 2025

@benjamincanac Yes, it’s possible to achieve this, but the current approach feels a bit like a workaround due to its complexity:

<UChip inset size="3xl" :show="!!avatar?.length">
  <template #content>
    <UButton
      variant="solid"
      color="neutral"
      icon="i-lucide-x"
      size="xs"
      class="rounded-full"
      @click="avatar = []"
    />
  </template>
  <UFileUpload
    v-model="avatar"
    layout="grid"
    :ui="{
      base: 'rounded-full size-26 p-0',
      filesActions: 'hidden',
      files: 'overflow-hidden rounded-full size-26',
      fileContent: 'rounded-full size-26',
      fileImage: 'rounded-full size-26 object-cover'
    }"
  >
    <template #empty>
      <div class="relative rounded-full size-24 flex items-center justify-center">
        <UIcon name="i-lucide-circle-user-round" size="24" />
      </div>
    </template>
  </UFileUpload>
</UChip>

We could consider integrating this directly into the component, but it might introduce extra complexity.
Let me know what you think, or if you have ideas for a cleaner approach!

@vachmara
Copy link
Contributor Author

vachmara commented Jul 8, 2025

Regarding the documentation, I haven’t updated it to reflect the new architecture yet. So yes, it would definitely be helpful to include a few concrete examples!

@caiotarifa
Copy link

@vachmara I believe that’s exactly the goal: add some examples to the docs to highlights the component’s flexibility (like Origin UI does).

https://originui.com/file-upload

@benjamincanac, which examples do you think we could add to ensure the component is minimally ready to be merged?

Copy link
Member

I'll work on this PR to improve the component a bit and let you know 😊

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.

Add file upload component
6 participants