Skip to content

HTML APIs — Geolocation, Drag & Drop, File API

DodaTech Updated 2026-06-24 8 min read

In this tutorial, you'll learn about HTML APIs. We cover key concepts, practical examples, and best practices.

Modern browsers expose powerful APIs directly in HTML and JavaScript — geolocation for maps, drag-and-drop for interactive interfaces, and the File API for client-side file processing.

In this tutorial, you'll learn three built-in HTML APIs — Geolocation for getting user position, Drag and Drop for building interactive interfaces, and the File API for reading files in the browser without a server. These APIs let you build rich applications with zero external dependencies. By the end, you'll combine all three in a practical file upload dashboard.

Real-world use: Durga Antivirus Pro uses the File API to scan locally selected files for threats before upload. Doda Browser's download manager uses Drag and Drop for organizing downloads into folders.

flowchart LR
  A[HTML APIs] --> B[Geolocation API]
  A --> C[Drag and Drop API]
  A --> D[File API]
  B --> E[getCurrentPosition]
  B --> F[watchPosition]
  C --> G[dragstart / dragover / drop]
  C --> H[DataTransfer]
  D --> I[FileReader]
  D --> J[File / Blob]
  D --> K[FileList]

Geolocation API

The Geolocation API provides the user's latitude, longitude, altitude, and heading through the navigator.geolocation object.

// One-time position fetch
function getLocation() {
  if (!navigator.geolocation) {
    console.error('Geolocation is not supported');
    return;
  }

  navigator.geolocation.getCurrentPosition(
    (position) => {
      const { latitude, longitude, accuracy, altitude, heading, speed } = position.coords;
      console.log(`Latitude: ${latitude}`);
      console.log(`Longitude: ${longitude}`);
      console.log(`Accuracy: ${accuracy}m`);
      console.log(`Altitude: ${altitude}m`);
      console.log(`Heading: ${heading}deg`);
      console.log(`Speed: ${speed}m/s`);
    },
    (error) => {
      switch (error.code) {
        case error.PERMISSION_DENIED:
          console.error('User denied location request');
          break;
        case error.POSITION_UNAVAILABLE:
          console.error('Location unavailable');
          break;
        case error.TIMEOUT:
          console.error('Location request timed out');
          break;
      }
    },
    {
      enableHighAccuracy: true,
      timeout: 10000,
      maximumAge: 60000
    }
  );
}

getLocation();

Expected output:

Latitude: 40.7128
Longitude: -74.0060
Accuracy: 65m
Altitude: null
Heading: null
Speed: null

Watching Position Changes

For real-time tracking (navigation, fitness apps), use watchPosition.

const watchId = navigator.geolocation.watchPosition(
  (position) => {
    const { latitude, longitude, heading, speed } = position.coords;
    updateMapMarker(latitude, longitude);
    if (heading !== null && speed !== null) {
      console.log(`Moving ${heading}deg at ${speed}m/s`);
    }
  },
  (error) => console.error('Watch error:', error),
  { enableHighAccuracy: true, timeout: 5000 }
);

// Stop watching
function stopTracking() {
  navigator.geolocation.clearWatch(watchId);
  console.log('Location tracking stopped');
}

Drag and Drop API

The Drag and Drop API lets users drag elements between zones using dragstart, dragover, drop, and dragend events.

<div id="file-pool" class="drop-zone">
  <p>Drop files here</p>
</div>

<ul id="file-list">
  <li draggable="true" data-type="image">screenshot.png</li>
  <li draggable="true" data-type="document">report.pdf</li>
  <li draggable="true" data-type="image">photo.jpg</li>
  <li draggable="true" data-type="code">script.js</li>
</ul>

<div id="image-zone" class="drop-zone">Image Files</div>
<div id="doc-zone" class="drop-zone">Documents</div>
const draggables = document.querySelectorAll('[draggable="true"]');
const dropZones = document.querySelectorAll('.drop-zone');

// Drag source events
draggables.forEach(item => {
  item.addEventListener('dragstart', (e) => {
    e.dataTransfer.setData('text/plain', item.textContent);
    e.dataTransfer.setData('type', item.dataset.type);
    item.classList.add('dragging');
  });

  item.addEventListener('dragend', (e) => {
    item.classList.remove('dragging');
  });
});

