Skip to main content

Patterns Upload files

A three step process: Ask the user to upload a file, use the native file browser, and then show them the upload and ask them to confirm it

When to use

Use this pattern whenever you need users to upload one or more files.

When not to use

Do not ask users to upload files unless you really need to in order to deliver your service.

Uploading files can involve a number of interactions that users might find challenging, like:

  • scanning a document or taking a photo
  • sending a file from one device to another
  • selecting a file from a folder
  • waiting for a file to be uploaded

How to use

How you help users upload files depends on whether they need to upload:

  • a single file
  • multiple files, one at a time
  • multiple files at the same time

Help users upload a single file

Use the file upload component in the GOV.UK Design System to let users upload a single file.

<div class="govuk-form-group">
  <label class="govuk-label govuk-label--xl" for="file-upload-1">
    Upload receipt
  </label>

  <div id="file-upload-1-hint" class="govuk-hint">
    You can upload your receipt as a scanned copy or photo of the original
  </div>

  <input class="govuk-file-upload" id="file-upload-1" name="file-upload-1" type="file" aria-describedby="file-upload-1-hint">

</div>

<button type="submit" class="govuk-button" data-module="govuk-button">
  Continue
</button>

{% from "govuk/components/file-upload/macro.njk" import govukFileUpload %}
{% from "govuk/components/button/macro.njk" import govukButton %}

{{ govukFileUpload({
  id: "file-upload-1",
  name: "file-upload-1",
  isPageHeading: true,
  label: {
    text: "Upload receipt",
    classes: 'govuk-label--xl'
  },
  hint: {
    text: 'You can upload your receipt as a scanned copy or photo of the original'
  }
}) }}

{{ govukButton({ text: 'Continue' }) }}

Once users have uploaded their file, let them check it’s the right one by showing a preview.

For files where a preview might be difficult to check, consider how you can help users check the information.

For example, if the file is a spreadsheet, you could show its contents in a table.

<h1 class="govuk-heading-xl">Check receipt</h1>

<div class="govuk-grid-row">
  <div class="govuk-grid-column-two-thirds">
    <img src="/assets/images/receipt.jpg" alt="Starbacks receipt" width="100%">
  </div>
</div>

<p class="govuk-body">receipt.jpg, 2MB</p>

<div class="govuk-form-group">

  <fieldset class="govuk-fieldset">

    <legend class="govuk-fieldset__legend govuk-fieldset__legend--m">

      Is this file correct?

    </legend>

    <div class="govuk-radios" data-module="govuk-radios">

      <div class="govuk-radios__item">
        <input class="govuk-radios__input" id="correct" name="correct" type="radio" value="yes">
        <label class="govuk-label govuk-radios__label" for="correct">
          Yes, add this file
        </label>

      </div>

      <div class="govuk-radios__item">
        <input class="govuk-radios__input" id="correct-2" name="correct" type="radio" value="no">
        <label class="govuk-label govuk-radios__label" for="correct-2">
          No, I want to choose a different file
        </label>

      </div>

    </div>

  </fieldset>

</div>

<button type="submit" class="govuk-button" data-module="govuk-button">
  Continue
</button>

{% from "govuk/components/button/macro.njk" import govukButton %}
{% from "govuk/components/radios/macro.njk" import govukRadios %}

<h1 class="govuk-heading-xl">Check receipt</h1>

<div class="govuk-grid-row">
  <div class="govuk-grid-column-two-thirds">
      <img src="{{ '/assets/images/receipt.jpg' | url }}" alt="Starbacks receipt" width="100%">
  </div>
</div>

<p class="govuk-body">receipt.jpg, 2MB</p>

{{ govukRadios({
  idPrefix: "correct",
  name: "correct",
  fieldset: {
    legend: {
      text: "Is this file correct?",
      classes: "govuk-fieldset__legend--m"
    }
  },
  items: [
    {
      value: "yes",
      text: "Yes, add this file"
    },
    {
      value: "no",
      text: "No, I want to choose a different file"
    }
  ]
}) }}

{{ govukButton({ text: 'Continue' }) }}

Let users upload additional files

If users need the option to upload more than one file, include an additional screen asking if they want to upload another.

<h1 class="govuk-heading-xl">Upload receipts</h1>

<div class="govuk-grid-row">
  <div class="govuk-grid-column-two-thirds">
    <h2 class="govuk-heading-m">Files added</h2>

    <dl class="govuk-summary-list">

      <div class="govuk-summary-list__row">
        <dt class="govuk-summary-list__key">
          File 1
        </dt>
        <dd class="govuk-summary-list__value">
          <a download href="/" class="govuk-link">receipta.jpg</a>, 2MB
        </dd>

        <dd class="govuk-summary-list__actions">
          <a class="govuk-link" href="#">Delete<span class="govuk-visually-hidden"> file 1</span></a>

        </dd>

      </div>

      <div class="govuk-summary-list__row">
        <dt class="govuk-summary-list__key">
          File 2
        </dt>
        <dd class="govuk-summary-list__value">
          <a download href="/" class="govuk-link">receipt2.jpg</a>, 5MB
        </dd>

        <dd class="govuk-summary-list__actions">
          <a class="govuk-link" href="#">Delete<span class="govuk-visually-hidden"> file 2</span></a>

        </dd>

      </div>

    </dl>

  </div>
