Erstelle eine stylishe, barrierefreie Datei-Auswahl in 3 Schritten

Native HMTL-Elemente sind von Haus aus barrierefrei. Die meisten lassen sich auch beliebig mit CSS stylen – wie ich in meinem Artikel über Web-Formulare gezeigt habe. Das Element zur Datei-Auswahl zählt leider nicht dazu.

Das <input type="file"> Element wird vom Browser als Schaltfläche dargestellt, welche den Datei-Auswahldialog des Betriebssystems öffnet. Diese Schaltfläche lässt sich gar nicht mit CSS stylen – weder die Größe und Farbe noch die Schriftart. Aber, kein Grund zu verzweifeln! Ich zeige euch wie es geht.

Eine Person sucht in einer Aktentasche nach einem Dokument. Foto: © Anete Lusina / pexels.com

Schritt 1: Native HTML-Elemente verwenden

Wenn ich ein Web-Formular mit Datei-Auswahl baue, dann sollen alle Nutzer:innen Dateien auswählen und hochladen können. Dazu zählen auch Menschen, die auf Screenreader oder die Tastaturbedienung angewiesen sind. Aus diesem Grund verwende ich das native, barrierefreie <input type="file"> Element. Ich habe eine Demo mit dem React-Framework erstellt. So sieht mein JSX-Code aus:

<label htmlFor="filepicker" className={styles.filePicker}> <span>Upload PDF</span> <input id="filepicker" type="file" accept=".pdf" aria-describedby="selected-file" onChange={event => onFilePickerChange(event)} /> </label> <p id="selected-file">{selectedFile}</p>

Ich verwende ein label Element, das die sichtbare Beschriftung meiner Datei-Auswahl ("Upload PDF") sowie das visuell verborgene input Element enthält. Auf diese Weise fungiert das label Element als sichtbare UI-Komponente, das sich beliebig stylen lässt (mehr dazu in Schritt 2).

Das p Element zeigt den Hinweis an, dass noch keine Datei ausgewählt wurde. Nach der Auswahl einer Datei zeigt es den Dateinamen (siehe Schritt 3). Dank des Attributs aria-describedby wird der Text auch von Screenreadern vorgelesen, wenn die Nutzer:innen mit der Datei-Auswahl interagieren.

Ich habe auch versucht, mithilfe von aria-hidden="true" den Absatz selbst vor assistiven Technologien zu verbergen. Da dies bei bestimmten Browser- und Screenreader-Kombinationen zu Problemen führte, habe ich das Attribut wieder entfernt. Jetzt hören Screenreader-Nutzer:innen den Hinweis möglicherweise zweimal. Das ist immer noch besser, als ihn gar nicht zu hören.

Schritt 2: Etwas CSS-Magie anwenden

Als nächstes mache ich das input Element mit CSS unsichtbar und positioniere es über dem label Element. Das erlaubt mir, die sichtbare Beschriftung benutzerdefiniert zu gestalten:

form label[for].filePicker { position: relative; background-color: rgb(49, 4, 92); color: white; font-size: 1rem; // ... more custom styling } form label[for].filePicker input[type=file] { position: absolute; top: 0; left: 0; height: 100%; width: 100%; opacity: 0; }

Achtet bitte darauf, das <input type="file"> Element nicht vor assistiven Technologien zu verbergen. Die Nutzung von display: none oder das Setzen einer Größe von null Pixel würde dazu führen, dass Screenreader das Element nicht mehr auffinden können.

Damit auch sehende Nutzer:innen ein visuelles Feedback erhalten, zeichne ich eine Outline für das label Element ein, wenn der Mauszeiger darüber bewegt wird oder wenn das darin verschachtelte input Element fokussiert wird.

form label[for].filePicker:focus-within, form label[for].filePicker:hover { outline: 2px solid black; outline-offset: 2px; }

Schritt 3: Eine Prise JavaScript

Als letzten Schritt möchte ich den Dateinamen anzeigen, wenn Nutzer:innen eine Datei ausgewählt haben. Zu diesem Zweck nutz ich das change Event, das ausgelöst wird, wenn der Eingabewert verändert wird.

const FileUpload: React.FunctionComponent = () => { const [selectedFile, setSelectedFile] = useState('No file selected'); const onFilePickerChange = (event: React.ChangeEvent<HTMLInputElement>) => { const files = Array.from(event.target.files ?? []); if (files.length > 0) { setSelectedFile(files[0].name); } } return ( // Only the relevant sections of the JSX code <input type="file" // ... onChange={event => onFilePickerChange(event)} /> <p id="selected-file">{selectedFile}</p> // ... ); };

Natürlich könnt ihr das auch in reinem JavaScript umsetzen – oder irgendeinem Framework eurer Wahl. Ich liefere euch nur ein Beispiel für eine Implementierung als React-Komponente. Seht euch den kompletten Quellcode auf GitHub an.

Die perfekte Datei-Auswahl, oder?

Hier seht ihr meine gestylte Datei-Auswahl in Aktion. Probiert es aus! Zum Vergleich habe ich auch ein unverändertes <input type="file"> Element eingebaut.

Ich bin mit dem Resultat an sich sehr glücklich. Allerdings geht es immer besser. Die Datei-Auswahl lässt sich super mit der Tastatur bedienen. Auch Screenreader-Nutzer:innen können mit dem Element gut interagieren, wobei es in Kombination mit gewissen Browsern und Plattformen kleinere Probleme gibt (siehe englische Version des Artikels).

Vielleicht werden diese Probleme durch zukünftige Updates gelöst. Oder ich finde noch eine bessere Lösung. Jedenfalls zeigt meine Demo, dass eine barrierefreie, gestylte Datei-Auswahl für Web-Formulare keine Hexerei ist.

Update am 26.03.2023

Ich habe mich geirrt: Es gibt tatsächlich eine Möglichkeit, das native <input type="file"> HTML-Element anzupassen. Ihr könnt das ::file-selector-button CSS-Pseudoelement verwenden, um die gerenderte Schaltfläche zu gestalten. Leider könnt ihr den Text, der innerhalb der Schaltfläche gerendert wird, nicht ändern. Hier findet ihr eine Demo mit weiteren Informationen dazu.

Update am 10.12.2023

Ich habe den HTML-Code in meinem Beispiel überarbeitet und die Screenreader-Tests mit den aktuellen Browserversionen erneut durchgeführt.

Erstellt am