Skip to main content

File input

Let people attach one or more files with a file input. See examples for accepted file types and multiple uploads.

This component requires the following JavaScript plugin:

Examples

Default

Breakpoints

Mobile

320px

Mobile Lg

480px

Tablet

640px

Desktop

1024px
Drag file here or choose from folder
HTML
<div
data-scope="file-input" data-part="root"
class="relative z-0 max-w-lg"
>
<label
data-scope="file-input" data-part="label"
class="block"
>Input accepts a single file</label>
<div>
<div data-scope="file-input" data-part="sr-status"></div>
<div
data-scope="file-input" data-part="dropzone"
class="border border-dashed border-gray-30 hover:border-gray-50 group data-[invalid]:border-orange-30v mt-2 relative w-full bg-white data-[dragging]:bg-blue-10"
>
<div
data-scope="file-input" data-part="item-group"
class="relative z-30 pointer-events-none hidden data-[valid]:block data-[valid]:bg-blue-10 group"
>
<div class="flex justify-between items-center p-2">
<div
data-scope="file-input" data-part="preview-heading"
class="font-bold"
></div>
</div>
<div
data-scope="file-input" data-part="item"
class="flex gap-2 p-2 border-t border-t-white group-data-[dragging]:opacity-10"
>
<img data-scope="file-input" data-part="item-preview-image" alt="" class="size-8 object-contain" />
<div data-file-name class="flex items-center"></div>
</div>
</div>
<div
data-scope="file-input" data-part="instructions"
class="py-8 px-4 pointer-events-none z-30 relative text-center data-[valid]:hidden"
>
<span data-scope="file-input" data-part="drag-text">Drag file here or</span>
<span data-scope="file-input" data-part="choose" class="text-blue-60v underline">choose from folder</span>
</div>
<div
data-scope="file-input" data-part="error-text"
class="hidden text-red-60v font-bold data-[invalid]:block -mt-6 mb-6 text-center"
></div>
<input
data-scope="file-input" data-part="input"
id="file-input-single"
class="cursor-pointer absolute inset-0 z-10 p-2 focus:outline-4 focus:outline-blue-40v [&::-webkit-file-upload-button]:hidden data-[dragging]:bg-blue-10 text-transparent"
type="file"
aria-label="Drag file here or choose from folder"
/>
</div>
</div>
</div>

Specific File Types

Breakpoints

Mobile

320px

Mobile Lg

480px

Tablet

640px

Desktop

1024px
Select PDF or TXT files
Drag file here or choose from folder
HTML
<div
data-scope="file-input" data-part="root"
class="relative z-0 max-w-lg"
>
<label
data-scope="file-input" data-part="label"
class="block"
>Input accepts only specific file types</label>
<span class="text-gray-50" id="file-input-specific-hint">Select PDF or TXT files</span>
<div>
<div data-scope="file-input" data-part="sr-status"></div>
<div
data-scope="file-input" data-part="dropzone"
class="border border-dashed border-gray-30 hover:border-gray-50 group data-[invalid]:border-orange-30v mt-2 relative w-full bg-white data-[dragging]:bg-blue-10"
>
<div
data-scope="file-input" data-part="item-group"
class="relative z-30 pointer-events-none hidden data-[valid]:block data-[valid]:bg-blue-10 group"
>
<div class="flex justify-between items-center p-2">
<div
data-scope="file-input" data-part="preview-heading"
class="font-bold"
></div>
</div>
<div
data-scope="file-input" data-part="item"
class="flex gap-2 p-2 border-t border-t-white group-data-[dragging]:opacity-10"
>
<img data-scope="file-input" data-part="item-preview-image" alt="" class="size-8 object-contain" />
<div data-file-name class="flex items-center"></div>
</div>
</div>
<div
data-scope="file-input" data-part="instructions"
class="py-8 px-4 pointer-events-none z-30 relative text-center data-[valid]:hidden"
>
<span data-scope="file-input" data-part="drag-text">Drag file here or</span>
<span data-scope="file-input" data-part="choose" class="text-blue-60v underline">choose from folder</span>
</div>
<div
data-scope="file-input" data-part="error-text"
class="hidden text-red-60v font-bold data-[invalid]:block -mt-6 mb-6 text-center"
></div>
<input
data-scope="file-input" data-part="input"
id="file-input-specific"
class="cursor-pointer absolute inset-0 z-10 p-2 focus:outline-4 focus:outline-blue-40v [&::-webkit-file-upload-button]:hidden data-[dragging]:bg-blue-10 text-transparent"
type="file"
aria-label="Drag file here or choose from folder"
aria-describedby="file-input-specific-hint"
accept=".pdf,.txt"
/>
</div>
</div>
</div>