// Drop target events
dropZones.forEach(zone => {
  zone.addEventListener('dragover', (e) => {
    e.preventDefault();
    zone.classList.add('drag-over');
  });

  zone.addEventListener('dragleave', () => {
    zone.classList.remove('drag-over');
  });

  zone.addEventListener('drop', (e) => {
    e.preventDefault();
    zone.classList.remove('drag-over');

    const type = e.dataTransfer.getData('type');
    const name = e.dataTransfer.getData('text/plain');

    if (zone.id === 'image-zone' && type === 'image') {
      zone.innerHTML += `<div>${name}</div>`;
    } else if (zone.id === 'doc-zone' && type === 'document') {
      zone.innerHTML += `<div>${name}</div>`;
    } else {
      alert(`Cannot drop ${name} here`);
    }
  });
});

Expected behavior: Dragging "screenshot.png" (type: image) over the Image zone highlights it. Dropping adds it to the zone. Dropping a document on the Image zone shows an alert.

File API

The File API lets web applications read files selected by the user or dropped onto the page.

<input type="file" id="file-input" multiple accept="image/*,.pdf,.txt">
<div id="file-output"></div>
const fileInput = document.getElementById('file-input');
const output = document.getElementById('file-output');

fileInput.addEventListener('change', (e) => {
  const files = e.target.files;
  output.innerHTML = '';

  for (const file of files) {
    const fileInfo = document.createElement('div');
    fileInfo.className = 'file-info';
    fileInfo.innerHTML = `
      <strong>${file.name}</strong><br>
      Size: ${(file.size / 1024).toFixed(1)}KB<br>
      Type: ${file.type || 'unknown'}<br>
      Last modified: ${new Date(file.lastModified).toLocaleDateString()}
    `;
    output.appendChild(fileInfo);
  }
});

Reading File Contents

Use FileReader to read text, data URLs, or ArrayBuffers.

function readFileAsText(file) {
  return new Promise((resolve, reject) => {
    const reader = new FileReader();
    reader.onload = () => resolve(reader.result);
    reader.onerror = () => reject(reader.error);
    reader.readAsText(file);
  });
}

function readFileAsDataURL(file) {
  return new Promise((resolve, reject) => {
    const reader = new FileReader();
    reader.onload = () => resolve(reader.result);
    reader.onerror = () => reject(reader.error);
    reader.readAsDataURL(file);
  });
}

async function processFile(file) {
  if (file.type.startsWith('image/')) {
    const dataUrl = await readFileAsDataURL(file);
    const img = document.createElement('img');
    img.src = dataUrl;
    img.style.maxWidth = '200px';
    document.body.appendChild(img);
  } else if (file.type === 'text/plain') {
    const text = await readFileAsText(file);
    const lines = text.split('\n');
    console.log(`File has ${lines.length} lines`);
    console.log('First 5 lines:', lines.slice(0, 5).join('\n'));
  }
}

fileInput.addEventListener('change', async (e) => {
  for (const file of e.target.files) {
    await processFile(file);
  }
});

Expected output for a text file:

File has 142 lines
First 5 lines: # Configuration file
# Doda Browser settings
homepage = "https://dodatech.com"
theme = "dark"
sidebar = true

File Drag-and-Drop Integration

Combine Drag and Drop with the File API for a complete drop-to-upload interface.

const dropZone = document.getElementById('file-pool');

dropZone.addEventListener('dragover', (e) => {
  e.preventDefault();
  dropZone.classList.add('active');
});

dropZone.addEventListener('dragleave', () => {
  dropZone.classList.remove('active');
});

dropZone.addEventListener('drop', async (e) => {
  e.preventDefault();
  dropZone.classList.remove('active');

  const files = e.dataTransfer.files;
  if (files.length === 0) return;

  const fileList = document.getElementById('file-list');
  fileList.innerHTML = '';

  for (const file of files) {
    const li = document.createElement('li');
    li.textContent = `${file.name} (${(file.size / 1024).toFixed(1)}KB)`;

    if (file.type.startsWith('image/')) {
      const dataUrl = await readFileAsDataURL(file);
      const img = document.createElement('img');
      img.src = dataUrl;
      img.style.width = '50px';
      img.style.height = '50px';
      img.style.objectFit = 'cover';
      li.prepend(img);
    }

    fileList.appendChild(li);
  }

  console.log(`Dropped ${files.length} file(s)`);
});

Expected behavior: Dragging a set of files from the desktop onto the drop zone displays thumbnail previews for images and file names with sizes for all files.

Threat Scanner Integration

Combine all three APIs for a practical security scanning tool.

