Skip to main content

File selector

A file selector lets me pick or drop my documents when I need to add them to an online form.

The File selector component allows a user to select multiple files from their device, either by dragging and dropping them into the component or using the file input modal dialog.

Details

  • Extends: USWDS File input
  • Modifier: .cfa-file-input, .cfa-form-group, .cfa-file-selector, .cfa-label, .cfa-hint, .cfa-button, .cfa-file-selector__*

The File selector extends the USWDS File input. Further customization is applied using the CSS modifier(s) .cfa-file-input, .cfa-form-group, .cfa-file-selector, .cfa-label, .cfa-hint, .cfa-button, .cfa-file-selector__* to add styles defined in a custom stylesheet.

Modifier. A modifier is a class name that applies a variant, type, or extended style customization to modify the component's visual appearance.

Examples

File selector

The HTML for the demonstration above is rendered using context passed to the component's Thymeleaf template fragment. Learn how to include component templates for Thymeleaf and Ruby in the source and usage section.

<div class="usa-form-group cfa-form-group cfa-file-selector" data-js="file-selector" id="dropzone-f12dc9ec83c3c">
  <div data-dropzone="uploads">
    <label class="usa-label cfa-label" for="input-f12dc9ec83c3c">
      <span>Add your files or photos <abbr class="usa-hint usa-hint--required cfa-hint text-normal">(required)</abbr>
      </span>
    </label>
    <span class="usa-error-message" aria-hidden="true" data-dropzone="input-error-message"></span>
    <div class="usa-file-input cfa-file-input">
      <div class="usa-file-input__target margin-bottom-3" data-dropzone="drag-and-drop-region">
        <div class="usa-file-input__box"></div>
        <div class="usa-file-input__instructions">
          <div class="usa-hint cfa-hint" aria-hidden="true" id="hint-f12dc9ec83c3c">
            <span class="usa-file-input__choose">Select or drop files here</span>. Accepted file types include .jpeg, .jpg, .png, .pdf, .bmp, .gif, .doc, .docx, .odt, .ods, or .odp files. Each file is limited to <b>20 MB</b>, and a maximum of <b>20 files</b> are allowed.
          </div>
          <div class="dz-message" data-dropzone="upload-button">
            <button class="usa-button cfa-button circle-9 padding-0 margin-0" type="button" data-dropzone="button" aria-hidden="true" focusable="false" tabindex="-1">
              <svg class="usa-icon square-7 margin-bottom-neg-2px" aria-hidden="true" focusable="false" tabindex="-1">
                <use href="https://codeforamerica.github.io/uswds/assets/img/sprite.svg#add"></use>
              </svg>
            </button>
          </div>
        </div>
        <input class="usa-file-input__input" type="file" data-dropzone="fallback" id="input-f12dc9ec83c3c" name="input['f12dc9ec83c3c']" aria-describedby="hint-f12dc9ec83c3c" accept=".jpeg, .jpg, .png, .pdf, .bmp, .gif, .doc, .docx, .odt, .ods, .odp" multiple="multiple">
        <div data-dropzone="hidden-input-container"></div>
      </div>
    </div>
  </div>
  <!--/* @hidden       "true"  Visually hides element */-->
  <!--/* @aria-hidden  "true"  Hides element from the accessibility API */-->
  <div data-dropzone="preview" hidden="true" aria-hidden="true">
    <h3 class="cfa-file-selector__preview-header" data-dropzone="preview-header" id="aria-db-a64085f4bc4ca"> Your documents. <span data-dropzone="preview-number">0</span>
      <span data-dropzone="preview-text">uploaded</span>
      <span>(<span>20 max</span>)</span>
    </h3>
    <ul class="add-list-reset" role="list" data-dropzone="preview-container" aria-describedby="aria-db-a64085f4bc4ca">
      <!--/* Use previewTemplate to add a custom preview template  */-->
      <!--/* @data-dropzone  "remove"  removes contents before passing to Dropzone */-->
      <!--/* Dropzone will modify or replace the contents of this element */-->
      <!--/* @data-dropzone  "remove"  removes contents before passing to Dropzone */-->
      <li class="cfa-file-selector__preview dz-image-preview" data-dropzone="preview-template">
        <div class="cfa-file-selector__details">
          <div class="cfa-file-selector__thumbnail" data-dropzone="thumbnail">
            <div class="cfa-file-selector__progress">
              <span class="cfa-file-selector__progress-bar" data-dz-uploadprogress="keep"></span>
            </div>
            <svg class="usa-icon cfa-file-selector__icon-error" aria-hidden="true" focusable="false" role="img">
              <use href="https://codeforamerica.github.io/uswds/assets/img/sprite.svg#warning"></use>
            </svg>
            <svg class="usa-icon cfa-file-selector__icon-default" aria-hidden="true" focusable="false" role="img">
              <use href="https://codeforamerica.github.io/uswds/assets/img/sprite.svg#file_present"></use>
            </svg>
            <img class="cfa-file-selector__img" data-dropzone="img" data-dz-thumbnail="keep" aria-hidden="true" alt="preview-template__filename--testing-truncated-text.ext">
          </div>
          <div class="cfa-file-selector__file">
            <div class="cfa-file-selector__filename" data-dz-name="keep">
              <span class="cfa-file-selector__filename-name" aria-hidden="true">preview-template__filename--testing-truncated-text</span>
              <span class="cfa-file-selector__filename-ext" aria-hidden="true">.ext</span>
            </div>
            <span class="cfa-file-selector__error-message usa-error-message" aria-live="polite" aria-atomic="true" data-dz-errormessage="keep"> Message </span>
            <div>
              <span class="font-body-2xs" title="File size">
                <span class="usa-sr-only">File size, </span>
                <span class="font-body-2xs" data-dz-size="keep">
                  <strong>99</strong> MB
                </span>
                <span>
                  <span class="text-base-lighter padding-inline-x-1 display-none mobile:display-inline-block" aria-hidden="true">|</span>
                  <button type="button" class="usa-button cfa-button cfa-button--danger usa-button--unstyled font-body-2xs" aria-hidden="true" focusable="false" data-dropzone="file-remove" data-dz-remove="keep">
                    <span data-dropzone="file-remove-label">remove</span>
                    <span class="usa-sr-only" data-dz-name="keep">preview-template__filename--testing-truncated-text.ext</span>
                  </button>
                  <!--/* @data-dropzone  "remove"  removes contents before passing to Dropzone. These are used to test the various states for the thumbnail upload. */-->
                  <span data-dropzone="remove">
                    <span class="text-base-lighter padding-inline-x-1 display-none mobile:display-inline-block" aria-hidden="true">|</span>
                    <button type="button" class="usa-button cfa-button usa-button--unstyled font-body-2xs" aria-hidden="true" focusable="false" data-dropzone="toggle-preview-state" data-dropzone-preview-state="cfa-file-selector__preview dz-image-preview">base</button>
                    <span class="text-base-lighter padding-inline-x-1 display-none mobile:display-inline-block" aria-hidden="true">|</span>
                    <button type="button" class="usa-button cfa-button usa-button--unstyled font-body-2xs" aria-hidden="true" focusable="false" data-dropzone="toggle-preview-state" data-dropzone-preview-state="cfa-file-selector__preview dz-image-preview dz-processing">processing</button>
                    <span class="text-base-lighter padding-inline-x-1 display-none mobile:display-inline-block" aria-hidden="true">|</span>
                    <button type="button" class="usa-button cfa-button usa-button--unstyled font-body-2xs" aria-hidden="true" focusable="false" data-dropzone="toggle-preview-state" data-dropzone-preview-state="cfa-file-selector__preview dz-image-preview dz-processing dz-complete">complete</button>
                    <span class="text-base-lighter padding-inline-x-1 display-none mobile:display-inline-block" aria-hidden="true">|</span>
                    <button type="button" class="usa-button cfa-button usa-button--unstyled font-body-2xs" aria-hidden="true" focusable="false" data-dropzone="toggle-preview-state" data-dropzone-preview-state="cfa-file-selector__preview dz-image-preview dz-processing dz-success dz-complete">success</button>
                    <span class="text-base-lighter padding-inline-x-1 display-none mobile:display-inline-block" aria-hidden="true">|</span>
                    <button type="button" class="usa-button cfa-button usa-button--unstyled font-body-2xs" aria-hidden="true" focusable="false" data-dropzone="toggle-preview-state" data-dropzone-preview-state="cfa-file-selector__preview dz-image-preview dz-processing dz-success dz-complete dz-default">default</button>
                    <span class="text-base-lighter padding-inline-x-1 display-none mobile:display-inline-block" aria-hidden="true">|</span>
                    <button type="button" class="usa-button cfa-button usa-button--unstyled font-body-2xs" aria-hidden="true" focusable="false" data-dropzone="toggle-preview-state" data-dropzone-preview-state="cfa-file-selector__preview dz-image-preview dz-processing dz-error dz-complete">error</button>
                  </span>
                </span>
              </span>
            </div>
          </div>
        </div>
      </li>
    </ul>
  </div>
  <!--/* Strings used by the UploadDocument script will be pulled from this element */-->
  <!--/* @hidden         "true"    Visually hides element */-->
  <!--/* @aria-hidden    "true"    Hides element from the accessibility API */-->
  <!--/* @data-dropzone  "remove"  removes contents before passing to Dropzone */-->
  <div hidden="true" aria-hidden="true" data-dropzone="remove">
    <p data-dropzone="dict" data-dropzone-dict="fileTooBig">Sorry, we can't accept files larger than 20 MB. Please, remove this file, make it smaller, then, try again.</p>
    <p data-dropzone="dict" data-dropzone-dict="maxFiles">You have uploaded the maximum number of 20 files. You will have the opportunity to add more later.</p>
    <p data-dropzone="dict" data-dropzone-dict="maxFilesExceeded">Sorry, we can't accept this file. You have uploaded the maximum number of 20 files. You will have the opportunity to add more later.</p>
    <p data-dropzone="dict" data-dropzone-dict="invalidFileType">Sorry, we can't accept this type of file. Please, remove this file, then, try another file that ends in .jpeg, .jpg, .png, .pdf, .bmp, .gif, .doc, .docx, .odt, .ods, or .odp.</p>
    <p data-dropzone="dict" data-dropzone-dict="responseError">Sorry, there was an error on our end. Please, remove this file and try again. If the error continues please try again later.</p>
  </div>