</div>

<div class="govuk-form-group">

  <fieldset class="govuk-fieldset">

    <legend class="govuk-fieldset__legend govuk-fieldset__legend--m">

      Do you want to upload another receipt?

    </legend>

    <div class="govuk-radios" data-module="govuk-radios">

      <div class="govuk-radios__item">
        <input class="govuk-radios__input" id="another" name="another" type="radio" value="yes">
        <label class="govuk-label govuk-radios__label" for="another">
          Yes
        </label>

      </div>

      <div class="govuk-radios__item">
        <input class="govuk-radios__input" id="another-2" name="another" type="radio" value="no">
        <label class="govuk-label govuk-radios__label" for="another-2">
          No
        </label>

      </div>

    </div>

  </fieldset>

</div>

<button type="submit" class="govuk-button" data-module="govuk-button">
  Continue
</button>

{% from "govuk/components/summary-list/macro.njk" import govukSummaryList %}
{% from "govuk/components/button/macro.njk" import govukButton %}
{% from "govuk/components/radios/macro.njk" import govukRadios %}

<h1 class="govuk-heading-xl">Upload receipts</h1>

<div class="govuk-grid-row">
  <div class="govuk-grid-column-two-thirds">
    <h2 class="govuk-heading-m">Files added</h2>

    {{ govukSummaryList({
      rows: [
        {
          key: {
            text: "File 1"
          },
          value: {
            html: '<a download href="/" class="govuk-link">receipta.jpg</a>, 2MB'
          },
          actions: {
            items: [
              {
                href: "#",
                text: "Delete",
                visuallyHiddenText: "file 1"
              }
            ]
          }
        },
        {
          key: {
            text: "File 2"
          },
          value: {
            html: '<a download href="/" class="govuk-link">receipt2.jpg</a>, 5MB'
          },
          actions: {
            items: [
              {
                href: "#",
                text: "Delete",
                visuallyHiddenText: "file 2"
              }
            ]
          }
        }
      ]
    }) }}
</div>
</div>

{{ govukRadios({
  idPrefix: "another",
  name: "another",
  fieldset: {
    legend: {
      text: "Do you want to upload another receipt?",
      classes: "govuk-fieldset__legend--m"
    }
  },
  items: [
    {
      value: "yes",
      text: "Yes"
    },
    {
      value: "no",
      text: "No"
    }
  ]
}) }}

{{ govukButton({ text: 'Continue' }) }}

Deleting a file

What happens when a user deletes a file depends on whether the list contains 1 file or multiple.

If there's multiple files in the list, display a success message at the top of the page.

<div class="moj-banner moj-banner--success" role="region" aria-label="Success">

  <svg class="moj-banner__icon" fill="currentColor" role="presentation" focusable="false" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 25 25" height="25" width="25">
    <path d="M25,6.2L8.7,23.2L0,14.1l4-4.2l4.7,4.9L21,2L25,6.2z" />
  </svg>

  <div class="moj-banner__message">File named abc.jpg has been deleted</div>

</div>

<h1 class="govuk-heading-xl">Upload receipts</h1>

<div class="govuk-grid-row">
  <div class="govuk-grid-column-two-thirds">
    <h2 class="govuk-heading-m">Files added</h2>

    <dl class="govuk-summary-list">

      <div class="govuk-summary-list__row">
        <dt class="govuk-summary-list__key">
          File 1
        </dt>
        <dd class="govuk-summary-list__value">
          <a download href="/">receipta.jpg</a>, 2MB
        </dd>

        <dd class="govuk-summary-list__actions">
          <a class="govuk-link" href="#">Delete<span class="govuk-visually-hidden"> file 1</span></a>

        </dd>

      </div>

      <div class="govuk-summary-list__row">
        <dt class="govuk-summary-list__key">
          File 2
        </dt>
        <dd class="govuk-summary-list__value">
          <a download href="/">receipt2.jpg</a>, 5MB
        </dd>

        <dd class="govuk-summary-list__actions">
          <a class="govuk-link" href="#">Delete<span class="govuk-visually-hidden"> file 2</span></a>

        </dd>

      </div>

    </dl>

  </div>
</div>

<div class="govuk-form-group">

  <fieldset class="govuk-fieldset">

    <legend class="govuk-fieldset__legend govuk-fieldset__legend--m">

      Do you want to upload another receipt?

    </legend>

    <div class="govuk-radios" data-module="govuk-radios">

      <div class="govuk-radios__item">
        <input class="govuk-radios__input" id="another" name="another" type="radio" value="yes">
        <label class="govuk-label govuk-radios__label" for="another">
          Yes
        </label>

      </div>

      <div class="govuk-radios__item">
        <input class="govuk-radios__input" id="another-2" name="another" type="radio" value="no">
        <label class="govuk-label govuk-radios__label" for="another-2">
          No
        </label>

      </div>

    </div>

  </fieldset>