Accept Multiple Files

Breakpoints

Mobile

320px

Mobile Lg

480px

Tablet

640px

Desktop

1024px
Select one or more files
Drag file here or choose from folder
HTML
<div
data-scope="file-input" data-part="root"
class="relative z-0 max-w-lg"
>
<label
data-scope="file-input" data-part="label"
class="block"
>Input accepts multiple files</label>
<span class="text-gray-50" id="file-input-many-hint">Select one or more files</span>
<div>
<div data-scope="file-input" data-part="sr-status"></div>
<div
data-scope="file-input" data-part="dropzone"
class="border border-dashed border-gray-30 hover:border-gray-50 group data-[invalid]:border-orange-30v mt-2 relative w-full bg-white data-[dragging]:bg-blue-10"
>
<div
data-scope="file-input" data-part="item-group"
class="relative z-30 pointer-events-none hidden data-[valid]:block data-[valid]:bg-blue-10 group"
>
<div class="flex justify-between items-center p-2">
<div
data-scope="file-input" data-part="preview-heading"
class="font-bold"
></div>
</div>
<div
data-scope="file-input" data-part="item"
class="flex gap-2 p-2 border-t border-t-white group-data-[dragging]:opacity-10"
>
<img data-scope="file-input" data-part="item-preview-image" alt="" class="size-8 object-contain" />
<div data-file-name class="flex items-center"></div>
</div>
</div>
<div
data-scope="file-input" data-part="instructions"
class="py-8 px-4 pointer-events-none z-30 relative text-center data-[valid]:hidden"
>
<span data-scope="file-input" data-part="drag-text">Drag file here or</span>
<span data-scope="file-input" data-part="choose" class="text-blue-60v underline">choose from folder</span>
</div>
<div
data-scope="file-input" data-part="error-text"
class="hidden text-red-60v font-bold data-[invalid]:block -mt-6 mb-6 text-center"
></div>
<input
data-scope="file-input" data-part="input"
id="file-input-many"
class="cursor-pointer absolute inset-0 z-10 p-2 focus:outline-4 focus:outline-blue-40v [&::-webkit-file-upload-button]:hidden data-[dragging]:bg-blue-10 text-transparent"
type="file"
aria-label="Drag file here or choose from folder"
aria-describedby="file-input-many-hint"
multiple
/>
</div>
</div>
</div>

Component API

Initialization

import { fileInputInit } from '@uswds-tailwind/compat/file-input'
fileInputInit()

FileInput is the corresponding instance class. Initialize after all parts and the preview template exist.

Anatomy

Use data-scope="file-input" data-part="root" on the wrapper. Required descendants are input, dropzone, instructions, and item-group. The item-group must contain an initial item template with an item-preview-image image and an element with data-file-name for the filename. Initialization removes this template and clones it for selected files.

Optional parts are label, box, drag-text, choose, preview-heading, error-text, and sr-status. Include a visible label, error text, and status region in accessible examples. The runtime writes selection copy and announcement text into these parts.

Attribute Description
accept Comma-separated file types; the accept option takes precedence. A rejected file rejects the entire batch and clears the accepted selection.
disabled Disables the native picker; the disabled option takes precedence.
multiple Allows multiple files in the native picker; the multiple option takes precedence.
aria-disabled Presence, including false, supplies the fallback for ariaDisabled. This option marks the control without blocking interaction.
data-errormessage Invalid-type message; the errorText option takes precedence. Defaults to Error: This is not a valid file type.
name Native form submission name.

The runtime generates data-dragging on the dropzone, data-invalid on the dropzone and error text, and data-valid on the item group. It hides instructions when files are selected and hides the item group when no files are selected.

Preview images use object URLs. Failed image loads receive data-preview-type with pdf, word, excel, video, or generic for fallback styling.

Configuration and methods

Use FileInput.getOrCreateInstance(root, options) to pass accept, multiple, disabled, ariaDisabled, errorText, id, or ids. Options take precedence over markup fallbacks.

setFiles(files) accepts a File[] and returns Promise<void> after the queued selection update. It applies client-side type validation and updates previews; it does not populate the native file input’s files. Use the native picker for normal form submission. api.acceptedFiles, api.invalid, and api.errorText expose selection state. This component has no selection-change callback.

accept is a file-picker hint and client-side constraint. The component does not upload files. Your application owns submission and server validation.

Cleanup and accessibility

fileInputInit() returns initialized instances. Call destroy() before removing markup to release preview URLs and stop the machine. Removed previews also release their URLs. See instance lifecycle.

The separate status region uses role="status" and aria-live="polite". Selection announcements follow a one-second delay. An initially disabled component hides this region. Keep hints linked to the input and retain visible focus styles.