</div>

Context is the information necessary to configure and render a component template to HTML. It may include plain text strings, HTML, class names, IDs or other HTML attribute values. The context here is defined as JSON but the root attributes are translated to different variable syntaxes for Thymeleaf and Ruby templates. Learn how to pass these variables to each component template in the source and usage section.

{
  "modifier": "",
  "id": "dropzone-f12dc9ec83c3c",
  "fileInput": {
    "modifier": "cfa-form-group cfa-file-input",
    "id": "form-group-f12dc9ec83c3c",
    "label": {
      "text": "Add your files or photos <abbr class=\"usa-hint usa-hint--required cfa-hint text-normal\">(required)</abbr>",
      "for": "input-f12dc9ec83c3c",
      "modifier": "cfa-label",
      "modifierHint": "cfa-hint"
    },
    "hint": {
      "text": "<span class=\"usa-file-input__choose\">Select or drop files here</span>. Accepted file types include .jpeg, .jpg, .png, .pdf, .bmp, .gif, .doc, .docx, .odt, .ods, or .odp files. Each file is limited to <b>20 MB</b>, and a maximum of <b>20 files</b> are allowed.",
      "modifier": "cfa-hint",
      "id": "hint-f12dc9ec83c3c"
    },
    "input": {
      "modifier": "usa-file-input cfa-input cfa-file-input__input",
      "id": "input-f12dc9ec83c3c",
      "name": "input['f12dc9ec83c3c']",
      "ariaDescribedby": "hint-f12dc9ec83c3c",
      "type": "file",
      "accept": ".jpeg, .jpg, .png, .pdf, .bmp, .gif, .doc, .docx, .odt, .ods, .odp",
      "multiple": "multiple"
    },
    "button": {
      "icon": "https://codeforamerica.github.io/uswds/assets/img/sprite.svg#add"
    }
  },
  "previewHeader": {
    "id": "aria-db-a64085f4bc4ca"
  },
  "defaultPreviewTemplate": {
    "error": {
      "icon": "https://codeforamerica.github.io/uswds/assets/img/sprite.svg#warning"
    },
    "thumbnail": {
      "default": "https://codeforamerica.github.io/uswds/assets/img/sprite.svg#file_present"
    }
  },
  "dict": [
    {
      "key": "fileTooBig",
      "string": "Sorry, we can't accept files larger than 20 MB. Please, remove this file, make it smaller, then, try again."
    },
    {
      "key": "maxFiles",
      "string": "You have uploaded the maximum number of 20 files. You will have the opportunity to add more later."
    },
    {
      "key": "maxFilesExceeded",
      "string": "Sorry, we can't accept this file. You have uploaded the maximum number of 20 files. You will have the opportunity to add more later."
    },
    {
      "key": "invalidFileType",
      "string": "Sorry, we can't accept this type of file. Please, remove this file, then, try another file that ends in .jpeg, .jpg, .png, .pdf, .bmp, .gif, .doc, .docx, .odt, .ods, or .odp."
    },
    {
      "key": "responseError",
      "string": "Sorry, there was an error on our end. Please, remove this file and try again. If the error continues please try again later."
    }
  ]
}