</div>

<button type="submit" class="govuk-button" data-module="govuk-button">
  Continue
</button>

{% from "govuk/components/summary-list/macro.njk" import govukSummaryList %}
{% from "govuk/components/button/macro.njk" import govukButton %}
{% from "govuk/components/radios/macro.njk" import govukRadios %}
{% from "moj/components/banner/macro.njk" import mojBanner %}

{{ mojBanner({
  type: 'success',
  text: 'File named abc.jpg has been deleted',
  iconFallbackText: 'Success'
}) }}

<h1 class="govuk-heading-xl">Upload receipts</h1>

<div class="govuk-grid-row">
  <div class="govuk-grid-column-two-thirds">
    <h2 class="govuk-heading-m">Files added</h2>

    {{ govukSummaryList({
      rows: [
        {
          key: {
            text: "File 1"
          },
          value: {
            html: '<a download href="/">receipta.jpg</a>, 2MB'
          },
          actions: {
            items: [
              {
                href: "#",
                text: "Delete",
                visuallyHiddenText: "file 1"
              }
            ]
          }
        },
        {
          key: {
            text: "File 2"
          },
          value: {
            html: '<a download href="/">receipt2.jpg</a>, 5MB'
          },
          actions: {
            items: [
              {
                href: "#",
                text: "Delete",
                visuallyHiddenText: "file 2"
              }
            ]
          }
        }
      ]
    }) }}
</div>
</div>

{{ govukRadios({
  idPrefix: "another",
  name: "another",
  fieldset: {
    legend: {
      text: "Do you want to upload another receipt?",
      classes: "govuk-fieldset__legend--m"
    }
  },
  items: [
    {
      value: "yes",
      text: "Yes"
    },
    {
      value: "no",
      text: "No"
    }
  ]
}) }}

{{ govukButton({ text: 'Continue' }) }}

If there's 1 file in the list, take users to the upload screen with a success message at the top of the page.

<div class="moj-banner moj-banner--success" role="region" aria-label="Success">

  <svg class="moj-banner__icon" fill="currentColor" role="presentation" focusable="false" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 25 25" height="25" width="25">
    <path d="M25,6.2L8.7,23.2L0,14.1l4-4.2l4.7,4.9L21,2L25,6.2z" />
  </svg>

  <div class="moj-banner__message">File named abc.jpg has been deleted</div>

</div>

<div class="govuk-form-group">
  <label class="govuk-label govuk-label--xl" for="file-upload-1">
    Upload receipts
  </label>

  <div id="file-upload-1-hint" class="govuk-hint">
    You can upload your receipt as a scanned copy or photo of the original
  </div>

  <input class="govuk-file-upload" id="file-upload-1" name="file-upload-1" type="file" aria-describedby="file-upload-1-hint">

</div>

<button type="submit" class="govuk-button" data-module="govuk-button">
  Continue
</button>

{% from "govuk/components/file-upload/macro.njk" import govukFileUpload %}
{% from "govuk/components/button/macro.njk" import govukButton %}
{% from "moj/components/banner/macro.njk" import mojBanner %}

{{ mojBanner({
  type: 'success',
  text: 'File named abc.jpg has been deleted',
  iconFallbackText: 'Success'
}) }}

{{ govukFileUpload({
  id: "file-upload-1",
  name: "file-upload-1",
  isPageHeading: true,
  label: {
    text: "Upload receipts",
    classes: 'govuk-label--xl'
  },
  hint: {
    text: 'You can upload your receipt as a scanned copy or photo of the original'
  }
}) }}

{{ govukButton({ text: 'Continue' }) }}

Let users upload multiple files at once

When users need to upload multiple files, start by letting them upload one file at a time, as shown in the previous example.

This is the simplest approach, especially for users with low digital literacy.

However, in services designed for regular and repeated use, like caseworking systems, it might be more helpful to let users upload multiple files at once.

Only take this approach if user research shows uploading files one at a time is problematic.

To let users upload multiple files at once, use the multi file upload component.

Let users enter additional information about their files

Files often have long, meaningless names by default, so you can let users enter a friendly name to make them easier to find later.

You can also let users provide a description of what a file contains, if research shows this is useful.

If you do add additional fields, show the answers on the check screen along with the file.

Accept multiple file types

Let users upload as many different file types as possible. You can convert them automatically if you need to. If you must limit file types, let users know by using hint text.

Reduce file size automatically

Wherever possible, let users upload large file sizes.

When showing users a preview of a large file to check, consider if you can show a smaller version of that file so that it loads faster.

If you do this, you can store the original file and give users the option to view it if they need to.

Error messages

Use the file upload error messages from the GOV.UK Design System.

Get help and contribute

Get help

You can contact the MoJ Design System team for help or support using this pattern.

Help improve this pattern

The MoJ Design System team would like to hear:

  • how you have used this pattern in your service
  • any feedback you have about its usage, for example accessibility or ideas for improvement

Add these comments to the upload files discussion on Github.