Naar de inhoud
Gratis naslagwerk over HTML
HTML leren en naslaan
Naslag / Formulieren

Het element <input type="file">

<input>-elementen met type="file" laten de gebruiker een of meer bestanden kiezen uit de opslag van hun apparaat. Eenmaal gekozen, kunnen de bestanden naar een server worden geüpload met behulp van formulierverzending, of bewerkt worden met JavaScript-code en de File API.

Code
<label for="avatar">Choose a profile picture:</label>

<input type="file" id="avatar" name="avatar" accept="image/png, image/jpeg" />
Resultaat in de browser

Waarde

Het value-attribuut van een bestandsinvoerveld bevat een tekenreeks die het pad naar het/de geselecteerde bestand(en) voorstelt. Als er nog geen bestand is geselecteerd, is de waarde een lege tekenreeks (""). Wanneer de gebruiker meerdere bestanden heeft geselecteerd, geeft de value het eerste bestand in de lijst van geselecteerde bestanden weer. De overige bestanden kunnen worden geïdentificeerd met behulp van de HTMLInputElement.files-eigenschap van het invoerveld.

Opmerking

De waarde is altijd de bestandsnaam voorafgegaan door C:\fakepath\, wat niet het werkelijke pad van het bestand is. Dit is om te voorkomen dat kwaadwillige software de bestandsstructuur van de gebruiker kan achterhalen.

Aanvullende attributen

Naast de gemeenschappelijke attributen die door alle <input>-elementen worden gedeeld, ondersteunen invoervelden van het type file ook de volgende attributen.

accept

De waarde van het accept-attribuut is een tekenreeks die de bestandstypen definieert die het bestandsinvoerveld moet accepteren. Deze tekenreeks is een door komma's gescheiden lijst van unieke bestandstypespecificaties. Omdat een bepaald bestandstype op meer dan één manier geïdentificeerd kan worden, is het nuttig om een uitgebreide set typespecificaties op te geven wanneer u bestanden van een bepaald formaat nodig heeft.

Er zijn bijvoorbeeld verschillende manieren waarop Microsoft Word-bestanden geïdentificeerd kunnen worden, dus een site die Word-bestanden accepteert, zou een <input> als volgt kunnen gebruiken:

HTML
<input
  type="file"
  id="docpicker"
  accept=".doc,.docx,.xml,application/msword,application/vnd.openxmlformats-officedocument.wordprocessingml.document" />

capture

De waarde van het capture-attribuut is een tekenreeks die aangeeft welke camera gebruikt moet worden voor het vastleggen van afbeeldings- of videogegevens, als het accept-attribuut aangeeft dat het invoerveld van een van die typen moet zijn. Een waarde van user geeft aan dat de naar de gebruiker gerichte camera en/of microfoon gebruikt moet worden. Een waarde van environment geeft aan dat de naar buiten gerichte camera en/of microfoon gebruikt moet worden. Als dit attribuut ontbreekt, staat het de user agent vrij om zelf te beslissen wat te doen. Als de gevraagde richting niet beschikbaar is, kan de user agent terugvallen op zijn standaardmodus.

Opmerking

capture was voorheen een Booleaans attribuut dat, indien aanwezig, verzocht dat het media-opnameapparaat van het apparaat, zoals een camera of microfoon, gebruikt werd in plaats van een bestandsinvoerveld aan te vragen.

multiple

Wanneer het Booleaanse attribuut multiple is opgegeven, staat het bestandsinvoerveld de gebruiker toe om meer dan één bestand te selecteren.

Niet-standaard attributen

Naast de hierboven vermelde attributen zijn de volgende niet-standaard attributen beschikbaar op sommige browsers. U kunt ze het beste vermijden waar mogelijk, aangezien het gebruik ervan het vermogen van uw code om te functioneren in browsers die ze niet implementeren, zal beperken.

webkitdirectory

Het Booleaanse attribuut webkitdirectory geeft, indien aanwezig, aan dat alleen mappen geselecteerd kunnen worden door de gebruiker in de interface van de bestandskiezer. Zie HTMLInputElement.webkitdirectory voor aanvullende details en voorbeelden.

Unieke bestandstypespecificaties