Accessibility

  • Unchecked
    Customization to the visual appearance of the File selector has been verified for WCAG 2.1 AA contrast minimum success.
  • Unchecked
    The File selector examples pass manual audits (WCAG 2.1 AA using axe or Lighthouse).
  • Unchecked
    The File selector achieves WCAG 2.1 AA resizing success.
    Resizing text up to 200% without loss of content or functionality.
  • Unchecked
    The File selector passes keyboard interaction tests.
    No keyboard test has been created.
  • Unchecked
    The File selector passes screen reader interaction tests.

  • Unchecked
    Guidance on ensuring File selector accessibility has been provided in this documentation.

Refer to additional accessibility guidance on the USWDS documentation site.

Checklist Key

  • Passes
    Passes
  • Unchecked
    Unchecked

Source and usage

Package: @codeforamerica/uswds/packages/cfa-file-selector

  • Sass stylesheet: ./_cfa-file-selector.scss
  • Thymeleaf template fragment: ./cfa-file-selector.th.html
  • Embedded Ruby (ERB) partial template: ./_cfa-file-selector.html.erb
  • JavaScript enables the drag-and-drop interaction, uploaded file preview and management, and validation messaging. The module extends the open source library Dropzone to provide interaction and customization options. The module can be found at ./cfa-file-selector.js. Guidance on individual module loading will added. Currently, there is one script that imports all modules. The source is located at @codeforamerica/js/index.js. This entrypoint is compiled using Rollup.js and distributed to @codeforamerica/dist/js/default.js.
