Skip to main content
U.S. flag

An official website of the United States government

Dot gov

The .gov means it’s official.
Federal government websites often end in .gov or .mil. Before sharing sensitive information, make sure you’re on a federal government site.

Https

The site is secure.
The https:// ensures that you are connecting to the official website and that any information you provide is encrypted and transmitted securely.

Latest release: Component Library: v56.6.1 released on Jun 9, 2026 | Guidance: Sprint 1 released on Jun 16, 2026 | Figma: Changelog

Components

File Input - Design decisions

Key design decisions for the File Input component.

What is an ADR?

We use the ADR (Architecture Decision Record) to structure design decision documentation. Each ADR covers three things: the context that prompted the decision, the decision itself, and its consequences — including trade-offs and any open questions.

ADR 001 - Limiting built-in functionality for encrypted and password-protected files

  • Date raised: July 17, 2025
  • Decision date: July 17, 2025

Context

Teams wanting to implement the va-file-input web component often need support for encrypted and password protected files. However, the current implementation of va-file-input does not determine if a file is encrypted nor does it decrypt the file. This has been a surprise for some teams who expected an all-in-one solution.

Decision

The va-file-input web component will support setting the encrypted property to true when the user needs to supply a password. This will display a password field. This password can be retrieved through the vaPasswordChange event. All additional functionality related to decrypting the file or using the provided password will need to be handled by the individual team.

This decision has been made because of the development principle to build components that decouple business requirements from the standardized UI and to keep the web component as “DRY” as possible which will allow for a more flexible and maintainable component. Each integration could potentially have a different approach or use case for how they need to handle encrypted and password protected files and the web component should not try to create a single solution for all of those situations. The VA Design System Team performed research that revealed there are unique ways to handle encryption. This principle also promotes modularity and allows different parts of an application to be developed, tested, and updated independently.

Other considerations include the fact that the majority of file related logic should live server side vs client side, which is where the file will likely be stored and processed.

Additionally, the VA Design System component-library is used in a number of different products and services, and we want to ensure that the component can accommodate the needs of all.

For this reason, VA.gov Platform will provide standardized and centralized utility functions that live in vets-website, primarily for usage in forms, that will give a basic implementation of how to handle encryption and password protected files.

Consequences

Teams will need to leverage centralized platform utilities for handling the detection and submissions of encrypted and password protected files. If they require further customization, they will need to implement their own solution and potentially offer that solution back to the platform or forms library for other VFS teams to use.

A step-by-step guide for checking encryption on vets-website is available at:

ADR 002 - Display static thumbnail for PDF files

  • Date raised: November 14, 2025
  • Decision date: November 20, 2025

Context

While doing accessibility testing on the file input components, it was observed that sometimes when loading a multi-paged PDF, the PDF file preview would allow you to scroll through the pages of the PDF, and if you clicked on the thumbnail some screen readers would announce more details about the PDF. This behavior is inconsistent, and not all PDFs show a preview like this.

Decision

The preview image size for the uploaded file is only 40px x 40px. It is impossible to distinguish the content of the file. There was no documentation left about why the previous decision was to show this as a feature. We decided to show a static, generic SVG file icon in its place.

Consequences

If there was any chance that users were hoping to verify they uploaded the right file via the preview, at such a small size, that functionality is now removed.

ADR 003 - Password encryption

  • Decision date: September 2025

Context

Users occasionally need to upload password-protected files, particularly encrypted PDFs, as part of their applications. The va-file-input web component needed a mechanism to collect passwords for encrypted files without handling the actual decryption logic.

Key requirements include:

  • Providing a user interface for password entry when encrypted files are uploaded
  • Maintaining separation of concerns between the web component (presentation) and business logic (decryption/processing)
  • Securely transmitting passwords to the backend for file decryption
  • Supporting the forms library’s file processing workflow

The challenge was determining where password collection, transmission, and file decryption responsibilities should reside within the platform architecture.

Decision