class LocalFileScanner {
  constructor() {
    this.dropZone = document.getElementById('scan-zone');
    this.threatPatterns = [/\.exe$/i, /\.scr$/i, /\.vbs$/i];
    this.setupDrop();
    this.setupGeolocation();
  }

  setupDrop() {
    this.dropZone.addEventListener('dragover', (e) => e.preventDefault());
    this.dropZone.addEventListener('drop', async (e) => {
      e.preventDefault();
      const files = Array.from(e.dataTransfer.files);
      this.scanFiles(files);
    });
  }

  setupGeolocation() {
    navigator.geolocation.getCurrentPosition(
      (pos) => {
        this.location = {
          lat: pos.coords.latitude,
          lng: pos.coords.longitude
        };
        console.log('Scan location logged:', this.location);
      },
      () => { this.location = null; }
    );
  }

  async scanFiles(files) {
    const results = [];
    for (const file of files) {
      const text = await readFileAsText(file);
      const score = this.calculateRiskScore(file, text);
      results.push({ file, score });
    }
    this.displayResults(results);
  }

  calculateRiskScore(file, content) {
    let score = 0;
    if (this.threatPatterns.some(p => p.test(file.name))) score += 50;
    if (content.includes('eval(') || content.includes('exec(')) score += 30;
    if (content.includes('base64') && content.length > 10000) score += 20;
    return Math.min(score, 100);
  }

  displayResults(results) {
    results.forEach(r => {
      const severity = r.score > 50 ? 'High' : r.score > 20 ? 'Medium' : 'Low';
      console.log(`${r.file.name}: ${severity} risk (${r.score}/100)`);
    });
  }
}

const scanner = new LocalFileScanner();

Common Errors

  1. Geolocation only works on HTTPS — Modern browsers block geolocation on insecure origins. Use localhost for development or deploy to HTTPS.
  2. Missing e.preventDefault() in dragover — Without preventing the default, the browser refuses the drop. Always call e.preventDefault() in both dragover and drop handlers.
  3. FileReader not checking file.type — Users can select any file type regardless of the accept attribute. Always validate file.type before processing.
  4. Memory limits with large files — Reading multi-GB files into memory crashes the tab. For large files, use File.slice() to read in chunks or use the Streams API.
  5. Drag data not available in drop eventdataTransfer.getData() only works during drop, not in dragover. Access it only when the drop fires.
  6. Not handling permission denial for geolocation — Users can deny geolocation. Always handle the error callback and degrade gracefully, showing manual location input.

Practice Questions

How do you get the user's current location?

Call navigator.geolocation.getCurrentPosition(success, error, options). The success callback receives a GeolocationPosition object containing coords (latitude, longitude, accuracy, altitude, heading, speed).

What events are required for drag and drop?

At minimum: dragstart on the draggable element, dragover (with preventDefault()) on the drop target, and drop on the target to handle the dropped data. dragend and dragleave are optional for cleanup.

How do you read a file selected by the user?

Use the FileReader API with readAsText(), readAsDataURL(), or readAsArrayBuffer(). For modern code, use file.text(), file.arrayBuffer() or file.stream() which return promises. Always wrap in try/catch and check file.size for limits.

Can the File API access any file on the user's system?

No. The File API only reads files explicitly selected by the user via an <input type="file"> element or dropped onto a drop zone. It cannot access arbitrary files without user interaction.

How does geolocation accuracy work?

Accuracy depends on the device. GPS provides 5-50m accuracy outdoors. Wi-Fi positioning provides 20-200m. IP geolocation provides city-level accuracy (1-50km). Set enableHighAccuracy: true for GPS but expect longer timeouts

Challenge

Build a secure file upload dashboard that: uses Drag and Drop to accept files; reads the first 64KB of each file to detect magic bytes (file signatures); checks file type against an allow-list; shows a preview for images and a text snippet for documents; logs the upload location via geolocation; and reports file statistics (count, total size, types).

Real-World Task

Extend Durga Antivirus Pro's local file scanner. Users should be able to drag files onto the application's web dashboard, see file metadata (name, size, type, last modified), and trigger a local scan. Read the file content with FileReader, check for suspicious patterns (e.g., eval, base64 payloads, known malware signatures), and display a risk score per file. Log the scan location via geolocation for audit trails.


Previous: JavaScript Fundamentals | Next: Web Workers for File Processing | Related: File API Reference

Built by the developers of Doda Browser, DodaZIP, and Durga Antivirus Pro.

Built by the developers of DodaTech

Doda Browser, DodaZIP & Durga Antivirus Pro