Packages are collections of functionality that make up a component. Typically, they include stylesheets, templates, and scripts. Learn more about packages on the USWDS documentation site.
Sass theme settings

Below is a demonstration of customizing the component theme settings. Refer to the theme and package-level settings documentation.

// Theme-level settings
@use 'cfa-uswds-theme' with (
  // Global theme settings that affect the component, changing these will affect other components
  $cfa-focus-color: 'gold-30v',                // Affects border color of the file input hover and focus state
  $cfa-color-base-ink: 'gray-warm-90',         // Affects color of the file input hint text and instructions
  $cfa-color-primary-lightest: 'mint-cool-5',  // Affects color of the file input hover state background
  $cfa-color-primary: 'mint-50',               // Affects the color of the file input border and primary button
  $cfa-color-error-lighter: 'orange-warm-10v', // Affects error state color of upload document elements
  $cfa-color-error: 'orange-warm-50v',         // Affects error state color of upload document elements
  $cfa-color-error-dark: 'orange-warm-60v',    // Affects error state color of upload document elements
  $cfa-color-success-lighter: 'green-cool-5v', // Affects success state color of upload document elements
  $cfa-color-success-darker: 'green-cool-60v', // Affects success state color of upload document elements
  $cfa-color-info-light: 'gray-warm-20',       // Affects informational state color of upload document elements
  $cfa-color-info-lighter: 'gray-warm-4',      // Affects informational state color of upload document elements
  $cfa-color-info-dark: 'gray-warm-60'         // Affects informational state color of upload document elements
);
// Package-level settings
@use 'cfa-core' with (
  $cfa-form-elements-border-width: 2px
);
Thymeleaf template fragment

This is the pre-rendered template fragment from the package. It is the same template used to render the demonstrations above. You may copy and paste from this example or use the template using the th:block th:replace tag. See the example below.

