# provider-fetch

Fetch data with HTML. Pair it with Quark to render the data. Zero app JS.


```html
<section>
  <provider-fetch api-url="/api/todos/1">
    <h4>Fetching todo...</h4>
    <span></span>
  </provider-fetch>
  <quark-sheet>
    provider-fetch[is-success] {
      $todo: prop("provision").body;
      h4 { content: "Todo ##{$todo.id}: #{$todo.title}"; }
      span { content: "Completed: #{$todo.completed}"; }
    }
  </quark-sheet>
</section>
```


## Features

- **Provides data** Use Quark to render that data
- **Auto-fetch** Fetches whenever `api-url` is set or changes
- **Re-fetch on demand** The `--fetch` command (`<button command="--fetch" commandfor="…">`) forces a re-fetch
- **Pausable** `is-paused` holds off auto-fetch without removing state
- **Highly configurable** Headers, method, `form-ref`,
  credentials, redirect, etc

## Installation


`@excom/provider-fetch` v0.1.5

```bash
pnpm add @excom/provider-fetch
```

```bash
npm install @excom/provider-fetch
```

```bash
yarn add @excom/provider-fetch
```

### Import

```ts
import "@excom/provider-fetch";
```



## Usage

```html
<provider-fetch api-url="/api/todos"></provider-fetch>
```

Hook the lifecycle state with CSS:

```css
provider-fetch[is-loading] { /* show loading spinner */ }
provider-fetch[is-error]::before { content: "An error occurred." }
```

`did-load` is set on the first success, kept through a refresh (where `is-loading` replaces `is-success`) and cleared on an error: gate content on `[did-load]` to keep it on screen during a refresh.

Or Quark:

```quark
provider-fetch[is-success] {
  $todo: prop("provision").body;
  span { content: $todo.title; }
}
```

### API Reference


#### Attributes

| Name | Surface | Type | Default | Values | Description | Inherited from |
| --- | --- | --- | --- | --- | --- | --- |
| `is-paused` | option | `boolean` |  |  | Pause auto-fetch. While set, `api-url` changes are ignored; the `--fetch` command still works. |  |
| `form-ref` | option | `string` |  | `<CSS Selector>` | CSS selector for a `<form>` to source the request from — its `action` (URL), `method`, `enctype` (Content-Type), and field values (as the JSON payload) all take priority over the matching attributes below. Omit to build the request entirely from attributes / custom `doFetch()` args. | `@excom/fetchable-element` |
| `has-body` | option | `boolean` |  |  | Force a request body even for methods that don't imply one (`GET` / `HEAD`). Already implied for `POST` / `PUT` / `PATCH`. | `@excom/fetchable-element` |
| `api-url` | option | `string` | `""` |  | Endpoint URL. When the request has no body, the JSON payload (from `form-ref` or custom `doFetch()` args) is merged in as query params instead. | `@excom/fetchable-element` |
| `api-method` | option | `string` | `"GET"` |  | HTTP method. Always uppercased before the request is sent. | `@excom/fetchable-element` |
| `header-accept` | option | `string` | `"application/json"` |  | `Accept` request header. | `@excom/fetchable-element` |
| `header-content-type` | option | `string` | `"application/json"` |  | `Content-Type` request header. Dropped entirely when the request has no body. | `@excom/fetchable-element` |
| `header-cache-control` | option | `string` |  |  | `Cache-Control` request header. Unset by default (browser default caching applies). | `@excom/fetchable-element` |
| `fetch-redirect` | option | `string` |  | `"follow"` \| `"error"` \| `"manual"` | `RequestInit.redirect` mode. Unset defers to the browser default (`follow`). | `@excom/fetchable-element` |
| `fetch-credentials` | option | `string` | `"include"` | `"omit"` \| `"same-origin"` \| `"include"` | `RequestInit.credentials` mode. | `@excom/fetchable-element` |
| `is-loading` | state | `boolean` |  |  | A request is currently in flight. | `@excom/fetchable-element` |
| `is-success` | state | `boolean` |  |  | The most recent request resolved successfully. Mutually exclusive with `is-loading` and `is-error`. | `@excom/fetchable-element` |
| `is-error` | state | `boolean` |  |  | The most recent request failed (status 400 or above, network error, or a thrown error other than `AbortError`). Fires with the `error` event. | `@excom/fetchable-element` |

