diff --git a/.changeset/clear-clubs-talk.md b/.changeset/clear-clubs-talk.md
new file mode 100644
index 0000000000..1bb79fef98
--- /dev/null
+++ b/.changeset/clear-clubs-talk.md
@@ -0,0 +1,5 @@
+---
+"@digdir/designsystemet-react": minor
+---
+
+**New experimental component**: `FileUpload`. Use it by importing `EXPERIMENTAL_FileUpload` from `@digdir/designsystemet-react`.
diff --git a/.changeset/quick-files-upload.md b/.changeset/quick-files-upload.md
new file mode 100644
index 0000000000..810ac081a5
--- /dev/null
+++ b/.changeset/quick-files-upload.md
@@ -0,0 +1,5 @@
+---
+"@digdir/designsystemet-css": minor
+---
+
+**file-upload**: New experimental component. Style with the `ds-file-upload` class.
diff --git a/apps/www/app/content/components/file-upload/en/accessibility.mdx b/apps/www/app/content/components/file-upload/en/accessibility.mdx
new file mode 100644
index 0000000000..ac26f72b49
--- /dev/null
+++ b/apps/www/app/content/components/file-upload/en/accessibility.mdx
@@ -0,0 +1,5 @@
+
+We are working to improve the accessibility documentation for this component. If you have questions or see something that should be prioritised, please contact us on [Github](https://github.com/digdir/designsystemet/issues/new?template=1bug_report.yml) or [Slack](https://designsystemet.no/slack).
+
+
+File upload must always have a visible `Label` associated with it through `Field`, so that screen readers can communicate what should be uploaded. Use `FileUpload.Description` to describe allowed file formats and sizes, so the user receives this information before uploading.
\ No newline at end of file
diff --git a/apps/www/app/content/components/file-upload/en/code.mdx b/apps/www/app/content/components/file-upload/en/code.mdx
new file mode 100644
index 0000000000..0269ad035c
--- /dev/null
+++ b/apps/www/app/content/components/file-upload/en/code.mdx
@@ -0,0 +1,51 @@
+
+File upload is under development. If you have feedback or suggestions, please report them on [Github](https://github.com/digdir/designsystemet/issues/new?template=BLANK_ISSUE&title=Feedback:%20FileUpload) or in [Slack](https://designsystemet.no/slack).
+
+
+
+
+## Usage
+
+Place File upload inside a [field](/en/components/docs/field/code) with a [label](/en/components/docs/label/code) so the upload area gets an accessible label.
+
+In plain HTML, use the class `ds-file-upload` on an element that contains an ``. The input is placed on top of the whole area so the entire surface becomes clickable.
+
+```html
+
+
+
+
Drop file here
+
+
+
+```
+
+To make the area read-only, set `readonly` on the input. The component then automatically switches to a neutral color scale and disables interaction.
+
+## CSS variables and data attributes
+
+File upload uses its own CSS variables to control things like background, border, icon and spacing. These can be overridden on `.ds-file-upload`.
+
+
+
+
+
+## React
+
+```tsx
+import { EXPERIMENTAL_FileUpload as FileUpload, Field, Label } from '@digdir/designsystemet-react';
+
+
+
+
+ Drop file here
+
+ File must be in csv format and less than 2MB
+
+ Upload file
+
+
+
+```
+
+
\ No newline at end of file
diff --git a/apps/www/app/content/components/file-upload/en/overview.mdx b/apps/www/app/content/components/file-upload/en/overview.mdx
new file mode 100644
index 0000000000..913293cef7
--- /dev/null
+++ b/apps/www/app/content/components/file-upload/en/overview.mdx
@@ -0,0 +1,44 @@
+---
+search_terms: file upload, upload file, attachment, drag and drop, fileupload, file input, dropzone
+---
+
+
+File upload is under development. If you have feedback or suggestions, please report them on [Github](https://github.com/digdir/designsystemet/issues/new?template=BLANK_ISSUE&title=Feedback:%20FileUpload) or in [Slack](https://designsystemet.no/slack).
+
+
+
+
+File upload is a form element used to upload files. The component combines a drag-and-drop area with a regular file picker, so the user can select files either by clicking or by dropping them into the area.
+
+If you need advanced file handling with per-file upload status, you must build this yourself around the component.
+
+**Use file upload when**
+- The user needs to upload one or more files as part of a form.
+- You want to support both drag-and-drop and click-to-select.
+
+**Avoid file upload when**
+- The user only needs to choose from a predefined set of options.
+- You can collect the information in a simpler way without requiring file upload.
+
+## Examples
+
+### With description
+You can provide a more detailed description inside the upload area.
+
+
+
+## Guidelines
+Only ask for file upload when it is necessary. If you can collect the information in a simpler way, you should do that instead.
+
+Make sure there is always a visible label that describes what should be uploaded. Also tell the user which requirements apply to the files.
+
+Always state
+- which file types are allowed
+- any file size limits
+- how many files can be uploaded
+- what the files will be used for
+
+## Text
+The button text should be short and action-oriented, for example "Choose files" or "Choose file".
+
+Make sure error messages follow the [guidelines for error messages](/en/patterns/errors), and use specific error messages for different error situations.
diff --git a/apps/www/app/content/components/file-upload/file-upload.stories.tsx b/apps/www/app/content/components/file-upload/file-upload.stories.tsx
new file mode 100644
index 0000000000..cd61968435
--- /dev/null
+++ b/apps/www/app/content/components/file-upload/file-upload.stories.tsx
@@ -0,0 +1,79 @@
+import {
+ EXPERIMENTAL_FileUpload,
+ Field,
+ Label,
+} from '@digdir/designsystemet-react';
+
+export const Preview = () => (
+
+
+
+ Filen må være i csv-format og mindre enn 2MB
+
+
+
+ Slipp fil her
+
+
+ Last opp fil
+
+
+
+
+);
+
+export const PreviewEn = () => (
+
+
+
+ File must be in csv format and less than 2MB
+
+
+
+ Drop file here
+
+
+ Upload file
+
+
+
+
+);
+
+export const FileUploadExample = () => (
+
+
+ beskrivelsestekst
+
+
+ Slipp fil her
+
+
+ Filen må være i csv-format og mindre enn 2MB
+
+
+ Last opp fil
+
+
+
+
+);
+
+export const FileUploadExampleEn = () => (
+
+
+ description text
+
+
+ Drop file here
+
+
+ File must be in csv format and less than 2MB
+
+
+ Upload file
+
+
+
+
+);
diff --git a/apps/www/app/content/components/file-upload/metadata.json b/apps/www/app/content/components/file-upload/metadata.json
new file mode 100644
index 0000000000..280622f21a
--- /dev/null
+++ b/apps/www/app/content/components/file-upload/metadata.json
@@ -0,0 +1,12 @@
+{
+ "no": {
+ "title": "File upload",
+ "subtitle": "File upload er et skjemaelement for å laste opp filer."
+ },
+ "en": {
+ "title": "File upload",
+ "subtitle": "File upload is a form element used to upload files."
+ },
+ "image": "FileUpload.svg",
+ "cssFile": "file-upload.css"
+}
diff --git a/apps/www/app/content/components/file-upload/no/accessibility.mdx b/apps/www/app/content/components/file-upload/no/accessibility.mdx
new file mode 100644
index 0000000000..5d0b5aa0b3
--- /dev/null
+++ b/apps/www/app/content/components/file-upload/no/accessibility.mdx
@@ -0,0 +1,5 @@
+
+Vi jobber med å forbedre dokumentasjonen for tilgjengelighet på denne komponenten. Har du spørsmål eller ser noe som bør prioriteres, ta gjerne kontakt med oss på [Github](https://github.com/digdir/designsystemet/issues/new?template=1bug_report.yml) eller [Slack](https://designsystemet.no/slack).
+
+
+File upload skal alltid ha en synlig `Label` knyttet til seg via `Field`, slik at skjermlesere kan formidle hva som skal lastes opp. Bruk `FileUpload.Description` til å beskrive tillatte filformater og størrelser, slik at brukeren får denne informasjonen før opplasting.
\ No newline at end of file
diff --git a/apps/www/app/content/components/file-upload/no/code.mdx b/apps/www/app/content/components/file-upload/no/code.mdx
new file mode 100644
index 0000000000..587bbc539f
--- /dev/null
+++ b/apps/www/app/content/components/file-upload/no/code.mdx
@@ -0,0 +1,51 @@
+
+File upload er under utvikling. Har du tilbakemelding eller innspill, meld fra på [Github](https://github.com/digdir/designsystemet/issues/new?template=BLANK_ISSUE&title=Feedback:%20FileUpload) eller i [Slack](https://designsystemet.no/slack).
+
+
+
+
+## Bruk
+
+Plasser File upload inni en [field](/no/components/docs/field/code) med en [label](/no/components/docs/label/code) slik at opplastingsområdet får en tilgjengelig ledetekst.
+
+Bruk klassen `ds-file-upload` på et element som inneholder en ``. Inputen blir lagt oppå hele området slik at hele flaten blir klikkbar.
+
+```html
+
+
+
+
Slipp fil her
+
+
+
+```
+
+For å gjøre området skrivebeskyttet, sett `readonly` på inputen. Komponenten bytter da automatisk til en nøytral fargeskala og deaktiverer interaksjon.
+
+## CSS-variabler og data-attributter
+
+File upload bruker egne CSS-variabler for å styre blant annet bakgrunn, kantlinje, ikon og luft. Disse kan overstyres på `.ds-file-upload`.
+
+
+
+
+
+## React
+
+```tsx
+import { EXPERIMENTAL_FileUpload as FileUpload, Field, Label } from '@digdir/designsystemet-react';
+
+
+
+
+ Slipp fil her
+
+ Filen må være i csv-format og mindre enn 2MB
+
+ Last opp fil
+
+
+
+```
+
+
\ No newline at end of file
diff --git a/apps/www/app/content/components/file-upload/no/overview.mdx b/apps/www/app/content/components/file-upload/no/overview.mdx
new file mode 100644
index 0000000000..f77dafb7c6
--- /dev/null
+++ b/apps/www/app/content/components/file-upload/no/overview.mdx
@@ -0,0 +1,44 @@
+---
+search_terms: filopplasting, last opp fil, opplasting, vedlegg, dra og slipp, fileupload, file input, upload, dropzone
+---
+
+
+File upload er under utvikling. Har du tilbakemelding eller innspill, meld fra på [Github](https://github.com/digdir/designsystemet/issues/new?template=BLANK_ISSUE&title=Feedback:%20FileUpload) eller i [Slack](https://designsystemet.no/slack).
+
+
+
+
+File upload er et skjemaelement for å laste opp filer. Komponenten kombinerer et område for å dra og slippe filer med en vanlig filvelger, slik at brukeren kan velge filer enten ved å klikke eller ved å slippe dem i området.
+
+Hvis du trenger avansert filhåndtering med opplastingsstatus per fil, må du selv bygge dette rundt komponenten.
+
+**Bruk file upload når**
+- Brukeren skal laste opp én eller flere filer som en del av et skjema.
+- Du ønsker å støtte både dra-og-slipp og klikk for å velge fil.
+
+**Unngå file upload når**
+- Brukeren kun skal velge fra et forhåndsdefinert sett med alternativer.
+- Du kan hente inn informasjonen på en enklere måte uten at filopplasting er nødvendig.
+
+## Eksempel
+
+### Med beskrivelse
+Du kan gi en mer utfyllende beskrivelse inni opplastingsområdet.
+
+
+
+## Retningslinjer
+Be bare om filopplasting når det er nødvendig. Hvis du kan hente inn informasjonen på en enklere måte, bør du gjøre det i stedet.
+
+Pass på at det alltid finnes en synlig label som beskriver hva som skal lastes opp. Fortell også hvilke krav som gjelder for filene.
+
+Oppgi alltid
+- hvilke filtyper som er tillatt
+- eventuelle begrensninger på filstørrelse
+- hvor mange filer som kan lastes opp
+- hva filene skal brukes til
+
+## Tekst
+Knappeteksten bør være kort og handlingsorientert, f.eks "Velg filer" eller "Velg fil".
+
+Sørg for at feilmeldinger følger [retningslinjene for feilmeldinger](/no/patterns/errors), og bruk spesifikke feilmeldinger for ulike feilsituasjoner.
diff --git a/apps/www/public/img/component-previews/FileUpload.svg b/apps/www/public/img/component-previews/FileUpload.svg
new file mode 100644
index 0000000000..11194155d7
--- /dev/null
+++ b/apps/www/public/img/component-previews/FileUpload.svg
@@ -0,0 +1,33 @@
+
diff --git a/packages/css/src/file-upload.css b/packages/css/src/file-upload.css
new file mode 100644
index 0000000000..100520227b
--- /dev/null
+++ b/packages/css/src/file-upload.css
@@ -0,0 +1,108 @@
+.ds-file-upload {
+ --dsc-file-upload-background: var(--ds-color-surface-default);
+ --dsc-file-upload-background--hover: var(--ds-color-surface-tinted);
+ --dsc-file-upload-icon-color: var(--ds-color-text-subtle);
+ --dsc-file-upload-border-color: var(--ds-color-border-default);
+ --dsc-file-upload-border-radius: var(--ds-border-radius-md);
+ --dsc-file-upload-border-width: max(2px, 0.125rem);
+ --dsc-file-upload-border-style: dashed;
+ --dsc-file-upload-border-style--hover: solid;
+ --dsc-file-upload-color: currentcolor;
+ --dsc-file-upload-padding: var(--ds-size-8) var(--ds-size-6);
+ --dsc-file-upload-icon-size: var(--ds-size-8);
+ --dsc-file-upload-icon-url: url('data:image/svg+xml,');
+ --dsc-file-upload-icon-url--readonly: url('data:image/svg+xml,');
+
+ --_icon-url: var(--dsc-file-upload-icon-url);
+ position: relative;
+ border: var(--dsc-file-upload-border-width) var(--dsc-file-upload-border-style) var(--dsc-file-upload-border-color);
+ border-radius: var(--dsc-file-upload-border-radius);
+ padding: var(--dsc-file-upload-padding);
+ background: var(--dsc-file-upload-background);
+ user-select: none;
+ outline: none; /* Hide outline when react-dropzone adds tabindex="0" */
+ text-align: center;
+ @composes ds-print-preserve from './base.css';
+
+ /* React-dropzone puts tabindex="0" on whatever gets {...getRootProps()} and set tabindex="-1" on input.. */
+ .ds-field[tabindex]:focus-visible:has(&) {
+ outline: none;
+ }
+ .ds-field[tabindex]:focus-visible &,
+ &:focus-within {
+ @composes ds-focus--visible from './base.css';
+ }
+
+ &:hover {
+ border-style: var(--dsc-file-upload-border-style--hover);
+ background-color: var(--dsc-file-upload-background--hover);
+ cursor: pointer;
+ }
+ &:has(:is([readonly], [aria-readonly='true'])) {
+ cursor: not-allowed;
+ pointer-events: none;
+ --_icon-url: var(--dsc-file-upload-icon-url--readonly);
+ --dsc-file-upload-background: var(--ds-color-surface-tinted);
+ --dsc-file-upload-background--hover: var(--ds-color-surface-tinted);
+
+ /* Override entire color scale to neutral as a catch-all*/
+ --ds-color-background-default: var(--ds-color-neutral-background-default);
+ --ds-color-background-tinted: var(--ds-color-neutral-background-tinted);
+ --ds-color-surface-default: var(--ds-color-neutral-surface-default);
+ --ds-color-surface-tinted: var(--ds-color-neutral-surface-tinted);
+ --ds-color-surface-hover: var(--ds-color-neutral-surface-hover);
+ --ds-color-surface-active: var(--ds-color-neutral-surface-active);
+ --ds-color-border-subtle: var(--ds-color-neutral-border-subtle);
+ --ds-color-border-default: var(--ds-color-neutral-border-default);
+ --ds-color-border-strong: var(--ds-color-neutral-border-strong);
+ --ds-color-text-subtle: var(--ds-color-neutral-text-subtle);
+ --ds-color-text-default: var(--ds-color-neutral-text-default);
+ --ds-color-base-default: var(--ds-color-neutral-base-default);
+ --ds-color-base-hover: var(--ds-color-neutral-base-hover);
+ --ds-color-base-active: var(--ds-color-neutral-base-active);
+ --ds-color-base-contrast-subtle: var(--ds-color-neutral-base-contrast-subtle);
+ --ds-color-base-contrast-default: var(--ds-color-neutral-base-contrast-default);
+ }
+ &:has([aria-invalid='true']) {
+ border-color: var(--ds-color-danger-border-default);
+ }
+
+ & > input[type='file'] {
+ position: absolute;
+ inset: 0;
+ margin: 0;
+ z-index: 1;
+ opacity: 0;
+ cursor: inherit;
+ }
+
+ /* Icon */
+ & > svg,
+ &:not(:has(> svg))::before {
+ color: var(--dsc-file-upload-icon-color);
+ display: block;
+ height: var(--dsc-file-upload-icon-size);
+ margin: 0 auto var(--ds-size-2);
+ width: var(--dsc-file-upload-icon-size);
+
+ @media (forced-colors: active) {
+ color: CanvasText;
+ }
+ }
+ &:not(:has(> svg))::before {
+ content: '';
+ background: currentColor;
+ mask: var(--_icon-url) center / contain no-repeat;
+ @media (forced-colors: active) {
+ background: CanvasText;
+ }
+ }
+ /* First line of text should be currentcolor */
+ & > [data-field='description']:not([data-field='description'] + [data-field='description']) {
+ color: var(--dsc-file-upload-color);
+ }
+ & > .ds-button {
+ width: fit-content;
+ margin: var(--ds-size-4) auto 0;
+ }
+}
diff --git a/packages/css/src/index.css b/packages/css/src/index.css
index 586c2c569a..399122ab31 100644
--- a/packages/css/src/index.css
+++ b/packages/css/src/index.css
@@ -12,6 +12,7 @@
@import url('./input.css') layer(ds.components);
@import url('./field.css') layer(ds.components);
@import url('./fieldset.css') layer(ds.components);
+@import url('./file-upload.css') layer(ds.components);
@import url('./alert.css') layer(ds.components);
@import url('./popover.css') layer(ds.components);
@import url('./skip-link.css') layer(ds.components);
diff --git a/packages/react/package.json b/packages/react/package.json
index 33e64fc792..92b72dd233 100644
--- a/packages/react/package.json
+++ b/packages/react/package.json
@@ -61,6 +61,7 @@
"@testing-library/user-event": "14.6.1",
"@types/react": "19.2.17",
"@types/react-dom": "19.2.3",
+ "react-dropzone": "15.0.0",
"react": "19.2.7",
"react-dom": "19.2.7",
"rimraf": "6.1.3",
diff --git a/packages/react/src/components/file-upload/file-upload-description.tsx b/packages/react/src/components/file-upload/file-upload-description.tsx
new file mode 100644
index 0000000000..e47a207284
--- /dev/null
+++ b/packages/react/src/components/file-upload/file-upload-description.tsx
@@ -0,0 +1,12 @@
+import { forwardRef, type HTMLAttributes } from 'react';
+import { Paragraph, type ParagraphProps } from '../paragraph/paragraph';
+
+export type FileUploadDescriptionProps = ParagraphProps &
+ HTMLAttributes;
+
+export const FileUploadDescription = forwardRef<
+ HTMLParagraphElement,
+ FileUploadDescriptionProps
+>(function FileUploadDescription(rest, ref) {
+ return ;
+});
diff --git a/packages/react/src/components/file-upload/file-upload-fake-button.tsx b/packages/react/src/components/file-upload/file-upload-fake-button.tsx
new file mode 100644
index 0000000000..b3786767e0
--- /dev/null
+++ b/packages/react/src/components/file-upload/file-upload-fake-button.tsx
@@ -0,0 +1,17 @@
+import { forwardRef, type HTMLAttributes } from 'react';
+import type { ButtonProps } from '../button/button';
+import { Button } from '../button/button';
+
+export type FileUploadFakeButtonProps = Pick &
+ HTMLAttributes;
+
+export const FileUploadFakeButton = forwardRef<
+ HTMLSpanElement,
+ FileUploadFakeButtonProps
+>(function FileUploadFakeButton({ variant = 'secondary', ...rest }, ref) {
+ return (
+
+ );
+});
diff --git a/packages/react/src/components/file-upload/file-upload-input.tsx b/packages/react/src/components/file-upload/file-upload-input.tsx
new file mode 100644
index 0000000000..18b55a0f10
--- /dev/null
+++ b/packages/react/src/components/file-upload/file-upload-input.tsx
@@ -0,0 +1,18 @@
+import { forwardRef, type InputHTMLAttributes } from 'react';
+
+export type FileUploadInputProps = InputHTMLAttributes;
+
+export const FileUploadInput = forwardRef<
+ HTMLInputElement,
+ FileUploadInputProps
+>(function FileUploadInput(rest, ref) {
+ return (
+ adds attributes
+ {...rest}
+ />
+ );
+});
diff --git a/packages/react/src/components/file-upload/file-upload.mdx b/packages/react/src/components/file-upload/file-upload.mdx
new file mode 100644
index 0000000000..a8175b7395
--- /dev/null
+++ b/packages/react/src/components/file-upload/file-upload.mdx
@@ -0,0 +1,25 @@
+import { Meta, Canvas, Controls, Primary } from '@storybook/addon-docs/blocks';
+import * as FileStories from './file-upload.stories';
+
+
+
+**Dokumentasjonen har blitt flyttet til [Designsystemet.no](https://designsystemet.no/no/components).**
+
+
+
+
+### working example for testing
+Issue: the button in the input gets focus and the screen reader reads "Label -> Ingen fil valgt -> Description inside dropzone wrapper" (then label and ingen fil valgt again but could be due to iframe)
+
+
+### Using react-dropzone
+Issue: `react-dropzone` puts `tabindex="0"` on whatever gets `{...getRootProps()}` and set `tabindex="-1"` on input, so screen reader does not read label/description outside of the dropzone wrapper.
+
+
+
+
+### Link variant
+
+
+### readOnly test
+
diff --git a/packages/react/src/components/file-upload/file-upload.stories.tsx b/packages/react/src/components/file-upload/file-upload.stories.tsx
new file mode 100644
index 0000000000..75ef628af2
--- /dev/null
+++ b/packages/react/src/components/file-upload/file-upload.stories.tsx
@@ -0,0 +1,311 @@
+import { CircleSlashIcon } from '@navikt/aksel-icons';
+import type { Meta, StoryFn, StoryObj } from '@storybook/react-vite';
+import { type DragEvent, useRef, useState } from 'react';
+import type { FileRejection } from 'react-dropzone';
+import { useDropzone } from 'react-dropzone';
+import { Button, Field, Label } from '../';
+import { EXPERIMENTAL_FileUpload as FileUpload } from './';
+
+type Story = StoryObj;
+
+const meta: Meta = {
+ title: 'Komponenter/FileUpload',
+ component: FileUpload,
+ parameters: {
+ customStyles: {
+ display: 'flex',
+ flexDirection: 'row',
+ justifyContent: 'center',
+ alignItems: 'center',
+ flexWrap: 'wrap',
+ gap: 'var(--ds-size-4)',
+ },
+ },
+};
+
+export default meta;
+
+export const Preview: Story = {
+ render: ({ ...args }) => {
+ return (
+
+
+
+ Drop file here
+
+ File must be in csv format and less than 2MB
+
+ Upload file
+
+
+
+ );
+ },
+};
+
+export const Variants: StoryFn = () => (
+ <>
+
+
+
+ Drop file here
+
+ File must be in csv format and less than 2MB
+
+ Upload file
+
+
+
+
+
+
+ Drop file here
+
+ File must be in csv format and less than 2MB
+
+ Upload file
+
+
+
+ >
+);
+export const LinkAlt: StoryFn = () => (
+
+
+
+
+ Drop files or click to browse
+
+
+ File must be in csv format and less than 2MB
+
+
+
+
+);
+
+export const ReadOnly: StoryFn = () => (
+
+
+ description text
+
+ Upload limit reached
+ Upload file
+
+
+
+);
+
+/* export const Disabled: StoryFn = () => (
+
+
+ description text
+
+
+ Drop file here
+
+
+ File must be in csv format and less than 2MB
+
+ Upload file
+
+
+ Invalid file format
+
+); */
+
+export const HiddenLabel: StoryFn = () => (
+
+
+ description text
+
+ Drop file here
+
+ File must be in csv format and less than 2MB
+
+ Upload file
+
+
+
+);
+
+export const WorkingExample: StoryFn = () => {
+ const fileInputRef = useRef(null);
+ const [uploadedFiles, setUploadedFiles] = useState([]);
+ const [isDragging, setIsDragging] = useState(false);
+ const [isReadOnly, setIsReadOnly] = useState(false);
+
+ const addFiles = (files: FileList) => {
+ setUploadedFiles((prev) => [...prev, ...Array.from(files)]);
+ setIsReadOnly(true);
+ };
+
+ const handleDrop = (event: DragEvent) => {
+ event.preventDefault();
+ setIsDragging(false);
+ if (event.dataTransfer.files.length > 0) {
+ addFiles(event.dataTransfer.files);
+ }
+ };
+
+ const handleChange = (event: React.ChangeEvent) => {
+ if (event.target.files && event.target.files.length > 0) {
+ addFiles(event.target.files);
+ event.target.value = '';
+ }
+ };
+
+ const handleReset = () => {
+ setUploadedFiles([]);
+ setIsReadOnly(false);
+ setIsDragging(false);
+ if (fileInputRef.current) {
+ fileInputRef.current.value = '';
+ }
+ };
+
+ return (
+
+
+
+ ) => {
+ event.preventDefault();
+ setIsDragging(true);
+ }}
+ onDragLeave={() => setIsDragging(false)}
+ onDrop={handleDrop}
+ >
+ {isReadOnly && (
+ <>
+
+
+ You can not upload more files
+
+ >
+ )}
+ {!isReadOnly && (
+ <>
+
+ {isDragging ? 'Drop file to upload' : 'Drop file here'}
+
+
+ File must be in svg format
+
+ Upload file
+ >
+ )}
+
+
+
+ {uploadedFiles.length > 0 && (
+ <>
+
+ {/* When using react-dropzone, it is important to apply the getRootProps to the
+ Field component and not the FileUpload component so screenreaders see the Label.
+ This should be noted in the docs */}
+
+
+
+ {isReadOnly && (
+ <>
+
+
+ You can not upload more files
+
+ >
+ )}
+ {!isReadOnly && (
+ <>
+ {isDragReject && }
+
+ {isDragReject
+ ? 'File type not accepted'
+ : isDragActive
+ ? 'Drop file(s) here'
+ : 'Drop file(s) or click to upload'}
+
+
+ File must be .svg, {MAX_FILES - files.length} of{' '}
+ {MAX_FILES} files remaining
+
+ Upload files
+ >
+ )}
+
+
+
+
+ {files.length > 0 && (
+ <>
+