The kit page API
Every call a Site Kit's JavaScript can make: route, place, anchor, onResponse, store, settings, command, sidebar, toast, ui.upgrade and theme.
Inside a kit's features/*.js and lib/*.js, kit is a local variable (never on window). It has everything switchboard has (emit, run, on, vars; see Safari and Chrome) plus the calls below. Site Kits explains how they fit together.
kit.route(pattern, { mount, unmount }) #
Runs mount(ctx) while the address matches pattern and unmount(ctx) when it stops matching. pattern is a path: :name matches one segment (it appears in ctx.params), * matches anything including slashes, and a trailing slash doesn't matter. Query and hash are ignored.
Unmount runs before mount, newest first. Going from
/item/1to/item/2unmounts and mounts again.mountmay be async. If the route leaves while it runs, itsawaits reject with anAbortErrorthat is ignored.Errors in
mountare reported. Three in a row turn that feature file off.
ctx #
ctx.params | The :name parts of the address, frozen. |
ctx.url | The current address as a URL. |
ctx.route | The pattern this route was declared with. |
ctx.signal | An AbortSignal that aborts at unmount. Pass it as { signal } to addEventListener and to observers, and they go with the route. |
ctx.settings | The kit's settings when the route mounted, frozen. A change mounts the route again. |
await ctx.anchor(name) | The element for an anchor declared in kit.json. Waits up to 5 seconds, then throws AnchorMissing (reported, and counted in the kit's health). |
ctx.place(html, anchor, position?, options?) | Puts HTML next to an element and returns the first element placed. |
ctx.place #
position is before, after, prepend, append (the default) or replace. anchor is an element (from ctx.anchor) or the name of one you have already awaited. The HTML is drawn in a closed shadow root with the kit's components and tokens, so the site's CSS can't reach it and yours doesn't leak out. <script> is removed. data-switchboard-run, -emit and -bind attributes work.
| option | |
|---|---|
like | "sibling" copies height, radius, weight, colours and hover from the neighbour. A selector copies from that element. false uses the kit's base theme. Default: "sibling" when the anchor already holds an element of the same kind. |
isolate | false places the HTML in the page's own DOM, with no shadow root, so the site's CSS applies. Default true. |
Placed content fades in over 150 ms and collapses in 120 ms when removed, and does neither under reduced motion. In a flex or grid parent it takes the parent's gap and alignment.
kit.onResponse(pattern, fn, options?) #
Calls fn(body, { url, status, method, at }) for each fetch or XHR response whose address path matches pattern, before the page draws it. The page always gets the original response.
patternmust be listed inpermissions.responsesinkit.json, and the kit needsmainWorld: true(and Allow User Scripts in Chrome). Otherwise it throws "not in this kit's permissions".as:"json"(default; a body that isn't JSON is skipped) or"text".types:["fetch", "xhr"](default both) or one of them.Bodies over 2 MB are skipped. An error in
fnis reported and doesn't affect the page or other hooks. Returns a function that removes the hook.
kit.store #
Records the kit keeps in Switchboard, shared by every tab in every browser and by the kit's macros. A key is a string up to 200 characters, a value is JSON up to 1 MB, a collection holds up to 10,000 keys. Names beginning __ are the kit's own.
await kit.store.get(collection, key) // the value, or null
await kit.store.put(collection, key, value) // true; fails naming the limit
await kit.store.delete(collection, key) // true
await kit.store.query(collection, { prefix, limit }) // [{ key, value }] in key order
const stop = kit.store.watch(collection, (key, value) => {}) // value is null after a delete
Everything but watch returns a promise and rejects with the reason (for example "the value is over 1 MB"). Your own change may come back to your watch too: compare with what you hold before redrawing.
kit.settings #
kit.settings.get("compact") // the current value
kit.settings.all() // a copy of every value
const stop = kit.settings.on((settings, changed) => {}) // changed: names that differ
Values come from settings in kit.json, with the person's changes laid over the defaults. When one changes, on handlers run first and then every mounted route mounts again, so a route that reads ctx.settings in mount needs nothing else.
kit.command(name, fn, options?) #
Adds a command to the palette (⌥⌘K). options.keys gives it a shortcut, such as "⌥⌘L", while the kit is on the page; a shortcut without ⌘, ⌥ or ⌃ doesn't fire while the person is typing in a field. fn may return a promise; a rejection is reported. Returns a function that removes it. Register inside mount and remove with ctx.signal to make a command exist only on its route.
The kit's macros with Callable from pages are listed in the palette without any code.
kit.sidebar #
kit.sidebar.set(tree) // draw (or replace) the sidebar
kit.sidebar.update(id, { text: "…" }) // change one node's props
const stop = kit.sidebar.on(id, (e) => {}) // e: { type, value, … }
kit.sidebar.open() // show it (the side panel, or the drawer)
A tree is nodes with an id: stack (children, gap), text (text, style: title, body, caption, mono), image, button (title, role), field (label, kind: text, multiline, secure; placeholder, value), toggle (label, value), list (items, select), table (columns, rows), progress, divider and spacer. Events: a button gives { type: "click" }, a field { type: "input", value } once typing pauses (and { type: "submit", value } on Return in a single-line field), a toggle { type: "toggle", value }, a list or table { type: "select", value }.
A kit with settings gets a ⚙ at the top of its sidebar that opens the kit's settings in Switchboard.
kit.toast(text, options?) #
A short message in the kit's look. style: info (default), success, warning, error. seconds: default 3. action: { label, run } adds a button.
kit.ui.upgrade(root) #
Makes the sb-* elements under root real components. ctx.place does it for what it places; call this for DOM you build yourself. It keeps watching root for markup added later, and returns root.
kit.theme #
Read-only: { tokens, lines, source }. tokens are the --sb-* values now in force, lines are the contrast nudges made to them, and source is profile, sibling, sample or switchboard.
kit.html(name) #
The text of a file in html/: kit.html("badge.html"), for ctx.place.
kit.gm(ctx, info) #
For imported Tampermonkey and Violentmonkey scripts only; the importer writes the call, you will not need it in a kit you write. info is {script: {name, version, namespace, description?}, grants, resources, runAt}. It resolves to an object holding the GM_* functions (and an async GM.* object), once the page reaches runAt:
GM_addStyleadds a<style>and removes it when the route unmounts;GM_getValue,GM_setValue,GM_deleteValueandGM_listValueskeep their values in the kit's store collectiongm(read once up front, so they stay synchronous);GM_registerMenuCommandiskit.command;GM_notificationiskit.toast(onclickis ignored);GM_setClipboardwrites to the page's clipboard;GM_openInTabopens a new tab;GM_getResourceTextandGM_getResourceURLread the script's@resourcefiles;GM_infoandunsafeWindoware provided.GM_xmlhttpRequest,GM_download,GM_cookieand the other calls that need more power than a page script should have throw an error that says so.
kit.id and kit.version #
The kit's id and version from kit.json.
Modules #
require("name") returns the exports of lib/name.js; ./name, lib/name.js and name.js mean the same. A module runs once per page. A cycle gets what the module has exported so far.