How to List Files in GeoLibre: 5 Approaches Explained with Source Code
GeoLibre supports five distinct file listing approaches—native Tauri dialogs, HTML file inputs, drag-and-drop, remote browse panels, and plugin-provided listings—all converging on a unified addLayer store mutation.
Every file import path in GeoLibre ultimately creates a GeoLibreLayer record in the central Zustand store (@geolibre/core). Whether you're building the desktop Tauri app or the web version, understanding these listing mechanisms helps you extend the platform with custom data sources.
Native File-System Dialogs (Tauri Desktop)
The Tauri open API provides native OS file pickers for the desktop build. This approach returns absolute file-system paths that feed directly into client-side loaders.
In apps/geolibre-desktop/src/hooks/useAddData.ts, the hook invokes the dialog and processes results:
export async function openFileDialog() {
const files = await window.__TAURI__.dialog.open({
multiple: true,
filters: [{ name: 'Geo files', extensions: ['geojson','shp','zip','kml'] }],
});
if (!files) return;
// `files` is an array of absolute paths
for (const path of files) {
await addGeoJsonLayerFromPath(path);
}
}
The paths are passed to DuckDB-WASM ST_Read, shpjs, or other loaders to produce GeoJSON. Layer IDs are generated via packages/map/src/vector-tile-layer-ids.ts.
HTML File Input (Web Build)
For browser environments, GeoLibre falls back to the standard <input type="file"> element. The FileList from this input is iterated and each File object is processed identically to the Tauri path branch.
In apps/geolibre-desktop/src/components/AddDataDialog.tsx:
<input
type="file"
multiple
accept=".geojson,.shp,.zip,.kml"
onChange={e => {
const list = e.target.files;
if (list) {
Array.from(list).forEach(file => addGeoJsonLayerFromFile(file));
}
}}
/>
The resulting GeoJSON is mapped to MapLibre sources through packages/map/src/style-mapper.ts.
Drag-and-Drop File Listing
Any UI surface accepting drops—primarily the map canvas—can list files via the DataTransfer API. The onDrop handler in apps/geolibre-desktop/src/components/MapCanvas.tsx extracts the FileList and forwards it to the shared import pipeline.
For ZIP shapefiles, packages/processing/src/wasm-convert.ts provides helper functions to unpack and convert before layer creation.
Remote Browse Panels
GeoLibre integrates with Source Cooperative, Hugging Face, and similar repositories through dedicated remote file panels. These components:
- Fetch JSON catalogs of remote datasets
- Build virtualized lists for performance
- Stream selected URLs through DuckDB-WASM (
ST_Readover HTTP)
Format support and size limits are defined in packages/plugins/src/plugins/remote-file-formats.ts:
// packages/plugins/src/plugins/remote-file-panels.tsx
{remoteCatalog.map(item => (
<button key={item.id} onClick={() => addRemoteLayer(item.url, item.name)}>
{item.name}
</button>
))}
Plugin-Provided File Listings
The plugin API exposes a registerFileLister hook in packages/plugins/src/plugins/plugin-api.ts. Plugins return arrays of file descriptors that the core UI consumes:
packages/plugins/src/plugins/plugin-api.ts— defines theregisterFileListerinterfaceapps/geolibre-desktop/src/hooks/usePlugins.ts— merges all registered listers into the Add Data dialog
This enables cloud storage browsers, database connectors, and other custom listing mechanisms without modifying core code.
The Unified Convergence Point
All five listing approaches mutate the same central store. The simplified addGeoJsonLayer function illustrates this pattern:
import { useStore } from '@geolibre/core';
export function addGeoJsonLayer(data: GeoJSON.GeoJSON, name: string) {
const id = generateLayerId();
useStore.getState().addLayer({
id,
name,
type: 'geojson',
source: { type: 'geojson', data },
// …additional UI metadata
});
}
After store insertion, @geolibre/map syncs layers to MapLibre for rendering.
Summary
- Tauri dialogs return absolute paths for desktop native file picking
- HTML file inputs handle browser-based selection via
FileReader - Drag-and-drop reuses the file input pipeline through
DataTransfer - Remote panels stream catalogs and URLs through DuckDB-WASM over HTTP
- Plugin listers extend the UI with custom file discovery mechanisms
All paths converge on @geolibre/core store mutations and MapLibre rendering.
Frequently Asked Questions
What file formats does GeoLibre support for listing?
GeoLibre supports GeoJSON, Shapefile (.shp and .zip), KML, and additional formats through DuckDB-WASM extensions. The supported list is defined in packages/plugins/src/plugins/remote-file-formats.ts for remote sources and in the Tauri dialog filters for local files.
How does GeoLibre handle large remote datasets?
Remote files are streamed through DuckDB-WASM using ST_Read over HTTP with configurable size limits. The virtualized list rendering in remote-file-panels.tsx ensures UI performance regardless of catalog size.
Can I add a custom file source like S3 or Google Drive?
Yes. Implement the registerFileLister hook from packages/plugins/src/plugins/plugin-api.ts to return file descriptors with URLs. The core UI will display your listings and route selections through the standard addRemoteLayer pipeline.
Where is the layer state managed in GeoLibre?
Layer state lives in the Zustand store at packages/core/src/store.ts. All file listing approaches—local, remote, or plugin—ultimately call useStore.getState().addLayer() to create GeoLibreLayer records that sync to MapLibre.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →