You are here

Add visually hidden file type indicator to file field links - Drupal 8

I'm working on a website which has icons on file upload links, like so:

PDF file links with icons

This is nice for people who can see the icons, but what about those who can't? Accessibility means giving all users an equivalent experience, regardless of how they're accessing the site.

If the icons were inline images, we could put an alt of "PDF" on them and be done. However, in this case, they're background images.

So, we want to add a visually hidden span at the end of file links with the filetype, e.g. "(PDF)". This will let screen reader users know that the link will open a file. We want it to be visually hidden because it would be redundant for those who can see the icon.

I mucked about trying to override template_preprocess_file_link in my theme, with not much success. Finally I got it, and that combined with a custom file-link.html.twig file, gave me the result I wanted.

My preprocess function, placed in my theme's .theme file:

// Add variables for file-link.html.twig template so we can re-write it to include a visually-hidden filetype indication in the link for accessibility
function THEMENAME_preprocess_file_link(&$variables) {
  $variables['file_type'] = strtr($variables['file']->getMimeType(), array());
  $variables['file_url'] = file_create_url($variables['file']->getFileUri());
  if (empty($variables['description'])) {
    $variables['link_text'] = $variables['file']->getFilename();
  else {
    $variables['link_text'] = $variables['description'];

It's pretty self-explanatory, we're getting the file type from the file variable. We're getting the file URL so we can print it separately in the template. We're creating a link_text variable that is set to the name of the file, or whatever is in the file description field, if it's present.

Then in THEMEFOLDER/templates/field, we create field-link.html.twig, with this content:

<span{{ attributes }} role="text">
    <a href="{{ file_url }}">{{ link_text }}
        {% if (description is not empty) %}
            <span class="visually-hidden">({{ file_type|replace({'application/pdf': 'PDF', 'vnd.openxmlformats-officedocument.presentationml.presentation': 'PowerPoint', 'vnd.openxmlformats-officedocument.wordprocessingml.document': 'Word'}) }})</span>
        {% endif %}

The if statement says we show this only on links created from the description field. Why? If the file name is used, it already has the file extension on the end. Those names are not ideal and I prefer users to enter something in the description field, but if they don't, the file name is better than nothing.

We are filtering the file_type variable to replace the MIME type names with human-readable equivalents. In this case, our file uploads fields allow PDF, .docx, and .pptx filetypes. Your usecase may be different so you'll have to inspect the field output to see what the MIME type is for your filetype, and add it to the replace filter accordingly.

The resulting output for an example PDF:

<span class="file file--mime-application-pdf file--application-pdf" role="text">
  <a href="/sites/default/files/2019-05/job_shadow_safety_miosha.pdf">Job Shadow Safety MIOSHA
    <span class="visually-hidden">(PDF)</span>

Add new comment

Filtered HTML

  • Web page addresses and e-mail addresses turn into links automatically.
  • Allowed HTML tags: <a> <em> <strong> <cite> <blockquote> <code> <ul> <ol> <li> <dl> <dt> <dd>
  • Lines and paragraphs break automatically.

Plain text

  • No HTML tags allowed.
  • Web page addresses and e-mail addresses turn into links automatically.
  • Lines and paragraphs break automatically.