We implemented a distributed approach to handling password-protected files.

Web Component (va-file-input)

The va-file-input web component supports an encrypted property. When set to true:

  • A password input field is displayed to the user
  • The password is masked
  • Password changes are emitted through the vaPasswordChange event
  • The component does NOT handle any decryption or password validation logic

Forms Library

The forms library is responsible for:

  • Capturing the password from the vaPasswordChange event
  • Validating the password decrypts the PDF
  • Transmitting the password securely to the backend along with the file

Backend

The backend handles:

  • Receiving the encrypted file and associated password
  • Decrypting the file using the provided password
  • Validating the decryption was successful
  • Processing the decrypted file for submission

PDF Encryption

For PDF files with encryption:

  • The forms library sends both the file and password to the backend
  • The backend decrypts the PDF before final submission
  • If decryption fails, the backend returns an appropriate error

ADR 004 - File type validation

  • Decision date: September 2025

Context

The va-file-input component is designed as a presentation component and does not handle business logic such as file type validation. As applications using this component need to validate uploaded files for security and data integrity, a decision was needed on where to implement file type validation logic.

Key validation requirements include:

  • Detecting mismatches between file extensions and actual MIME types (e.g., a PDF file renamed with a .png extension)
  • Validating UTF encoding for text-based files
  • Supporting both single and multi-file upload patterns

Without centralized validation logic, each application would need to implement its own validation, leading to inconsistent error handling and duplicate code across the platform.

Decision

File type validation logic lives in the forms library rather than in the va-file-input web component itself.

The forms library provides validation for:

  1. MIME type and file extension matching — ensures the file’s actual format matches its declared extension
  2. UTF encoding validation — verifies proper character encoding for text files

Standard error messages

  • UTF encoding error: “The file’s encoding is not valid”
  • MIME type/extension mismatch: “The file extension doesn’t match the file format. Please choose a different file.”

Custom error handling outside of forms library

Applications requiring custom error handling outside the forms library can refer to the implementation example in vets-website’s ds-v3-playground application.

ADR 005 - Display read-only data via dt instead of inert

  • Decision date: March 10, 2026

Context

va-file-input and va-file-input-multiple allow users to upload a file and assign it a document type (e.g. “Birth certificate”, “Utility bill”) via a <select> element in the slot. Once the file is uploaded and enters a review state, the document type selection becomes immutable — the user can no longer change it.

Previously, the review state applied the inert attribute to the <select> to prevent interaction. While inert correctly removes the element from tab order and blocks pointer interaction, it also removes the element from the accessibility tree entirely. Screen reader users receive no indication that a document type was selected or what that value is.

This is a WCAG 2.2 failure under:

  • 1.3.1 Info and Relationships — the selected value is not conveyed to AT
  • 4.1.2 Name, Role, Value — the value of the control is not exposed

Decision

In the review state of va-file-input and va-file-input-multiple, replace the inert-disabled <select> with a <dl> displaying the document type label and the user’s selected value.

<dl>
  <dt>Document type</dt>
  <dd>[User-selected document type label]</dd>
</dl>

This pattern is scoped to the file card context. It is not a general-purpose read-only select pattern for other components or use cases.

Rationale

<select> has no native readonly attribute. The available alternatives each carry a meaningful cost:

  • inert — removes the element from the accessibility tree. AT users cannot perceive the value. Not acceptable.
  • disabled — semantically incorrect here. disabled signals the field is unavailable for interaction, not that the user already made a confirmed choice. It also excludes the value from form submission, requiring a hidden input workaround. AT announces it as “dimmed” or “unavailable,” which misrepresents the state.
  • aria-disabled + pointer-events: none — does not reliably prevent keyboard interaction. AT can still open the select in some browser/AT combos.
  • aria-readonly — not a valid ARIA property on listbox or combobox roles. Silently ignored by AT.

None of these correctly communicate “this is a confirmed, immutable value the user previously set.”