#### Provision

| Name | Type | Description | Inherited from |
| --- | --- | --- | --- |
| `provision` | `FetchResponse` (`{ bodyUsed: boolean; headers: [string, string][]; ok: boolean; redirected: boolean; status: number; statusText: string; type: ResponseType; url: string; body: unknown; }`) | Response payload on success, or error payload on failure. Success shape: `{ status, statusText, ok, headers, url, redirected, bodyUsed, type, body }`. Failure shape is either that same response shape (server responded with an error status) or `{ message, stack }` (request never completed). Not reflected as an attribute. | `@excom/fetchable-element` |

#### Fires

| Name | Type | Description | Inherited from |
| --- | --- | --- | --- |
| `provider-fetch-submit` | `ProviderFetchSubmitEvent` (`CustomEvent & { type: "provider-fetch-submit"; detail: [url: string, requestInit: RequestInit]; bubbles: true; cancelable: true; composed: true }`) | Internal — dispatched whenever a fetch is about to run (auto-fetch or `--fetch`). Built by `getFetchArgs()`. Cancelable; default action calls `doFetch()`. |  |
| `provider-fetch-loading` | `FetchableLoadingEvent` (`CustomEvent & { type: "{tag}-loading"; detail: void; bubbles: true; cancelable: true; composed: true }`) | Dispatched immediately before the request is sent. | `@excom/fetchable-element` |
| `provider-fetch-success` | `FetchableSuccessEvent` (`CustomEvent & { type: "{tag}-success"; detail: { bodyUsed: boolean; headers: [string, string][]; ok: boolean; redirected: boolean; status: number; statusText: string; type: ResponseType; url: string; body: unknown; }; bubbles: true; cancelable: true; composed: true }`) | Dispatched when the request resolves successfully. `event.detail` is the parsed response (see `provision`). | `@excom/fetchable-element` |
| `provider-fetch-error` | `FetchableErrorEvent` (`CustomEvent & { type: "{tag}-error"; detail: { bodyUsed: boolean; headers: [string, string][]; ok: boolean; redirected: boolean; status: number; statusText: string; type: ResponseType; url: string; body: unknown; } \| { message: string; stack?: string }; bubbles: true; cancelable: true; composed: true }`) | Dispatched when the request fails — status 400 or above, network error, or a thrown error. `event.detail` is the error payload (see `provision`). Not dispatched for aborted requests. | `@excom/fetchable-element` |

#### Commands

| Command | Action |
| --- | --- |
| `--fetch` | Re-runs the request with the current attributes, even while `is-paused`. |

#### Default actions

| Event | Default behavior (unless preventDefault() is called) |
| --- | --- |
| `provider-fetch-submit` | Calls `doFetch([url, requestInit])` with the event's detail. |



### Examples

#### Comprehensive

This example shows loading state, error state, rendering, and refetching.


```html
<section>
  <provider-fetch id="demo-refetch-provider" api-url="/api/todos/1" class="tag-article grid">
    <ul></ul>
    <ul></ul>
    <template id="demo-refetch-item">
      <li class="tag-code"></li>
    </template>
  </provider-fetch>
  <button type="button" command="--fetch" commandfor="demo-refetch-provider">Refetch</button>
  <style>
    #demo-provider-fetch-refetch { max-width: none; }
    #demo-provider-fetch-refetch provider-fetch {
      &[is-loading] {
        opacity: 0.5;
        border: 1px dashed yellow;
      }
      &[is-success] { border: 1px solid green; }
      &[is-error] {
        border: 1px solid red;
        &::before { content: "An error occurred."; }
      }
      ul:first-of-type::before { content: "Todo data:"; }
      ul:last-of-type::before { content: "Response data:"; }
      li { display: block; }
    }
  </style>
  <quark-sheet>
    provider-fetch[is-success] {
      $res: prop("provision");
      li { content: "#{index}: #{item}"; }
      ul:first-of-type { content: iterate($res.body, "#demo-refetch-item"); }
      ul:last-of-type { content: iterate($res, "#demo-refetch-item"); }
    }
  </quark-sheet>
</section>
```

## Release notes

### 0.1.1 (2026-09-23)

- Ship only dist (and declared extras) in the npm tarball; drop build logs, tests and sources