<div th:fragment="fileSelector(id, fileInput, previewHeader, previewTemplate, defaultPreviewTemplate, dict)" class="usa-form-group cfa-form-group cfa-file-selector" th:attr="id=${id}" data-js="file-selector">
  <div data-dropzone="uploads">
    <label class="usa-label" th:if="${fileInput.label}" th:classappend="${fileInput.label.modifier}" th:attr="id=${fileInput.label.id},for=${fileInput.label.for},tabindex=${fileInput.label.tabindex}">
      <span th:utext="${fileInput.label.text}">Label</span>
      <abbr th:if="${fileInput.input.required}" aria-hidden="true" class="usa-hint usa-hint--required" th:classappend="${fileInput.label.modifierHint}">*</abbr>
    </label>
    <span class="usa-error-message" aria-hidden="true" data-dropzone="input-error-message" th:classappend="${fileInput.error.modifier}" th:attr="id=${fileInput.error.id}" th:utext="${fileInput.error.text}">Message</span>
    <div class="usa-file-input cfa-file-input">
      <div class="usa-file-input__target margin-bottom-3" data-dropzone="drag-and-drop-region">
        <div class="usa-file-input__box"></div>
        <div class="usa-file-input__instructions">
          <div th:if="${fileInput.hint}" class="usa-hint" th:classappend="${fileInput.hint.modifier}" th:attr="id=${fileInput.hint.id}" th:utext="${fileInput.hint.text}" aria-hidden="true">Hint</div>
          <div class="dz-message" data-dropzone="upload-button">
            <button class="usa-button cfa-button circle-9 padding-0 margin-0" type="button" data-dropzone="button" aria-hidden="true" focusable="false" tabindex="-1">
              <svg class="usa-icon square-7 margin-bottom-neg-2px" aria-hidden="true" focusable="false" tabindex="-1">
                <use th:href="${fileInput.button.icon}"></use>
              </svg>
            </button>
          </div>
        </div>
        <input class="usa-file-input__input" type="file" data-dropzone="fallback" th:attr="id=${fileInput.input.id},name=${fileInput.input.name},aria-labelledby=${fileInput.input.ariaLabelledby},aria-describedby=${fileInput.input.ariaDescribedby},accept=${fileInput.input.accept},multiple=${fileInput.input.multiple}">
        <div data-dropzone="hidden-input-container"></div>
      </div>
    </div>
  </div>
  <!--/* @hidden       "true"  Visually hides element */-->
  <!--/* @aria-hidden  "true"  Hides element from the accessibility API */-->
  <div data-dropzone="preview" hidden="true" aria-hidden="true">
    <h3 class="cfa-file-selector__preview-header" data-dropzone="preview-header" th:attr="id=${previewHeader.id}">
      Your documents. <span data-dropzone="preview-number">0</span> <span data-dropzone="preview-text">uploaded</span> <span>(<span>20 max</span>)</span>
    </h3>
    <ul class="add-list-reset" role="list" data-dropzone="preview-container" th:attr="aria-describedby=${previewHeader.id}">
      <!--/* Use previewTemplate to add a custom preview template  */-->
      <!--/* @data-dropzone  "remove"  removes contents before passing to Dropzone */-->
      <li th:if="${previewTemplate}" th:utext="${previewTemplate}" class="cfa-file-selector__preview dz-image-preview" data-dropzone="preview-template" data-dropzone="remove"></li>
      <!--/* Dropzone will modify or replace the contents of this element */-->
      <!--/* @data-dropzone  "remove"  removes contents before passing to Dropzone */-->
      <li th:if="${defaultPreviewTemplate}" class="cfa-file-selector__preview dz-image-preview" data-dropzone="preview-template" data-dropzone="remove">
        <div class="cfa-file-selector__details">
          <div class="cfa-file-selector__thumbnail" data-dropzone="thumbnail">
            <div class="cfa-file-selector__progress">
              <span class="cfa-file-selector__progress-bar" data-dz-uploadprogress="keep"></span>
            </div>
            <svg class="usa-icon cfa-file-selector__icon-error" aria-hidden="true" focusable="false" role="img">
              <use th:href="${defaultPreviewTemplate.error.icon}"></use>
            </svg>
            <svg class="usa-icon cfa-file-selector__icon-default" aria-hidden="true" focusable="false" role="img">
              <use th:href="${defaultPreviewTemplate.thumbnail.default}"></use>
            </svg>
            <img class="cfa-file-selector__img" data-dropzone="img" data-dz-thumbnail="keep" aria-hidden="true" alt="preview-template__filename--testing-truncated-text.ext" />
          </div>
          <div class="cfa-file-selector__file">
            <div class="cfa-file-selector__filename" data-dz-name="keep">
              <span class="cfa-file-selector__filename-name" aria-hidden="true">preview-template__filename--testing-truncated-text</span>
              <span class="cfa-file-selector__filename-ext" aria-hidden="true">.ext</span>
            </div>
            <span class="cfa-file-selector__error-message usa-error-message" aria-live="polite" aria-atomic="true" data-dz-errormessage="keep">
              Message
            </span>
            <div>
              <span class="font-body-2xs" title="File size">
                <span class="usa-sr-only">File size, </span>
                <span class="font-body-2xs" data-dz-size="keep">
                  <strong>99</strong> MB
                </span>
              <span>
              <span class="text-base-lighter padding-inline-x-1 display-none mobile:display-inline-block" aria-hidden="true">|</span>
              <button type="button" class="usa-button cfa-button cfa-button--danger usa-button--unstyled font-body-2xs" aria-hidden="true" focusable="false" data-dropzone="file-remove" data-dz-remove="keep"><span data-dropzone="file-remove-label">remove</span> <span class="usa-sr-only" data-dz-name="keep">preview-template__filename--testing-truncated-text.ext</span></button>
              <!--/* @data-dropzone  "remove"  removes contents before passing to Dropzone. These are used to test the various states for the thumbnail upload. */-->
              <span data-dropzone="remove">
                <span class="text-base-lighter padding-inline-x-1 display-none mobile:display-inline-block" aria-hidden="true">|</span>
                <button type="button" class="usa-button cfa-button usa-button--unstyled font-body-2xs" aria-hidden="true" focusable="false" data-dropzone="toggle-preview-state" data-dropzone-preview-state="cfa-file-selector__preview dz-image-preview">base</button>
                <span class="text-base-lighter padding-inline-x-1 display-none mobile:display-inline-block" aria-hidden="true">|</span>
                <button type="button" class="usa-button cfa-button usa-button--unstyled font-body-2xs" aria-hidden="true" focusable="false" data-dropzone="toggle-preview-state" data-dropzone-preview-state="cfa-file-selector__preview dz-image-preview dz-processing">processing</button>
                <span class="text-base-lighter padding-inline-x-1 display-none mobile:display-inline-block" aria-hidden="true">|</span>
                <button type="button" class="usa-button cfa-button usa-button--unstyled font-body-2xs" aria-hidden="true" focusable="false" data-dropzone="toggle-preview-state" data-dropzone-preview-state="cfa-file-selector__preview dz-image-preview dz-processing dz-complete">complete</button>
                <span class="text-base-lighter padding-inline-x-1 display-none mobile:display-inline-block" aria-hidden="true">|</span>
                <button type="button" class="usa-button cfa-button usa-button--unstyled font-body-2xs" aria-hidden="true" focusable="false" data-dropzone="toggle-preview-state" data-dropzone-preview-state="cfa-file-selector__preview dz-image-preview dz-processing dz-success dz-complete">success</button>
                <span class="text-base-lighter padding-inline-x-1 display-none mobile:display-inline-block" aria-hidden="true">|</span>
                <button type="button" class="usa-button cfa-button usa-button--unstyled font-body-2xs" aria-hidden="true" focusable="false" data-dropzone="toggle-preview-state" data-dropzone-preview-state="cfa-file-selector__preview dz-image-preview dz-processing dz-success dz-complete dz-default">default</button>
                <span class="text-base-lighter padding-inline-x-1 display-none mobile:display-inline-block" aria-hidden="true">|</span>
                <button type="button" class="usa-button cfa-button usa-button--unstyled font-body-2xs" aria-hidden="true" focusable="false" data-dropzone="toggle-preview-state" data-dropzone-preview-state="cfa-file-selector__preview dz-image-preview dz-processing dz-error dz-complete">error</button>
              </span>
            </div>
          </div>
        </div>
      </li>
    </ul>
  </div>
  <!--/* Strings used by the UploadDocument script will be pulled from this element */-->
  <!--/* @hidden         "true"    Visually hides element */-->
  <!--/* @aria-hidden    "true"    Hides element from the accessibility API */-->
  <!--/* @data-dropzone  "remove"  removes contents before passing to Dropzone */-->
  <div hidden="true" aria-hidden="true" data-dropzone="remove">
    <p th:each="item: ${dict}" th:text="${item.string}" data-dropzone="dict" th:attr="data-dropzone-dict=${item.key}">String</p>
  </div>