A <dl> is semantically appropriate because in the review state, the document type is no longer a form input — it is a confirmed data point associated with a specific file. A description list is a label/value pair that is well-supported across AT/browser combinations. It announces correctly in both browse mode and when navigated to directly, requires no ARIA overrides, and is consistent with how confirmed metadata is displayed in card/summary contexts.

Consequences

Positive

  • Screen reader users can now perceive the confirmed document type value
  • Eliminates WCAG 1.3.1 and 4.1.2 failures in the review state
  • No ARIA workarounds or hidden input hacks required
  • Pattern is stable across AT/browser combinations

Negative / watch items

  • The visual and interaction pattern shifts from a form control to static content — consuming teams should ensure the surrounding UI makes the review state clear to sighted users as well
  • If the component ever needs to support editing the document type after upload (inline edit pattern), the <dl> approach will need to be revisited in favor of a toggled edit state
  • JAWS in forms mode will skip <dl> content — acceptable here since the review state is not inside an active form submission context, but should be verified if that assumption changes
  • <dl>/<dt> is not cleanly announced using VoiceOver on Chrome. More exploration is encouraged.

ADR 006 - Make available older password version for claim-status team only

  • Decision date: March 18, 2026

Context

The claim-status tool team requested a change to va-file-input with the password enhancement because their backend and frontend are not set up to handle the additional submit button.

claim-status uses the va-file-input-multiple component outside of the forms-system. Unlike the forms-system, claim-status does not immediately upload files. A user will add multiple files, specify file type, and add a password (if relevant) then upload all files together. This means the accessibility issues with the forms-system implementation of an encrypted PDF upload may not exist for claim-status.

For claim-status to use the new design of the file-input (which requires immediate file upload) the claim-status team would have to re-architect their frontend and modify their backend significantly.

Decision

Re-implement the updates to va-file-input and va-file-input-multiple that introduced the new password submit button pattern, while adding backward compatibility for the existing pattern that uses only a password text input and emits vaPasswordChange.

Backward compatibility is supported through a new disablePasswordSubmitPattern prop (default: false) on both components. When this prop is false, the password section renders a submit button and emits vaPasswordSubmit on button click. When this prop is true, there is no rendered submit button — this is the version available to claim-status.

Because we do not want other teams setting disablePasswordSubmitPattern to true, it is not displayed as an option in Figma or VADS. The claim-status tool is the only approved consumer of disablePasswordSubmitPattern="true".

Consequences

More teams may want to set disablePasswordSubmitButtonPattern to true now that we have one product using it, but each use case will need to be evaluated individually.

ADR 007 - Use hint text instead of warning alert for encrypted file password requirement

  • Decision date: April 27, 2026

Context

When a user uploads an encrypted file using the file input component, the component must:

  • Inform the user that a password is required
  • Provide a way to enter that password
  • Confirm when the file has been successfully unlocked

The original approach used a va-alert (warning) to communicate that a password is required. However:

  • Alerts are not reliably announced via aria-live="polite" in Safari and on iOS due to known browser/AT inconsistencies
  • Moving focus to a non-interactive alert is unreliable across screen readers and devices
  • Focus should remain on the next required user action (the password input), not on a static message

Options considered and rejected:

  • Error state on the password field — rejected because the user has not made an error; uploading an encrypted file is a valid action
  • Both a warning alert and hint text — introduces duplication, increases cognitive load, and does not resolve the core announcement reliability issue

Decision

  • Remove the warning alert when a password is required
  • Use hint text on the password input to communicate that the file is encrypted and requires a password
  • Rely on focus behavior so that when the password field appears, screen readers announce the label and hint text

For success: when a file is successfully unlocked, add confirmation text to the accessible name (aria-label) of the file input — for example, “You have successfully unlocked the file: [file name]”. Focus remains on the file input, ensuring the message is announced reliably.

For missing or invalid password: no change to existing error handling. The error message appears only after user interaction.

Consequences