Een unieke bestandstypespecificatie is een tekenreeks die een bestandstype beschrijft dat door de gebruiker geselecteerd kan worden in een <input>-element van het type file. Elke unieke bestandstypespecificatie kan een van de volgende vormen aannemen:

  • Een geldige, niet-hoofdlettergevoelige bestandsextensie, beginnend met een punt ("."). Bijvoorbeeld: .jpg, .pdf, of .doc.
  • Een geldige MIME-typetekenreeks, zonder extensies.
  • De tekenreeks audio/*, wat "elk audiobestand" betekent.
  • De tekenreeks video/*, wat "elk videobestand" betekent.
  • De tekenreeks image/*, wat "elk afbeeldingsbestand" betekent.

Het accept-attribuut neemt als waarde een tekenreeks die een of meer van deze unieke bestandstypespecificaties bevat, gescheiden door komma's. Een bestandskiezer die inhoud nodig heeft die als afbeelding gepresenteerd kan worden, inclusief zowel standaard afbeeldingsformaten als PDF-bestanden, zou er bijvoorbeeld als volgt uit kunnen zien:

HTML
<input type="file" accept="image/*,.pdf" />

Bestandsinvoervelden gebruiken

Een eenvoudig voorbeeld

HTML
<form method="post" enctype="multipart/form-data">
  <div>
    <label for="file">Choose file to upload</label>
    <input type="file" id="file" name="file" multiple />
  </div>
  <div>
    <button>Submit</button>
  </div>
</form>
CSS
div {
  margin-bottom: 10px;
}

Dit levert de volgende uitvoer op:

Resultaat in de browser
Opmerking

U kunt dit voorbeeld ook op GitHub vinden — zie de broncode, en ook bekijk het live in werking.

Ongeacht het apparaat of besturingssysteem van de gebruiker, biedt het bestandsinvoerveld een knop die een dialoogvenster voor het kiezen van bestanden opent, waarmee de gebruiker een bestand kan kiezen.

Door het multiple-attribuut op te nemen, zoals hierboven getoond, wordt aangegeven dat er meerdere bestanden tegelijk gekozen kunnen worden. De gebruiker kan meerdere bestanden kiezen uit de bestandskiezer op elke manier die het gekozen platform toestaat (bijvoorbeeld door Shift of Control ingedrukt te houden en vervolgens te klikken). Als u wilt dat de gebruiker slechts één bestand per <input> kiest, laat u het multiple-attribuut weg.

Informatie over geselecteerde bestanden verkrijgen

De geselecteerde bestanden worden geretourneerd door de HTMLInputElement.files-eigenschap van het element, wat een FileList-object is dat een lijst met File-objecten bevat. De FileList gedraagt zich als een array, dus u kunt de length-eigenschap ervan controleren om het aantal geselecteerde bestanden te achterhalen.

Elk File-object bevat de volgende informatie:

nameDe naam van het bestand.
lastModifiedEen getal dat de datum en tijd aangeeft waarop het bestand voor het laatst is gewijzigd, in milliseconden sinds het UNIX-epoch (1 januari 1970, om middernacht).
lastModifiedDate VerouderdEen Date-object dat de datum en tijd voorstelt waarop het bestand voor het laatst is gewijzigd. Dit is verouderd en zou niet gebruikt moeten worden. Gebruik in plaats daarvan lastModified.
sizeDe grootte van het bestand in bytes.
typeHet MIME-type van het bestand.
webkitRelativePath Niet-standaardEen tekenreeks die het pad van het bestand aangeeft ten opzichte van de basismap die geselecteerd is in een mapkiezer (dat wil zeggen, een file-kiezer waarin het webkitdirectory-attribuut is ingesteld). Dit is niet-standaard en moet met voorzichtigheid gebruikt worden.

Geaccepteerde bestandstypen beperken

Vaak wilt u niet dat de gebruiker willekeurig welk bestandstype dan ook kan kiezen; in plaats daarvan wilt u vaak dat ze bestanden van een specifiek type of specifieke typen selecteren. Als uw bestandsinvoerveld gebruikers bijvoorbeeld een profielfoto laat uploaden, wilt u waarschijnlijk dat ze web-compatibele afbeeldingsformaten selecteren, zoals JPEG of PNG.

Acceptabele bestandstypen kunnen worden opgegeven met het accept-attribuut, dat een door komma's gescheiden lijst van toegestane bestandsextensies of MIME-types neemt. Enkele voorbeelden:

  • accept="image/png" of accept=".png" — accepteert PNG-bestanden.
  • accept="image/png, image/jpeg" of accept=".png, .jpg, .jpeg" — accepteer PNG- of JPEG-bestanden.
  • accept="image/*" — accepteer elk bestand met een image/* MIME-type. (Op veel mobiele apparaten kan de gebruiker hierbij ook een foto maken met de camera.)
  • accept=".doc,.docx,.xml,application/msword,application/vnd.openxmlformats-officedocument.wordprocessingml.document" — accepteer alles wat op een MS Word-document lijkt.

Laten we eens naar een uitgebreider voorbeeld kijken:

HTML
<form method="post" enctype="multipart/form-data">
  <div>
    <label for="profile_pic">Choose file to upload</label>
    <input
      type="file"
      id="profile_pic"
      name="profile_pic"
      accept=".jpg, .jpeg, .png" />
  </div>
  <div>
    <button>Submit</button>
  </div>
</form>
CSS
div {
  margin-bottom: 10px;
}

Dit levert een vergelijkbare uitvoer op als het vorige voorbeeld:

Resultaat in de browser
Opmerking

U kunt dit voorbeeld ook op GitHub vinden — zie de broncode, en ook bekijk het live in werking.

Het lijkt er misschien op, maar als u probeert een bestand te selecteren met dit invoerveld, ziet u dat de bestandskiezer u alleen de bestandstypen laat selecteren die zijn opgegeven in de waarde van accept (de exacte interface verschilt per browser en besturingssysteem).

Het accept-attribuut valideert de typen van de geselecteerde bestanden niet; het geeft browsers aanwijzingen om gebruikers te begeleiden bij het selecteren van de juiste bestandstypen. Het is (in de meeste gevallen) nog steeds mogelijk voor gebruikers om een optie in de bestandskiezer om te schakelen waardoor ze dit kunnen omzeilen en elk gewenst bestand kunnen selecteren, en dus onjuiste bestandstypen kunnen kiezen.

Daarom moet u ervoor zorgen dat het accept-attribuut wordt ondersteund door passende server-side validatie.

Annuleringen detecteren

De cancel-gebeurtenis wordt geactiveerd wanneer de gebruiker zijn selectie niet wijzigt, en dus de eerder geselecteerde bestanden opnieuw selecteert. De cancel-gebeurtenis wordt ook geactiveerd wanneer het dialoogvenster van de bestandskiezer wordt gesloten of geannuleerd, via de knop "annuleren" of de escape-toets.

De volgende code logt bijvoorbeeld naar de console als de gebruiker de pop-up sluit zonder een bestand te selecteren:

JS
const elem = document.createElement("input");
elem.type = "file";
elem.addEventListener("cancel", () => {
  console.log("Cancelled.");
});
elem.addEventListener("change", () => {
  if (elem.files.length === 1) {
    console.log("File selected: ", elem.files[0]);
  }
});
elem.click();

Opmerkingen

  1. U kunt de waarde van een bestandskiezer niet vanuit een script instellen — het volgende heeft bijvoorbeeld geen effect:

    JS
    const input = document.querySelector("input[type=file]");
    input.value = "foo";
  2. Wanneer er een bestand wordt gekozen met een <input type="file">, wordt het werkelijke pad naar het bronbestand om vanzelfsprekende beveiligingsredenen niet getoond in het value-attribuut van het invoerveld. In plaats daarvan wordt de bestandsnaam getoond, voorafgegaan door C:\fakepath\. Er zijn wat historische redenen voor deze eigenaardigheid, maar het wordt door alle moderne browsers ondersteund, en is zelfs gedefinieerd in de specificatie.

Voorbeelden

In dit voorbeeld presenteren we een iets geavanceerdere bestandskiezer die gebruikmaakt van de bestandsinformatie die beschikbaar is in de HTMLInputElement.files-eigenschap, en die ook een paar slimme trucjes laat zien.

Opmerking

U kunt de volledige broncode voor dit voorbeeld op GitHub bekijken — file-example.html (bekijk het ook live). We zullen de CSS niet toelichten; de JavaScript is de belangrijkste focus.

Laten we eerst naar de HTML kijken:

HTML
<form method="post" enctype="multipart/form-data">
  <div>
    <label for="image_uploads">Choose images to upload (PNG, JPG)</label>
    <input
      type="file"
      id="image_uploads"
      name="image_uploads"
      accept=".jpg, .jpeg, .png"
      multiple />
  </div>
  <div class="preview">
    <p>No files currently selected for upload</p>
  </div>
  <div>
    <button>Submit</button>
  </div>
</form>
CSS
html {
  font-family: sans-serif;
}

form {
  background: #cccccc;
  margin: 0 auto;
  padding: 20px;
  border: 1px solid black;
}

form ol {
  padding-left: 0;
}

form li,
div > p {
  background: #eeeeee;
  display: flex;
  justify-content: space-between;
  margin-bottom: 10px;
  list-style-type: none;
  border: 1px solid black;
}

form img {
  height: 64px;
  order: 1;
}

form p {
  line-height: 32px;
  padding-left: 10px;
}

form label,
form button {
  background-color: #7f9ccb;
  padding: 5px 10px;
  border-radius: 5px;
  border: 1px ridge black;
  font-size: 0.8rem;
  height: auto;
}

form label:hover,
form button:hover {
  background-color: #2d5ba3;
  color: white;
}

form label:active,
form button:active {
  background-color: #0d3f8f;
  color: white;
}

Dit lijkt op wat we al eerder hebben gezien — niets bijzonders om te vermelden.

Laten we vervolgens de JavaScript doorlopen.

In de eerste regels script krijgen we verwijzingen naar het formulierinvoerveld zelf, en naar het <div>-element met de klasse .preview. Vervolgens verbergen we het <input>-element — we doen dit omdat bestandsinvoervelden meestal lelijk zijn, moeilijk te stylen, en inconsistent qua vormgeving tussen browsers. U kunt het input-element activeren door op het bijbehorende <label> te klikken, dus het is beter om het input-element visueel te verbergen en het label vorm te geven als een knop, zodat de gebruiker weet dat hij ermee moet interageren als hij bestanden wil uploaden.

JS
const input = document.querySelector("input");
const preview = document.querySelector(".preview");

input.style.opacity = 0;
Opmerking

opacity wordt gebruikt om het bestandsinvoerveld te verbergen in plaats van visibility: hidden of display: none, omdat ondersteunende technologie de laatste twee stijlen interpreteert als betekenend dat het bestandsinvoerveld niet interactief is.

Vervolgens voegen we een gebeurtenislistener toe aan het invoerveld om te luisteren naar wijzigingen in de geselecteerde waarde ervan (in dit geval, wanneer er bestanden geselecteerd worden). De gebeurtenislistener roept onze aangepaste functie updateImageDisplay() aan.

JS
input.addEventListener("change", updateImageDisplay);

Telkens wanneer de functie updateImageDisplay() wordt aangeroepen, doen we het volgende:

  • We gebruiken een while-lus om de vorige inhoud van de voorbeeld-<div> te legen.

  • We halen het FileList-object op dat de informatie over alle geselecteerde bestanden bevat, en slaan het op in een variabele genaamd curFiles.

  • We controleren of er geen bestanden geselecteerd zijn, door te controleren of curFiles.length gelijk is aan 0. Zo ja, dan tonen we een bericht in de voorbeeld-<div> dat er geen bestanden zijn geselecteerd.

  • Als er bestanden wel zijn geselecteerd, doorlopen we ze allemaal, en tonen we informatie erover in de voorbeeld-<div>. Enkele dingen om hierbij op te merken:

  • We gebruiken de aangepaste functie validFileType() om te controleren of het bestand van het juiste type is (bijvoorbeeld de afbeeldingstypen die zijn opgegeven in het accept-attribuut).

  • Als dat zo is, doen we het volgende:

    • We tonen de naam en bestandsgrootte in een lijstitem binnen de voorgaande <div> (verkregen via file.name en file.size). De aangepaste functie returnFileSize() retourneert een netjes opgemaakte versie van de grootte in bytes/KB/MB (standaard rapporteert de browser de grootte in absolute bytes).
    • We genereren een miniatuurvoorbeeld van de afbeelding door URL.createObjectURL(file) aan te roepen. Vervolgens voegen we ook de afbeelding toe aan het lijstitem, door een nieuwe <img> te maken en de src ervan in te stellen op de miniatuur.
  • Als het bestandstype ongeldig is, tonen we in een lijstitem een bericht dat de gebruiker een ander bestandstype moet selecteren.

JS
function updateImageDisplay() {
  while (preview.firstChild) {
    preview.removeChild(preview.firstChild);
  }

  const curFiles = input.files;
  if (curFiles.length === 0) {
    const para = document.createElement("p");
    para.textContent = "No files currently selected for upload";
    preview.appendChild(para);
  } else {
    const list = document.createElement("ol");
    preview.appendChild(list);

    for (const file of curFiles) {
      const listItem = document.createElement("li");
      const para = document.createElement("p");
      if (validFileType(file)) {
        para.textContent = `File name ${file.name}, file size ${returnFileSize(
          file.size,
        )}.`;
        const image = document.createElement("img");
        image.src = URL.createObjectURL(file);
        image.alt = image.title = file.name;

        listItem.appendChild(image);
        listItem.appendChild(para);
      } else {
        para.textContent = `File name ${file.name}: Not a valid file type. Update your selection.`;
        listItem.appendChild(para);
      }

      list.appendChild(listItem);
    }
  }
}

De aangepaste functie validFileType() neemt een File-object als parameter, en gebruikt vervolgens Array.prototype.includes() om te controleren of een van de waarden in fileTypes overeenkomt met de type-eigenschap van het bestand. Als er een overeenkomst gevonden wordt, retourneert de functie true. Als er geen overeenkomst gevonden wordt, retourneert deze false.

JS
// https://voorbeeld.nl/en-US/docs/Web/Media/Guides/Formats/Image_types
const fileTypes = [
  "image/apng",
  "image/bmp",
  "image/gif",
  "image/jpeg",
  "image/pjpeg",
  "image/png",
  "image/svg+xml",
  "image/tiff",
  "image/webp",
  "image/x-icon",
];

function validFileType(file) {
  return fileTypes.includes(file.type);
}

De functie returnFileSize() neemt een getal (van bytes, afkomstig van de size-eigenschap van het huidige bestand), en zet het om in een netjes opgemaakte grootte in bytes/KB/MB.

JS
function returnFileSize(number) {
  if (number < 1e3) {
    return `${number} bytes`;
  } else if (number >= 1e3 && number < 1e6) {
    return `${(number / 1e3).toFixed(1)} KB`;
  }
  return `${(number / 1e6).toFixed(1)} MB`;
}
Opmerking

De eenheden "KB" en "MB" hier gebruiken de conventie van het SI-voorvoegsel van 1KB = 1000B, vergelijkbaar met macOS. Verschillende systemen geven bestandsgroottes op verschillende manieren weer — Ubuntu gebruikt bijvoorbeeld IEC-voorvoegsels waarbij 1KiB = 1024B, terwijl RAM-specificaties vaak SI-voorvoegsels gebruiken om machten van twee weer te geven (1KB = 1024B). Om deze reden hebben we 1e3 (1000) en 1e6 (100000) gebruikt in plaats van 1024 en 1048576. In uw toepassing moet u het eenhedensysteem duidelijk aan uw gebruikers communiceren als de exacte grootte belangrijk is.

JS
const button = document.querySelector("form button");
button.addEventListener("click", (e) => {
  e.preventDefault();
  const para = document.createElement("p");
  para.append("Image uploaded!");
  preview.replaceChildren(para);
});

Het voorbeeld ziet er als volgt uit; probeer het eens uit:

Resultaat in de browser

Technische samenvatting

Waarde Een tekenreeks die het pad naar het geselecteerde bestand voorstelt.
Gebeurtenissen change, input en cancel
Ondersteunde gemeenschappelijke attributen required
Aanvullende attributen accept, capture, multiple
IDL-attributen files en value
DOM-interface

HTMLInputElement

Impliciete ARIA-rol geen overeenkomstige rol

Verwante elementen