</div>
Template fragment inclusion

Below is an example of how to use the fragment from the package directory using the th:block th:replace inclusion tag. Replace the fragment parameters using your variables or context.

<th:block th:replace="~{packages/cfa-file-selector/cfa-file-selector.th :: fileSelector(${id}, ${fileInput}, ${previewHeader}, ${previewTemplate}, ${defaultPreviewTemplate}, ${dict})}" />
ERB template partial

This is the pre-rendered partial template from the package. You may copy and paste from this example or use the template directly from the path.

<div class="usa-form-group cfa-form-group cfa-file-selector" data-js="file-selector"<% if defined?(id) %> id="<%= id %>"<% end %>>
  <div data-dropzone="uploads">
    <% if fileInput['label'] %><label class="usa-label<% if fileInput['label']['modifier'] %> <%= fileInput['label']['modifier'] %><% end %>"<% if fileInput['label']['id'] %> id="<%= fileInput['label']['id'] %>"<% end %><% if fileInput['label']['for'] %> for="<%= fileInput['label']['for'] %>"<% end %><% if fileInput['label']['tabindex'] %> tabindex="<%= fileInput['label']['tabindex'] %>"<% end %>>
      <span><%= fileInput['label']['text'] %></span>
      <% if fileInput['input']['required'] %>
      <abbr aria-hidden="true" class="usa-hint usa-hint--required<% if fileInput['label']['modifierHint'] %> <%= fileInput['label']['modifierHint'] %><% end %>">*</abbr>
      <% end %>
    </label><% end %>
    <span class="usa-error-message<% if fileInput['error'] && fileInput['error']['modifier'] %> <%= fileInput['error']['modifier'] %><% end %>" aria-hidden="true" data-dropzone="input-error-message"<% if fileInput['error'] && fileInput['error']['id'] %> id="<%= fileInput['error']['id'] %>"<% end %>>
      <% if fileInput['error'] && fileInput['error']['text'] %><%= fileInput['error']['text'] %><% end %>
    </span>
    <div class="usa-file-input cfa-file-input">
      <div class="usa-file-input__target margin-bottom-3" data-dropzone="drag-and-drop-region">
        <div class="usa-file-input__box"></div>
        <div class="usa-file-input__instructions">
          <% if fileInput['hint'] %>
          <div class="usa-hint<% if fileInput['hint']['modifier'] %> <%= fileInput['hint']['modifier'] %><% end %>" id="<%= fileInput['hint']['id'] %>" aria-hidden="true"><%= fileInput['hint']['text'] %></div>
          <% end %>
          <div class="dz-message" data-dropzone="upload-button">
            <button class="usa-button cfa-button circle-9 padding-0 margin-0" type="button" data-dropzone="button" aria-hidden="true" focusable="false" tabindex="-1">
              <svg class="usa-icon square-7 margin-bottom-neg-2px" aria-hidden="true" focusable="false" tabindex="-1">
                <use href="<%= fileInput['button']['icon'] %>"></use>
              </svg>
            </button>
          </div>
        </div>
        <input class="usa-file-input__input" type="file" data-dropzone="fallback"
          <% if fileInput['input']['id'] %> id="<%= fileInput['input']['id'] %>"<% end %>
          <% if fileInput['input']['name'] %> name="<%= fileInput['input']['name'] %>"<% end %>
          <% if fileInput['input']['aria-labelledby'] %> aria-labelledby="<%= fileInput['input']['ariaLabelledby'] %>"<% end %>
          <% if fileInput['input']['aria-describedby'] %> aria-describedby="<%= fileInput['input']['ariaDescribedby'] %>"<% end %>
          <% if fileInput['input']['accept'] %> accept="<%= fileInput['input']['accept'] %>"<% end %>
          <% if fileInput['input']['multiple'] %> multiple="<%= fileInput['input']['multiple'] %>"<% end %>>
        <div data-dropzone="hidden-input-container"></div>
      </div>
    </div>
  </div>
  <%# @hidden       "true"  Visually hides element %>
  <%# @aria-hidden  "true"  Hides element from the accessibility API %>
  <div data-dropzone="preview" hidden="true" aria-hidden="true">
    <h3 class="cfa-file-selector__preview-header" data-dropzone="preview-header" id="<%= previewHeader['id'] %>">
      Your documents. <span data-dropzone="preview-number">0</span> <span data-dropzone="preview-text">uploaded</span> <span>(<span>20 max</span>)</span>
    </h3>
    <ul class="add-list-reset" role="list" data-dropzone="preview-container" aria-describedby="<%= previewHeader['id'] %>">
      <%# Use previewTemplate to add a custom preview template  %>
      <%# @data-dropzone  "remove"  removes contents before passing to Dropzone %>
      <% if defined?(previewTemplate) %>
      <li class="cfa-file-selector__preview dz-image-preview" data-dropzone="preview-template" data-dropzone="remove">
        <%= previewTemplate %>
      </li>
      <% end %>
      <%# Dropzone will modify or replace the contents of this element %>
      <%# @data-dropzone  "remove"  removes contents before passing to Dropzone %>
      <% if defined?(defaultPreviewTemplate) %>
      <li class="cfa-file-selector__preview dz-image-preview" data-dropzone="preview-template" data-dropzone="remove">
        <div class="cfa-file-selector__details">
          <div class="cfa-file-selector__thumbnail" data-dropzone="thumbnail">
            <div class="cfa-file-selector__progress">
              <span class="cfa-file-selector__progress-bar" data-dz-uploadprogress="keep"></span>
            </div>
            <svg class="usa-icon cfa-file-selector__icon-error" aria-hidden="true" focusable="false" role="img">
              <use href="<%= defaultPreviewTemplate['error']['icon'] %>"></use>
            </svg>
            <svg class="usa-icon cfa-file-selector__icon-default" aria-hidden="true" focusable="false" role="img">
              <use href="<%= defaultPreviewTemplate['thumbnail']['default'] %>"></use>
            </svg>
            <img class="cfa-file-selector__img" data-dropzone="img" data-dz-thumbnail="keep" aria-hidden="true" alt="preview-template__filename--testing-truncated-text.ext" />
          </div>
          <div class="cfa-file-selector__file">
            <div class="cfa-file-selector__filename" data-dz-name="keep">
              <span class="cfa-file-selector__filename-name" aria-hidden="true">preview-template__filename--testing-truncated-text</span>
              <span class="cfa-file-selector__filename-ext" aria-hidden="true">.ext</span>
            </div>
            <span class="cfa-file-selector__error-message usa-error-message" aria-live="polite" aria-atomic="true" data-dz-errormessage="keep">
              Message
            </span>
            <div>
              <span class="font-body-2xs" title="File size">
                <span class="usa-sr-only">File size, </span>
                <span class="font-body-2xs" data-dz-size="keep">
                  <strong>99</strong> MB
                </span>
              <span>
              <span class="text-base-lighter padding-inline-x-1 display-none mobile:display-inline-block" aria-hidden="true">|</span>
              <button type="button" class="usa-button cfa-button cfa-button--danger usa-button--unstyled font-body-2xs" aria-hidden="true" focusable="false" data-dropzone="file-remove" data-dz-remove="keep"><span data-dropzone="file-remove-label">remove</span> <span class="usa-sr-only" data-dz-name="keep">preview-template__filename--testing-truncated-text.ext</span></button>
              <%# @data-dropzone  "remove"  removes contents before passing to Dropzone. These are used to test the various states for the thumbnail upload. %>
              <span data-dropzone="remove">
                <span class="text-base-lighter padding-inline-x-1 display-none mobile:display-inline-block" aria-hidden="true">|</span>
                <button type="button" class="usa-button cfa-button usa-button--unstyled font-body-2xs" aria-hidden="true" focusable="false" data-dropzone="toggle-preview-state" data-dropzone-preview-state="cfa-file-selector__preview dz-image-preview">base</button>
                <span class="text-base-lighter padding-inline-x-1 display-none mobile:display-inline-block" aria-hidden="true">|</span>
                <button type="button" class="usa-button cfa-button usa-button--unstyled font-body-2xs" aria-hidden="true" focusable="false" data-dropzone="toggle-preview-state" data-dropzone-preview-state="cfa-file-selector__preview dz-image-preview dz-processing">processing</button>
                <span class="text-base-lighter padding-inline-x-1 display-none mobile:display-inline-block" aria-hidden="true">|</span>
                <button type="button" class="usa-button cfa-button usa-button--unstyled font-body-2xs" aria-hidden="true" focusable="false" data-dropzone="toggle-preview-state" data-dropzone-preview-state="cfa-file-selector__preview dz-image-preview dz-processing dz-complete">complete</button>
                <span class="text-base-lighter padding-inline-x-1 display-none mobile:display-inline-block" aria-hidden="true">|</span>
                <button type="button" class="usa-button cfa-button usa-button--unstyled font-body-2xs" aria-hidden="true" focusable="false" data-dropzone="toggle-preview-state" data-dropzone-preview-state="cfa-file-selector__preview dz-image-preview dz-processing dz-success dz-complete">success</button>
                <span class="text-base-lighter padding-inline-x-1 display-none mobile:display-inline-block" aria-hidden="true">|</span>
                <button type="button" class="usa-button cfa-button usa-button--unstyled font-body-2xs" aria-hidden="true" focusable="false" data-dropzone="toggle-preview-state" data-dropzone-preview-state="cfa-file-selector__preview dz-image-preview dz-processing dz-success dz-complete dz-default">default</button>
                <span class="text-base-lighter padding-inline-x-1 display-none mobile:display-inline-block" aria-hidden="true">|</span>
                <button type="button" class="usa-button cfa-button usa-button--unstyled font-body-2xs" aria-hidden="true" focusable="false" data-dropzone="toggle-preview-state" data-dropzone-preview-state="cfa-file-selector__preview dz-image-preview dz-processing dz-error dz-complete">error</button>
              </span>
            </div>
          </div>
        </div>
      </li>
      <% end %>
    </ul>
  </div>
  <%# Strings used by the UploadDocument script will be pulled from this element %>
  <%# @hidden         "true"    Visually hides element %>
  <%# @aria-hidden    "true"    Hides element from the accessibility API %>
  <%# @data-dropzone  "remove"  removes contents before passing to Dropzone %>
  <div hidden="true" aria-hidden="true" data-dropzone="remove">
    <% dict.each do |item| %><p data-dropzone="dict" data-dropzone-dict="<%= item['key'] %>"><%= item['string'] %></p><% end %>
  </div>
</div>
Partial render

Below is an example of how to include the partial in a view from the package directory using the Ruby ERB class. Replace the argument values using your variables or context. In a Rails environment, the render method can be used instead with the same hash values.

<%= ERB.new(File.read('packages/cfa-file-selector/_cfa-file-selector.html.erb'), 0, 0, '@fileSelector').result_with_hash({id: id, previewTemplate: previewTemplate, fileInput: fileInput, defaultPreviewTemplate: defaultPreviewTemplate, dict: dict}) %>

uswds.codeforamerica.org

Learn more about Code for America by visiting codeforamerica.org