---
title: Svelte
description: The full Files API in the browser, idiomatic Svelte - useFiles returns the verbs plus Svelte stores for ambient state (read with $store), with useList / useFile / useSearch.
---

`files-sdk/svelte` brings the full Files API to the browser as idiomatic Svelte. `useFiles` returns one method per `Files` verb — `upload`, `download`, `url`, `list`, and the rest — plus ambient upload/error state as **Svelte stores** you read with the `$` prefix.

```svelte
<script lang="ts">
  import { useFiles } from "files-sdk/svelte";
  import { onDestroy } from "svelte";

  const files = useFiles({ endpoint: "/api/files" });
  const { isUploading, progress, error } = files;
  onDestroy(files.abort); // cancel any in-flight calls on unmount

  async function onUpload(event: Event) {
    const file = (event.currentTarget as HTMLInputElement).files?.[0];
    if (file) {
      await files.upload(file);
    }
  }
</script>

<input type="file" on:change={onUpload} />
{#if $isUploading}<progress value={$progress.fraction} />{/if}
{#if $error}<p>{$error.message}</p>{/if}
```

The binding ships **no Svelte runtime** — its stores are a tiny implementation of the store contract, so `$store` auto-subscription works exactly as with `writable`.

## The verbs

Every verb mirrors the SDK — `upload`, `download`, `head`, `exists`, `list`, `listAll`, `search`, `url`, `delete`, `copy`, `move`, `signedUploadUrl`, `capabilities` — including the bulk array forms. They are plain methods:

```ts lineNumbers
const { key } = await files.upload(file); // keyless → server mints the key
const stored = await files.download("report.pdf"); // → a lazy StoredFile
const link = await files.url("avatar.png"); // → string, for <img src>
await files.delete(["a.txt", "b.txt"]); // bulk → { deleted, errors? }
```

## Ambient state (stores)

```ts lineNumbers
files.isUploading; // Readable<boolean>      → $isUploading
files.progress; // Readable<{ loaded, total, fraction }>
files.uploads; // Readable<FileUploadState[]> — per-file live state
files.error; // Readable<FilesError | undefined> — last error from any verb
files.reset(); // clear ambient error + upload state (re-arms after abort)
files.abort(); // abort every in-flight call — wire to onDestroy
```

Svelte's lifecycle hooks need the compiler, so cancel in-flight work by calling `files.abort` from `onDestroy` — one line, as above.

## Reactive reads

The query stores load on creation and expose `data` / `error` / `isLoading` / `isFetching` stores plus `refetch()`. Svelte's reactivity lives at the component level, so re-run them from a `$:` block when a dependency changes:

```svelte
<script lang="ts">
  import { useList } from "files-sdk/svelte";

  let prefix = "docs/";
  const { data, isLoading, refetch } = useList({ prefix });

  $: prefix, refetch(); // re-run whenever `prefix` changes
</script>

{#if $isLoading}Loading…{:else}
  <ul>{#each $data?.items ?? [] as item}<li>{item.key}</li>{/each}</ul>
{/if}
```

`useFile(key)` (a `head()` for previews) and `useSearch(pattern, opts)` work the same way.

## Setting up the gateway

Point the binding at a mounted [gateway](/ui/server/gateway) — `createFilesRouter` on Next, Hono, Express, or any Web-`Request` runtime — and lock it down with [`authorize`](/ui/server/authorization).