Positive

  • More reliable screen reader announcement across browsers and devices
  • Keeps focus on the next required user action
  • Avoids misuse of error states
  • Reduces duplicate or competing messaging

Negative

  • Breaks from the common pattern of using warning alerts for notable conditions
  • Sighted users lose a high-visibility warning treatment
  • Relies on users noticing the password field and its hint text

ADR 008 - Adopt the multi-file input array pattern for document upload with metadata

  • Date raised: February 1, 2026

Context

va-file-input-multiple supports slot-based additional fields (for example, a document-type dropdown) that render inline with each uploaded file. Teams have used this to collect both files and per-file metadata in one component instance.

This architecture has produced recurring issues:

  • Race conditions from slot timing differences that make validation and error setting unreliable
  • Flaky tests that pass or fail depending on render order
  • Brittle focus management across light DOM and shadow DOM when returning from OS file pickers
  • Accessibility and usability concerns when file input, metadata inputs, and actions are combined on one card

This ADR was raised by the VA Design System team with Matthew Dingee, Amy Leadem, and Robert Hassell. Discussion occurred in .

Decision

Adopt the multi-file input array pattern as the default approach for collecting multiple documents with metadata on VA.gov forms.

  • Use single-file va-file-input to upload one file at a time
  • Collect per-file metadata on a follow-up page using standard form components like va-radio and va-select
  • Connect the flow with the existing array builder (multiple responses) pattern for summary, add/edit/remove, confirmations, and URL-addressable state

This decision does not deprecate va-file-input or va-file-input-multiple, does not change encrypted-file password behavior, and does not replace slot-based usage where per-file metadata is not required.

Consequences

Positive

  • Eliminates slot-render timing dependencies and related race conditions
  • Simplifies focus management by keeping each page scoped to one task
  • Improves accessibility and usability by aligning to the one-task-per-page principle and using standard, tested form controls
  • Provides a migration path for forms relying on attachmentSchema-based document type handling
  • Reuses existing array builder flows instead of requiring net-new framework code
  • Improves test reliability by removing slot-timing flakiness

Negative / watch items

  • Teams currently using inline slot-based metadata collection will need to migrate flows to separate upload and metadata steps
  • Multi-step experiences require careful content and navigation design so users understand the upload-to-metadata progression

ADR 009 - Handle encrypted file decryption on the backend rather than client-side

  • Decision date: September 2025

Context

Teams using va-file-input with encrypted files need a place for decryption logic to live. Several client-side approaches were considered before settling on a backend-first model.

Decision

Encrypted file decryption is handled on the backend. The va-file-input component collects the password and emits it via vaPasswordChange — all decryption and processing happens server-side.

The following client-side alternatives were considered and rejected:

  • Client-side decryption (e.g., pdf-lib, PDF.js) — Decrypting in the browser exposes decrypted content in memory, increases attack surface, produces no audit trail, and relies on JS libraries with incomplete AES-256 support. Bundle size cost is non-trivial for a feature most users won’t encounter.
  • Client-side password validation before upload — Still requires crypto library weight, and the backend must verify independently anyway, making the frontend check redundant.
  • Strip encryption client-side, upload plain file — Silently removing a user’s intentional file protection is a trust and disclosure problem. It also prevents backends that need to store both the encrypted original and decrypted copy from doing so.
  • Handling logic inside va-file-input itself — Components own presentation, not business logic. Embedding decryption would couple a shared cross-product component to VA-specific backend contracts, introduce untestable dependencies, and duplicate logic the backend must perform regardless.

Consequences

Positive

  • Decryption fits naturally into the existing server-side file storage and processing pipeline
  • Keeps sensitive operations in a controlled, auditable environment
  • Lets each team handle their own decryption constraints without a forced one-size-fits-all frontend implementation

Negative / watch items

  • Teams must implement or use centralized platform utilities for backend decryption — the component alone is not intended to handle encrypted files end-to-end
Edit this page in GitHub (Permissions required)
Last updated: May 28, 2026