Field type="file" is not accessible (Form Element)

Well, yes it is, but only halfway. Let me explain to you.

This is how a file type field from the Bricks form is rendered in the frontend:

<div class="form-group file" role="group" aria-labelledby="label-uhfdyw">
  <label for="form-field-84b8cc" class="required">Files</label>
  <input multiple="" data-limit="3" data-files-ref="84b8cc" id="form-field-84b8cc" name="form-field-uhfdyw" aria-label="Files" type="file" value="" required="">
  <div data-files-ref="84b8cc" class="file-result" data-error-limit="File %s not accepted. File limit exceeded." data-error-size="File %s not accepted. Size limit exceeded.">
    <span class="text"></span>
    <button type="button" class="bricks-button remove">Remove</button>
  </div>
  <label for="form-field-84b8cc" class="required choose-files">Upload File</label>				
</div>

The input field of type=“file” is hidden and in exchange a <label> element is added with the class .choose-files

Style of the default input[type="file"] :

:where(.brxe-form) input.file, :where(.brxe-form) input[type=file] {
    display: block;
    height: 0;
    opacity: 0;
    width: 0;
}

Style of the substitute “input file” (the <label> tag):

:where(.brxe-form) .choose-files {
    border-style: solid;
    border-width: 1px;
    cursor: pointer;
    display: inline-block;
    line-height: 40px;
    padding: 0 15px;
    text-align: center;
    text-transform: none;
    white-space: nowrap;
    width: auto;
}

When using the ‘tab’ button to navigate the website, the :focus-visible styles are not displaying correctly for the input[type=file], because his CSS propierties (height:0; width:0, opacity:0).

In other words, users can access the field and upload a file but the field is not visually selected.

I am a person who cares a lot about the design and CSS specifications of :focus-visible. I consider that the :focus-visible should appear for the <label> element with class .choose-files and not for the input[type="file"], since the latter is not what the user sees in the form .

A possible solution:

Adding the attribute tabindex=0 to the <label> element makes it accessible with ‘tab’.

Furthermore, you must prevent the input from being accessible (otherwise you would have to press ‘tab’ twice to continue browsing). To do this, simply modify the display:block property to display:none; for the input[type=file]. This also avoids unexpected behavior when we add a CSS property to the containing group, that is, to the .formgroup.file selector, for example if we apply a gap.

New <label> HTML:
<label for="form-field-84b8cc" class="required choose-files" tabindex=0 >Upload File </label>

New input[type=file] CSS styles:

:where(.brxe-form) input.file, :where(.brxe-form) input[type=file] {
    display: none;
    height: 0;
    opacity: 0;
    width: 0;
}

In the meanwhile I fixed everything with this JS snippet.

document.addEventListener('DOMContentLoaded', function () {
    document.querySelectorAll('label.choose-files').forEach(label => {
        label.setAttribute('tabindex', '0');
        label.addEventListener('keydown', function (event) {
            if (event.key === ' ' || event.key === 'Spacebar') {
                const inputId = this.getAttribute('for');
                const inputFile = document.getElementById(inputId);
                inputFile.click();
                event.preventDefault();
            }
        });
    });
    document.querySelectorAll('.brxe-form input[type="file"]').forEach(input => {
        input.style.display = 'none';
    });
});

I want to record a video exemplifying everything described. But in the meantime I want to record this in writing.

BTW, If we had the possibility to create nested forms this would be very easy to solve without the need to use JS (to add the attribute). Maybe it’s time to launch a nested form, so we can have more control over each field independently.

Thank you.

1 Like