loading
Warning:
Chromium only, and it needs a service worker The API hangs off an active ServiceWorkerRegistration, so IsSupported is false until one is registered. In Chromium on Android the entries appear under Downloads → Articles for you; on desktop Chromium they are registered but there is no UI that lists them. Firefox and Safari do not implement it.
Note:
An entry is a claim, not a copy Indexing stores a title, a description, icons and a URL - nothing else. Cache the page first (see CacheStorage): an indexed URL that fails offline is worse than no entry, and Chromium removes entries whose cached response goes away.

Prerequisite: register the demo worker

ServiceWorker.Register / IsSupported

The same minimal /sw.js the rest of this category uses. Registering it is what makes registration.index exist.

@inject Bit.Butil.ServiceWorker serviceWorker
@inject Bit.Butil.ContentIndex contentIndex

<button @onclick="RegisterWorker">Register /sw.js</button>

@code {
    private async Task RegisterWorker()
    {
        await serviceWorker.Register("/sw.js");
        await serviceWorker.Ready();

        // registration.index only exists once there is an active registration to hang it off.
        var supported = await contentIndex.IsSupported();
    }
}
Live sample
support output
Results will appear here when you interact with the samples.

Register offline content

Add

The URL has to be inside the worker's scope, and Chromium requires at least one icon it can fetch. Adding the same id twice replaces the earlier entry rather than adding a second one. The button below caches the page first, so the entry is honest.

@inject Bit.Butil.ContentIndex contentIndex
@inject Bit.Butil.CacheStorage cacheStorage

@code {
    private async Task AddEntry()
    {
        // The entry is only honest if the URL really is available offline, so the page goes into the
        // cache the worker's fetch handler reads before it is advertised.
        await cacheStorage.Add("butil-content-index", "/articles/42");

        var added = await contentIndex.Add(new ContentIndexEntry
        {
            Id = "article-42",
            Title = "The article's title",
            Description = "One line about it, shown under the title.",
            Url = "/articles/42",
            Category = "article",
            Icons = [new ContentIndexIcon { Src = "/icon-512.png", Sizes = "512x512", Type = "image/png" }]
        });
    }
}
Live sample
add output
Results will appear here when you interact with the samples.

List and remove

GetAll / Delete

GetAll is the only honest answer to what is currently indexed: the browser removes entries on its own too - when the user deletes one from its UI, or when the cached response behind the URL goes away.

C#
ContentIndexEntry[] entries = await contentIndex.GetAll();
foreach (var entry in entries)
{
    // entry.Id, entry.Title, entry.Url, entry.Icons
}

await contentIndex.Delete("article-42");
Live sample
index output
Results will appear here when you interact with the samples.

API reference

Member
Signature
Description
IsSupported
ValueTask<bool> IsSupported()
True when the active service worker registration exposes index.
Add
ValueTask<bool> Add(ContentIndexEntry entry)
Registers one piece of offline-available content, replacing any entry with the same id.
Delete
ValueTask<bool> Delete(string id)
Removes an entry. Removing an id that is not there is not an error.
GetAll
ValueTask<ContentIndexEntry[]> GetAll()
Everything currently indexed for this service worker registration.
ContentIndexEntry
class ContentIndexEntry { string Id; string Title; string Description; string Url; string Category; ContentIndexIcon[] Icons; }
One indexed piece of content. Url must be inside the worker's scope.
ContentIndexIcon
class ContentIndexIcon { string Src; string Sizes; string Type; string Label; }
One icon for the browser's UI. Fetched while the entry is registered, so an unreachable one fails the Add.
An unhandled error has occurred. Reload 🗙